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 Web框架Flask中使用新浪SAE云存储实例
Feb 08 Python
Python的自动化部署模块Fabric的安装及使用指南
Jan 19 Python
Python入门_浅谈数据结构的4种基本类型
May 16 Python
python打包压缩、读取指定目录下的指定类型文件
Apr 12 Python
python 将md5转为16字节的方法
May 29 Python
Python实现基于PIL和tesseract的验证码识别功能示例
Jul 11 Python
python分割一个文本为多个文本的方法
Jul 22 Python
Python迷宫生成和迷宫破解算法实例
Dec 24 Python
pytorch中的卷积和池化计算方式详解
Jan 03 Python
容易被忽略的Python内置类型
Sep 03 Python
python 实现网易邮箱邮件阅读和删除的辅助小脚本
Mar 01 Python
基于Python绘制子图及子图刻度的变换等的问题
May 23 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 array_flip() 删除数组重复元素
2009/01/14 PHP
不要轻信 PHP_SELF的安全问题
2009/09/05 PHP
php从完整文件路径中分离文件目录和文件名的方法
2015/03/13 PHP
用jQuery简化JavaScript开发分析
2009/02/19 Javascript
jquery 可排列的表实现代码
2009/11/13 Javascript
jquery对dom的操作常用方法整理
2013/06/25 Javascript
js左右弹性滚动对联广告代码分享
2014/02/19 Javascript
字段太多jquey快速清空表单内容方法
2014/08/21 Javascript
JavaScript使用slice函数获取数组部分元素的方法
2015/04/06 Javascript
js 判断所选时间(或者当前时间)是否在某一时间段的实现代码
2015/09/05 Javascript
JavaScript表单验证实例之验证表单项是否为空
2016/01/10 Javascript
javascript正则表达式之分组概念与用法实例
2016/06/16 Javascript
红黑树的插入详解及Javascript实现方法示例
2018/03/26 Javascript
Linux Centos7.2下安装nodejs&amp;npm配置全局路径的教程
2018/05/15 NodeJs
vue 实现axios拦截、页面跳转和token 验证
2018/07/17 Javascript
仿ElementUI实现一个Form表单的实现代码
2019/04/23 Javascript
浅谈vue 组件中的setInterval方法和window的不同
2020/07/30 Javascript
Python判断值是否在list或set中的性能对比分析
2016/04/16 Python
python实现二分查找算法
2017/09/21 Python
python 拼接文件路径的方法
2018/10/23 Python
Python实现Mysql数据统计及numpy统计函数
2019/07/15 Python
Python split() 函数拆分字符串将字符串转化为列的方法
2019/07/16 Python
python实现统计代码行数的小工具
2019/09/19 Python
python实现小世界网络生成
2019/11/21 Python
Python获取、格式化当前时间日期的方法
2020/02/10 Python
django 将自带的数据库sqlite3改成mysql实例
2020/07/09 Python
html5的自定义data-*属性与jquery的data()方法的使用
2014/07/02 HTML / CSS
悦木之源美国官网:Origins美国
2016/08/01 全球购物
印尼最大的婴儿用品购物网站:Orami
2017/09/28 全球购物
斯福泰克软件测试面试题
2015/02/16 面试题
php优化查询foreach代码实例讲解
2021/03/24 PHP
小学生开学第一课活动方案
2014/03/27 职场文书
《登鹳雀楼》教学反思
2014/04/09 职场文书
公司合并协议书范本
2014/09/30 职场文书
2015新年寄语大全
2014/12/08 职场文书
解决Jenkins集成SonarQube遇到的报错问题
2021/07/15 Java/Android