【Python网络爬虫四】通过关键字爬取多张百度图片的图片

最近看了女神的新剧《逃避虽然可耻但有用》,同样男主也是一名程序员,所以很有共鸣

被大只萝莉萌的一脸一脸的,我们来爬一爬女神的皂片。

百度搜索结果:新恒结衣

本文主要分为4个部分:

  1.下载简单页面

  2.爬取多张图片

  3.页面解码

  4.爬取过程排错处理

1.下载简单页面

通过查看网页的html源码,分析得出,同一张图片共有4种链接:

{"thumbURL":"http://img5.imgtn.bdimg.com/it/u=2243348409,3607039200&fm=23&gp=0.jpg",
"middleURL":"http://img5.imgtn.bdimg.com/it/u=2243348409,3607039200&fm=21&gp=0.jpg",
"hoverURL":"http://img5.imgtn.bdimg.com/it/u=2243348409,3607039200&fm=23&gp=0.jpg",
"objURL":"http://attachments.gfan.com/attachments2/day_110111/1101112033d77a4a8eb2b00eb1.jpg"}

主要区别是分辨率不同,objURL是图片的源也是最清楚的一张。经测试,前三种都有反爬虫措施,用浏览器可以打开,但是刷新一次就403 Forbidden。用爬虫获取不到图片

第四种objURL是指图片的源网址,获取该网址会出现三种情况:

  1. 正常。继续下载
  2. 403 Forbidden。用continue跳过。
  3. 出现异常。用try except处理。
 1 #coding: utf-8
 2 import os
 3 import re
 4 import urllib
 5 import urllib2
 6
 7 def getHtml(url):
 8     page=urllib.urlopen(url)
 9     html=page.read()
10     return html
11
12 def getImg(html):
13     reg=r‘"objURL":"(.*?)"‘   #正则
14     # 括号表示分组,将括号的内容捕获到分组当中
15     #  这个括号也就可以匹配网页中图片的url了
16     imgre=re.compile(reg)
17     print imgre
18     imglist=re.findall(imgre,html)
19     l=len(imglist)
20     print l
21     return imglist
22
23 def downLoad(urls,path):
24     index = 1
25     for url in urls:
26         print("Downloading:", url)
27         try:
28             res = urllib2.Request(url)
29             if str(res.status_code)[0] == "4":
30                 print("未下载成功:", url)
31                 continue
32         except Exception as e:
33             print("未下载成功:", url)
34         filename = os.path.join(path, str(index) + ".jpg")
35         urllib.urlretrieve(url,filename)        #直接将远程数据下载到本地。
36         index += 1
37 html =getHtml("http://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=result&fr=&s"
38               "f=1&fmq=1484296421424_R&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&"
39               "word=新垣结衣&f=3&oq=xinyuanj&rsp=0")
40 Savepath="D:\TestDownload"
41 downLoad(getImg(html),Savepath)

其中urlretrieve方法
直接将远程数据下载到本地。

        urllib.urlretrieve(url[, filename[, reporthook[, data]]])
        参数说明:
        url:外部或者本地url
        filename:指定了保存到本地的路径(如果未指定该参数,urllib会生成一个临时文件来保存数据);
        reporthook:是一个回调函数,当连接上服务器、以及相应的数据块传输完毕的时候会触发该回调。我们可以利用这个回调函数来显示当前的下载进度。
        data:指post到服务器的数据。该方法返回一个包含两个元素的元组(filename, headers),filename表示保存到本地的路径,header表示服务器的响应头。

女神的照片就这么被爬下来了

2.爬取更多图片

等等,这个方法不过瘾呀,百度图片的页面是动态加载的,需要你往下滑才能继续加载后面的照片,我们这才完成了第一步,只爬到了30张图。

打开浏览器,按F12,切换到Network标签,然后将网页向下拉。这时浏览器地址栏的网址并没有改变,而网页中的图片却一张张增加,说明网页在后台与服务器交互数据。好的发现了就是这个家伙

