Python之多线程爬虫抓取网页图片的示例代码


Posted in Python onJanuary 10, 2018

目标

嗯,我们知道搜索或浏览网站时会有很多精美、漂亮的图片。

我们下载的时候,得鼠标一个个下载,而且还翻页。

那么,有没有一种方法,可以使用非人工方式自动识别并下载图片。美美哒。

那么请使用python语言,构建一个抓取和下载网页图片的爬虫。

当然为了提高效率,我们同时采用多线程并行方式。

思路分析

Python有很多的第三方库,可以帮助我们实现各种各样的功能。问题在于,我们弄清楚我们需要什么:

1)http请求库,根据网站地址可以获取网页源代码。甚至可以下载图片写入磁盘。

2)解析网页源代码,识别图片连接地址。比如正则表达式,或者简易的第三方库。

3)支持构建多线程或线程池。

4)如果可能,需要伪造成浏览器,或绕过网站校验。(嗯,网站有可能会防着爬虫 ;-))

5)如果可能,也需要自动创建目录,随机数、日期时间等相关内容。

如此,我们开始搞事情。O(∩_∩)O~

环境配置

操作系统:windows 或 linux 皆可

Python版本:Python3.6 ( not Python 2.x 哦)

第三方库

urllib.request

threading 或者 concurrent.futures 多线程或线程池(python3.2+)

re 正则表达式内置模块

os 操作系统内置模块

编码过程

我们分解一下过程。完整源代码在博文最终提供。

伪装为浏览器

import urllib.request

# ------ 伪装为浏览器 ---
def makeOpener(head={
  'Connection': 'Keep-Alive',
  'Accept': 'text/html, application/xhtml+xml, */*',
  'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
  'Connection': 'keep-alive',
  'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0'
  }):
  cj = http.cookiejar.CookieJar()
  opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cj))
  header = []
  for key, value in head.items():
    elem = (key, value)
    header.append(elem)
  opener.addheaders = header
  return opener

获取网页源代码

# ------ 获取网页源代码 ---
# url 网页链接地址
def getHtml(url):
  print('url='+url)
  oper = makeOpener()
  if oper is not None:
    page = oper.open(url)
    #print ('-----oper----')
  else:
    req=urllib.request.Request(url)
    # 爬虫伪装浏览器
    req.add_header('User-Agent','Mozilla/5.0 (Windows NT 6.1; WOW64; rv:57.0) Gecko/20100101 Firefox/57.0')
    page = urllib.request.urlopen(req)
  html = page.read()
  if collectHtmlEnabled: #是否采集html
    with open('html.txt', 'wb') as f:
      f.write(html) # 采集到本地文件,来分析
  # ------ 修改html对象内的字符编码为UTF-8 ------
  if chardetSupport:
    cdt = chardet.detect(html)
    charset = cdt['encoding'] #用chardet进行内容分析
  else:
    charset = 'utf8'
  try:
    result = html.decode(charset)
  except:
    result = html.decode('gbk')
  return result

下载单个图片

# ------ 根据图片url下载图片 ------
# folderPath 定义图片存放的目录 imgUrl 一个图片的链接地址 index 索引,表示第几个图片
def downloadImg(folderPath, imgUrl, index):
  # ------ 异常处理 ------
  try:
    imgContent = (urllib.request.urlopen(imgUrl)).read()
  except urllib.error.URLError as e:
    if printLogEnabled : print ('【错误】当前图片无法下载')
    return False
  except urllib.error.HTTPError as e:
    if printLogEnabled : print ('【错误】当前图片下载异常')
    return False
  else:
    imgeNameFromUrl = os.path.basename(imgUrl)
    if printLogEnabled : print ('正在下载第'+str(index+1)+'张图片,图片地址:'+str(imgUrl))
    # ------ IO处理 ------
    isExists=os.path.exists(folderPath)
    if not isExists: # 目录不存在,则创建
       os.makedirs( folderPath )
       #print ('创建目录')
    # 图片名命名规则,随机字符串
    imgName = imgeNameFromUrl
    if len(imgeNameFromUrl) < 8:
      imgName = random_str(4) + random_str(1,'123456789') + random_str(2,'0123456789')+"_" + imgeNameFromUrl
    filename= folderPath + "\\"+str(imgName)+".jpg"
    try:
       with open(filename, 'wb') as f:
         f.write(imgContent) # 写入本地磁盘
       # if printLogEnabled : print ('下载完成第'+str(index+1)+'张图片')
    except :
      return False
    return True

下载一批图片(多线程/线程池模式皆支持)

# ------ 批量下载图片 ------
# folderPath 定义图片存放的目录 imgList 多个图片的链接地址
def downloadImgList(folderPath, imgList):
  index = 0
  # print ('poolSupport='+str(poolSupport))
  if not poolSupport:
   #print ('多线程模式')
   # ------ 多线程编程 ------
   threads = []
   for imgUrl in imgList:
     # if printLogEnabled : print ('准备下载第'+str(index+1)+'张图片')
     threads.append(threading.Thread(target=downloadImg,args=(folderPath,imgUrl,index,)))
     index += 1
   for t in threads:
     t.setDaemon(True)
     t.start()
   t.join() #父线程,等待所有线程结束
   if len(imgList) >0 : print ('下载结束,存放图片目录:' + str(folderPath))
  else:
   #print ('线程池模式')
    # ------ 线程池编程 ------
   futures = []
   # 创建一个最大可容纳N个task的线程池 thePoolSize 为 全局变量
   with concurrent.futures.ThreadPoolExecutor(max_workers=thePoolSize) as pool: 
    for imgUrl in imgList:
     # if printLogEnabled : print ('准备下载第'+str(index+1)+'张图片')
     futures.append(pool.submit(downloadImg, folderPath, imgUrl, index))
     index += 1
    result = concurrent.futures.wait(futures, timeout=None, return_when='ALL_COMPLETED')
    suc = 0
    for f in result.done:
      if f.result(): suc +=1
    print('下载结束,总数:'+str(len(imgList))+',成功数:'+str(suc)+',存放图片目录:' + str(folderPath))

