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 相关文章推荐
Java Web开发过程中登陆模块的验证码的实现方式总结
May 25 Python
Python3实现抓取javascript动态生成的html网页功能示例
Aug 22 Python
轻量级的Web框架Flask 中模块化应用的实现
Sep 11 Python
Python 批量合并多个txt文件的实例讲解
May 08 Python
详解Python 正则表达式模块
Nov 05 Python
python实现自动解数独小程序
Jan 21 Python
python实现图片中文字分割效果
Jul 22 Python
python gdal安装与简单使用
Aug 01 Python
python从zip中删除指定后缀文件(推荐)
Dec 05 Python
Python内置数据类型list各方法的性能测试过程解析
Jan 07 Python
Python @property原理解析和用法实例
Feb 11 Python
Django+Django-Celery+Celery的整合实战
Jan 20 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分页示例分享
2014/04/30 PHP
PHP中Socket连接及读写数据超时问题分析
2016/07/19 PHP
PHP符合PSR编程规范的实例分享
2016/12/21 PHP
Nigma vs Alliance BO5 第五场2.14
2021/03/10 DOTA
不间断滚动JS打包类,基本可以实现所有的滚动效果,太强了
2007/12/08 Javascript
js跨域问题之跨域iframe自适应大小实现代码
2010/07/17 Javascript
JS加jquery简单实现标签元素的显示或隐藏
2013/09/23 Javascript
浅析JavaScript中的typeof运算符
2013/11/30 Javascript
js+html5实现canvas绘制圆形图案的方法
2015/06/05 Javascript
js实现的Easy Tabs选项卡用法实例
2015/09/06 Javascript
基于javascript代码实现通过点击图片显示原图片
2015/11/29 Javascript
js事件冒泡、事件捕获和阻止默认事件详解
2016/08/04 Javascript
AngularJS实现select的ng-options功能示例
2017/07/12 Javascript
基于 Bootstrap Datetimepicker 联动
2017/08/03 Javascript
React-router v4 路由配置方法小结
2017/08/08 Javascript
微信小程使用swiper组件实现图片轮播切换显示功能【附源码下载】
2017/12/12 Javascript
Vue 使用 Mint UI 实现左滑删除效果CellSwipe
2018/04/27 Javascript
解决vue项目中页面调用数据 在数据加载完毕之前出现undefined问题
2019/11/14 Javascript
JS实现时间校验的代码
2020/05/25 Javascript
Vue项目中使用mock.js的完整步骤
2021/01/12 Vue.js
[19:15]DK战队纪录片
2014/09/02 DOTA
Django+uni-app实现数据通信中的请求跨域的示例代码
2019/10/12 Python
python sklearn常用分类算法模型的调用
2019/10/16 Python
python爬虫库scrapy简单使用实例详解
2020/02/10 Python
如何在django中实现分页功能
2020/04/22 Python
html5 div布局与table布局详解
2016/11/16 HTML / CSS
德国在线订购鲜花:Fleurop
2018/08/25 全球购物
写给女朋友的检讨书
2014/01/28 职场文书
选秀节目策划方案
2014/06/06 职场文书
升职感谢信
2015/01/22 职场文书
道歉信范文
2015/05/12 职场文书
黑白记忆观后感
2015/06/18 职场文书
幼儿园春季开学通知
2015/07/16 职场文书
pytorch中的numel函数用法说明
2021/05/13 Python
Python+Tkinter打造签名设计工具
2022/04/01 Python
ubuntu开机后ROS程序自启动问题
2022/12/24 Servers