XHR英文全名XmlHttpRequest,中文可以解释为可扩展超文本传输请求。Xml可扩展标记语言,Http超文本传输协议,Request请求。XMLHttpRequest对象可以在不向服务器提交整个页面的情况下,实现局部更新网页。当页面全部加载完毕后,客户端通过该对象向服务器请求数据,服务器端接受数据并处理后,向客户端反馈数据。

点开对比Request的URL,可以发现,基本上是一样的,除了末尾一点点。

只是pn的值不一样,测试发现,pn应该是表示当前请求的图片序号,rn表示更新显示图片的数量。

pn=90&rn=30&gsm=5a&1484307466221=
pn=120&rn=30&gsm=5a&1484307466223=
pn=150&rn=30&gsm=78&1484307469213=
pn=180&rn=30&gsm=78&1484307469214=
pn=210&rn=30&gsm=b4&1484307553244=

现在知道了,其实我们只要不断访问这个Request URL,改变他的pn值理论上就可以实现下载多张图片了。

1 def getMoreURL(word):
2     word = urllib.quote(word)
3     url = r"http://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&fp=result&queryWord={word}" 4           r"&cl=2&lm=-1&ie=utf-8&oe=utf-8&st=-1&ic=0&word={word}&face=0&istype=2nc=1&pn={pn}&rn=60"
5     urls = (url.format(word=word, pn=x) for x in itertools.count(start=0, step=30))
6     #itertools.count 0开始,步长30,迭代
7     return urls

其中,urllib.quote的作用是,对url就行处理。

按照标准, URL 只允许一部分 ASCII 字符(数字字母和部分符号),其他的字符(如汉字)是不符合 URL 标准的。
所以 URL 中使用其他字符就需要进行 URL 编码。

URL 中传参数的部分(query String),格式是:

name1=value1&name2=value2&name3=value3

假如你的 name 或者 value 值中有『&』或者『=』等符号,就当然会有问题。所以URL中的参数字符串也需要把『&=』等符号进行编码。

URL编码的方式是把需要编码的字符转化为 %xx 的形式。通常 URL 编码是基于 UTF-8 的(当然这和浏览器平台有关)。
例子:
比如『我』,unicode 为 0x6211, UTF-8 编码为 0xE6 0x88 0x91,URL 编码就是

%E6%88%91

itertools.count(start,step)的作用是一个迭代器,2个参数是开始和步长,这样就得到一个等差数列,这个数列填入url中,就得到了我们的urls。

试了下,转到解析得到的数据,objURL居然不是一个http的图片,查资料,显示下一步要做的就是解码

"objURL":"ippr_z2C$qAzdH3FAzdH3Fta_z&e3Bi1fsk_z&e3Bv54AzdH3FkufAzdH3Fw6vitejAzdH3F99lwbdublldlnvjaavmc8c01ba8a8m1mu0vjwama_z&e3B3r2"

3.页面解码

参考百度图片页面解码,发现其实就是一个table,key和value对应就可以解码了,简直就是明文密码0.0.。。。

所以在我们的程序里加个字典,多个解码的过程。

期间解码过程一度出错,经过仔细排查,是url.translate(char_table)出了问题,

str 的translate方法需要用单个字符的十进制unicode编码作为key 
value 中的数字会被当成十进制unicode编码转换成字符 
也可以直接用字符串作为value

所以需要加上一行

char_table = {ord(key): ord(value) for key, value in char_table.items()}

然而试了还是不行,提示translate方法有问题,去查了一下官方的文档

里面的例子是maketrans()方法一起用的,例子是替换元音字母

#!/usr/bin/python

from string import maketrans   # 引用 maketrans 函数。

intab = "aeiou"
outtab = "12345"
trantab = maketrans(intab, outtab)

str = "this is string example....wow!!!";
print str.translate(trantab);

输出结果:

1 th3s 3s str3ng 2x1mpl2....w4w!!!

所以对我们的chartable做处理,将key和value 通过maketrans关联:

    intab="wkv1ju2it3hs4g5rq6fp7eo8dn9cm0bla"
    outtab="abcdefghijklmnopqrstuvw1234567890"
    trantab = maketrans(intab, outtab)