调用例子

如百度贴吧为例

# ------ 下载百度帖子内所有图片 ------
# folderPath 定义图片存放的目录 url 百度贴吧链接
def downloadImgFromBaidutieba(folderPath='tieba', url='https://tieba.baidu.com/p/5256331871'):
  html = getHtml(url)
  # ------ 利用正则表达式匹配网页内容找到图片地址 ------
  #reg = r'src="(.*?\.jpg)"'
  reg = r'src="(.*?/sign=.*?\.jpg)"'
  imgre = re.compile(reg);
  imgList = re.findall(imgre, html)
  print ('找到图片个数:' + str(len(imgList)))
  # 下载图片
  if len(imgList) >0 : downloadImgList(folderPath, imgList) 

# 程序入口
if __name__ == '__main__':
  now = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S')
  # 下载百度帖子内所有图片
  downloadImgFromBaidutieba('tieba\\'+now, 'https://tieba.baidu.com/p/5256331871')

效果

Python之多线程爬虫抓取网页图片的示例代码

Python之多线程爬虫抓取网页图片的示例代码

Python之多线程爬虫抓取网页图片的示例代码

完整源码请见

我的github:https://github.com/SvenAugustus/PicDownloader-example

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
用Python的Tornado框架结合memcached页面改善博客性能
Apr 24 Python
python统计日志ip访问数的方法
Jul 06 Python
Python设计实现的计算器功能完整实例
Aug 18 Python
Python 结巴分词实现关键词抽取分析
Oct 21 Python
PyQt5+requests实现车票查询工具
Jan 21 Python
Python地图绘制实操详解
Mar 04 Python
Python实现直播推流效果
Nov 26 Python
Python综合应用名片管理系统案例详解
Jan 03 Python
Python如何将字符串转换为日期
Jul 31 Python
Python 忽略文件名编码的方法
Aug 01 Python
Django实现简单的分页功能
Feb 22 Python
Python中re模块的元字符使用小结
Apr 07 Python
Python设计模式之观察者模式简单示例
Jan 10 #Python
Python爬虫实例_城市公交网络站点数据的爬取方法
Jan 10 #Python
Python爬虫_城市公交、地铁站点和线路数据采集实例
Jan 10 #Python
Python tornado队列示例-一个并发web爬虫代码分享
Jan 09 #Python
Python中join函数简单代码示例
Jan 09 #Python
Python中顺序表的实现简单代码分享
Jan 09 #Python
python中set()函数简介及实例解析
Jan 09 #Python
You might like
发布一个用PHP fsockopen写的HTTP下载的类
2007/02/22 PHP
实现PHP多线程异步请求的3种方法
2014/01/17 PHP
CI框架集成Smarty的方法分析
2016/05/17 PHP
利用PHP实现开心消消乐的算法示例
2017/10/12 PHP
PHP使用mongoclient简单操作mongodb数据库示例
2019/02/08 PHP
用于table内容排序
2006/07/21 Javascript
JavaScript是否可实现多线程  深入理解JavaScript定时机制
2009/12/22 Javascript
jQuery 在光标定位的地方插入文字的插件
2012/05/10 Javascript
JavaScript 更严格的相等 [译]
2012/09/20 Javascript
如何创建一个JavaScript弹出DIV窗口层的效果
2013/09/25 Javascript
javascript使用定时函数实现跳转到某个页面
2013/12/25 Javascript
在JS中如何调用JSP中的变量
2014/01/22 Javascript
jQuery操作select下拉框的text值和value值的方法
2014/05/31 Javascript
Google官方支持的NodeJS访问API,提供后台登录授权
2014/07/29 NodeJs
jQuery实现网页顶部固定导航效果代码
2015/12/24 Javascript
实例代码详解javascript实现窗口抖动及qq窗口抖动
2016/01/04 Javascript
在ASP.NET MVC项目中使用RequireJS库的用法示例
2016/02/15 Javascript
JavaScript实现创建自定义对象的常用方式总结
2018/07/09 Javascript
如何在vue里面优雅的解决跨域(路由冲突问题)
2019/01/20 Javascript
中高级前端必须了解的JS中的内存管理(推荐)
2019/07/04 Javascript
浅谈JavaScript中的“!!”作用
2020/08/03 Javascript
简单介绍Python中的readline()方法的使用
2015/05/24 Python
Python使用爬虫猜密码
2016/02/19 Python
Python SVM(支持向量机)实现方法完整示例
2018/06/19 Python
Python中的字符串切片(截取字符串)的详解
2019/05/15 Python
pyinstaller参数介绍以及总结详解
2019/07/12 Python
windows下Pycharm安装opencv的多种方法
2020/03/05 Python
python开根号实例讲解
2020/08/30 Python
Data URI scheme详解和使用实例及图片base64编码实现方法
2014/05/08 HTML / CSS
html5使用canvas画空心圆与实心圆
2014/12/15 HTML / CSS
Mio Skincare中文官网:肌肤和身体护理
2016/10/26 全球购物
Book Depository美国:全球领先的专业网上书店之一
2019/08/14 全球购物
代码中finally中的代码会不会执行
2012/02/06 面试题
生产主管岗位职责
2013/11/10 职场文书
铁路个人事迹材料
2014/01/30 职场文书
基本公共卫生服务健康教育工作方案
2014/05/22 职场文书