到此为止,成功解析图片url。

4.爬取过程排错处理

真正在爬取的时候,会有一些错误,什么404,403啊,这样的话,程序就爬不到图片,这就比较尴尬了。

所以在下载的时候,需要做处理。

开始的时候,我用的是这种:

1 try:
2         res = requests.get(imgUrl, timeout=10)  #超时
3         if str(res.status_code)[0] == "4":
4             print(str(res.status_code), ":" , imgUrl)
5             return False
6     except Exception as e:
7         print("抛出异常:", imgUrl)
8         print(e)

但是爬着爬着发现,有的时候status_code不存在,又调试了一番,通过对比,发现404,403这种属于HTTPErro,但是request的时候,还可能产生URLError,如下图。

所以抛出异常的过程就需要进行分开处理了。

10060 因为目标主机主动拒绝,连接不能建立。这通常是因为试图连接到一个远程主机上不活动的服务,如没有服务器应用程序处于执行状态

 1 res = urllib2.Request(url)
 2         try:
 3             response = urllib2.urlopen(res ,data=None, timeout=5)  #超时处理
 4         except urllib2.URLError, e:
 5             if hasattr(e,‘code‘):
 6                 error_status = e.code
 7                 print(error_status, "未下载成功:", url)
 8                 continue
 9             elif hasattr(e,‘reason‘):
10                 print( "time out", url)
11                 continue

测试成功,可以通过自己设置下载图片数量,然后无线爬了,爬的速度差不多2分钟爬了300多张,这和图片的源和大小都有一定关系。

All Code:

  1 #coding: utf-8
  2 import os
  3 import re
  4 import urllib
  5 import urllib2
  6 import itertools  #迭代器
  7 from string import maketrans
  8
  9 str_table = {
 10     ‘_z2C$q‘: ‘:‘,
 11     ‘_z&e3B‘: ‘.‘,
 12     ‘AzdH3F‘: ‘/‘
 13 }
 14
 15 char_table = {
 16     ‘w‘: ‘a‘,
 17     ‘k‘: ‘b‘,
 18     ‘v‘: ‘c‘,
 19     ‘1‘: ‘d‘,
 20     ‘j‘: ‘e‘,
 21     ‘u‘: ‘f‘,
 22     ‘2‘: ‘g‘,
 23     ‘i‘: ‘h‘,
 24     ‘t‘: ‘i‘,
 25     ‘3‘: ‘j‘,
 26     ‘h‘: ‘k‘,
 27     ‘s‘: ‘l‘,
 28     ‘4‘: ‘m‘,
 29     ‘g‘: ‘n‘,
 30     ‘5‘: ‘o‘,
 31     ‘r‘: ‘p‘,
 32     ‘q‘: ‘q‘,
 33     ‘6‘: ‘r‘,
 34     ‘f‘: ‘s‘,
 35     ‘p‘: ‘t‘,
 36     ‘7‘: ‘u‘,
 37     ‘e‘: ‘v‘,
 38     ‘o‘: ‘w‘,
 39     ‘8‘: ‘1‘,
 40     ‘d‘: ‘2‘,
 41     ‘n‘: ‘3‘,
 42     ‘9‘: ‘4‘,
 43     ‘c‘: ‘5‘,
 44     ‘m‘: ‘6‘,
 45     ‘0‘: ‘7‘,
 46     ‘b‘: ‘8‘,
 47     ‘l‘: ‘9‘,
 48     ‘a‘: ‘0‘
 49 }
 50
 51 intab="wkv1ju2it3hs4g5rq6fp7eo8dn9cm0bla"
 52 outtab="abcdefghijklmnopqrstuvw1234567890"
 53 trantab = maketrans(intab, outtab)
 54
 55 char_table = {ord(key): ord(value) for key, value in char_table.items()}
 56 def deCode(url):
 57     # 先替换字符串
 58     for key, value in str_table.items():
 59         url = url.replace(key, value)
 60     # 再替换剩下的字符
 61     d=url.translate(trantab)
 62     return d
 63
 64 def getMoreURL(word):
 65     word = urllib.quote(word)
 66     url = r"http://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&fp=result&queryWord={word}"  67           r"&cl=2&lm=-1&ie=utf-8&oe=utf-8&st=-1&ic=0&word={word}&face=0&istype=2nc=1&pn={pn}&rn=30"
 68     urls = (url.format(word=word, pn=x) for x in itertools.count(start=0, step=30))
 69     #itertools.count 0开始,步长30,迭代
 70     return urls
 71
 72 def getHtml(url):
 73     page=urllib.urlopen(url)
 74     html=page.read()
 75     return html
 76
 77 #解析图片url解码
 78 def getImg(html):
 79     reg=r‘"objURL":"(.*?)"‘   #正则
 80     # 括号表示分组,将括号的内容捕获到分组当中
 81     #  这个括号也就可以匹配网页中图片的url了
 82     imgre=re.compile(reg)
 83     imageList=re.findall(imgre, html)
 84     imgUrls=[]
 85
 86     for image in imageList:
 87         imgUrls.append(deCode(image))
 88
 89     l=len(imgUrls)
 90     print l
 91     return imgUrls
 92
 93 def downLoad(urls,path):
 94     global index
 95     for url in urls:
 96         print("Downloading:", url)
 97         res = urllib2.Request(url)
 98         try:
 99             response = urllib2.urlopen(res ,data=None, timeout=5)  #超时处理
100         except urllib2.URLError, e:
101             if hasattr(e,‘code‘):
102                 error_status = e.code
103                 print(error_status, "未下载成功:", url)
104                 continue
105             elif hasattr(e,‘reason‘):
106                 print( "time out", url)
107                 continue
108
109             continue
110
111         filename = os.path.join(path, str(index) + ".jpg")
112         urllib.urlretrieve(url,filename)        #直接将远程数据下载到本地。
113         index += 1
114         # urllib.urlretrieve(url[, filename[, reporthook[, data]]])
115         # 参数说明:
116         # url:外部或者本地url
117         # filename:指定了保存到本地的路径(如果未指定该参数,urllib会生成一个临时文件来保存数据);
118         # reporthook:是一个回调函数,当连接上服务器、以及相应的数据块传输完毕的时候会触发该回调。我们可以利用这个回调函数来显示当前的下载进度。
119         # data:指post到服务器的数据。该方法返回一个包含两个元素的元组(filename, headers),filename表示保存到本地的路径,header表示服务器的响应头。
120         if index-1==1000:
121             break
122
123 if __name__ == ‘__main__‘:
124     keyWord="新垣结衣"
125     index = 1
126     Savepath = "D:\TestDownload"
127     urls=getMoreURL(keyWord)
128
129     for url in urls:
130         downLoad(getImg(getHtml(url)),Savepath)
131         if index-1==1000:
132             break

时间: 2024-08-24 12:11:05

【Python网络爬虫四】通过关键字爬取多张百度图片的图片的相关文章

【Python网络爬虫四】多线程爬取多张百度图片的图片

最近看了女神的新剧<逃避虽然可耻但有用> 被大只萝莉萌的一脸一脸的,我们来爬一爬女神的皂片. 百度搜索结果:新恒结衣 1.下载简单页面 通过查看网页的html源码,分析得出,同一张图片共有4种链接: {"thumbURL":"http://img5.imgtn.bdimg.com/it/u=2243348409,3607039200&fm=23&gp=0.jpg", "middleURL":"http://i

python网络爬虫第三弹(&lt;爬取get请求的页面数据&gt;)

一.urllib库 urllib是python自带的一个用于爬虫的库,其主要作用就是通过代码模拟浏览器发送请求,其常被用到的子模块在 python3中的为urllib.request 和 urllib.parse,在python2中的是 urllib 和 urllib2 二.由易到难首页面所有的数据值 1.爬取百度首页所有的数据值 import urllib.request import urllib.parse url = 'http://www.baidu.com' # 通过 URLopen

Python网络爬虫(6)--爬取淘宝模特图片

经过前面的一些基础学习,我们大致知道了如何爬取并解析一个网页中的信息,这里我们来做一个更有意思的事情,爬取MM图片并保存.网址为https://mm.taobao.com/json/request_top_list.htm.这个网址有很多页,通过在网址后添加?page=页码来进入指定的页. 为了爬取模特的图片,我们首先要找到各个模特自己的页面.通过查看网页源码,我们可以发现,模特各自的页面的特点如下: 我们可以通过查找class属性为lady-name的标签,然后取其href属性来获取各个模特各

python网络爬虫(7)爬取静态数据详解

目的 爬取http://seputu.com/数据并存储csv文件 导入库 lxml用于解析解析网页HTML等源码,提取数据.一些参考:https://www.cnblogs.com/zhangxinqi/p/9210211.html requests请求网页 chardet用于判断网页中的字符编码格式 csv用于存储文本使用. re用于正则表达式 from lxml import etree import requests import chardet import csv import re

什么是Python网络爬虫?带你爬向顶峰

首先我们来介绍一下什么是Python网络爬虫,先大概了解一下关于Python网络爬虫的相关知识点. Python作为一门入门简单,功能强大的,库类完善的语言,身受广大猿友们的喜欢.本身对Python也是非常有好感的,所以时不时的逛逛有关Python的网站啥的.通过在各大Python学习群和论坛的学习,我发现学习Python的人大部分都对网络爬虫很感兴趣.下面给各位介绍下Python的学习流程,并且会给出对应的学习教程. 第一步--学习Python 不管你有没有编程语言基础,也不管你其他语言是多厉

网络爬虫:使用多线程爬取网页链接

前言: 经过前面两篇文章,你想大家应该已经知道网络爬虫是怎么一回事了.这篇文章会在之前做过的事情上做一些改进,以及说明之前的做法的不足之处. 思路分析: 1.逻辑结构图 上图中展示的就是我们网络爬虫中的整个逻辑思路(调用Python解析URL,这里仅仅作了简略的展示). 2.思路说明: 首先.我们来把之前思路梳理一下.之前我们採用的两个队列Queue来保存已经訪问过和待訪问的链接列表,并採用广度优先搜索进行递归訪问这些待訪问的链接地址.并且这里使用的是单线程操作. 在对数据库的操作中.我们加入了

网络爬虫之动态内容爬取

根据联合国网站可访问性审计报告,73%的主流网站都在其重要功能中依赖JavaScript.和单页面应用的简单表单事件不通,使用JavaScript时,不再是加载后立即下载所有页面内容.这样会造成许多网页在浏览其中展示的内容不会出现在HTML源码中,针对于这种依赖于JavaScript的动态网站,我们需要采取相应方法,比如JavaScript逆向工程.渲染JavaScript等方法. 1. 动态网页示例 如上图,打开智联招聘主页,输入python,搜索会出现上面的页面,现在我们爬取上图红色标记出的

python网络爬虫之使用scrapy爬取图片

在前面的章节中都介绍了scrapy如何爬取网页数据,今天介绍下如何爬取图片. 下载图片需要用到ImagesPipeline这个类,首先介绍下工作流程: 1 首先需要在一个爬虫中,获取到图片的url并存储起来.也是就是我们项目中test_spider.py中testSpider类的功能 2 项目从爬虫返回,进入到项目通道也就是pipelines中 3 在通道中,在第一步中获取到的图片url将被scrapy的调度器和下载器安排下载. 4 下载完成后,将返回一组列表,包括下载路径,源抓取地址和图片的校

用Python多线程实现生产者消费者模式爬取斗图网的表情图片

什么是生产者消费者模式 某些模块负责生产数据,这些数据由其他模块来负责处理(此处的模块可能是:函数.线程.进程等).产生数据的模块称为生产者,而处理数据的模块称为消费者.在生产者与消费者之间的缓冲区称之为仓库.生产者负责往仓库运输商品,而消费者负责从仓库里取出商品,这就构成了生产者消费者模式. 生产者消费者模式的优点 解耦假设生产者和消费者分别是两个线程.如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合).如果未来消费者的代码发生变化,可能会影响到生产者的代码.