前言
这是学习Python爬虫以来,我的第二个爬虫项目了。经过这次爬虫项目练习,让我了解到了很多爬虫需要注意的东西。也再一次证明了,我在上一次的爬虫实在是入门级别,因此这次学习过程颇为曲折,遇到了许多坑坑洼洼,实在扎心,因此我将会把整个学习探索的过程写在下面…
言归正传,本次爬取的目标网站是百度图片,为了帮助一位研究生学姐的忙下载10000张火灾烟雾照片,作为CNN卷积神经网络的训练集样本使用。
1 . 网页真实HTML代码问题
一开始的时候,我的想法便是直接利用浏览器的直接查看每个元素,然后分析其中的树状结构
F12查看img元素
使用BeautifulSoup解析出一个个地址,然后Downloader一个个图片地址
然而现实很快就啪啪啪打脸我…
BeautifulSoup无法解析
输出了,说明根本就没有解析指定的HTML的Tag!
当时,我年轻的以为是我自己的BeautifulSoup解析大法没有用好,于是钻入研究该网页的BeautifulSoup解析中,将BeautifulSoup解析大法又重学了个遍,然而还是无法解析…
于是我开始怀疑,这个网页无法用BeautSoup解析出来,毕竟人家是Baidu嘛,于是我开始使用牛逼的正则表达式解析,于是再一次年轻无知地掉入正则表达式解析的坑中,然而…
正则表达式无法解析
正则解析直接给我返回了一个空列表,说明根本就没解析到这玩意,但是不该呀,我正则解析了整个html文本,怎么会出现没有匹配项的问题???也就是此时,我终于开始警觉起来,是不是这网页不是我想象中的那样所见即所得的简单?
于是,我直接使用最繁琐的方法,用我的肉眼查看源代码,结果,震惊了!!!根本就找不到在中看到的树状结构的HTML代码,倒是一大堆JavaScript代码,而且极其混乱,感受下这个画风…
瀑布流源码
后来,百度才发现,瀑布流布局是使动态加载的,需要解析每次服务器返回的数据才能在,在此处就是动态加载新的图片,当时觉得难,遂放弃,动态解析的不会抓取,我就走常规方法呗,于是切换到传统分页模式查看元素
传统翻页式F12查看元素
果然吼!对比之前瀑布流页面的F12查看元素都不同啦,看起来,似乎是找到诀窍了哦!
然而,现实再一次打脸,无论使用BeautifulSoup或是正则表达式解析,都无法获取正确结果。于是,有了上一次的经验,自然而言会想到所谓的中看到的HTML代码,也许不是那么直接明显的,于是Google Chrome快捷键,事实的结果更是令人震惊!!!
传统翻页式源码
根据布局推测出该有的图片的位置处,却一张图片url都没有!!!
于是,我知道了,这个网页绝不是那种简单地布局加载,遂求助于伟大Bing,发现了原因,原来所有图片都是JavaScript解析出来的,也就是说根本没有把图片放在一个个HTML Tag中!!!所以说,想通过XML节点解析的方法获取图片URL根本行不通!!!因为图片的真实URL在此处
隐藏在JavaScript中的真实URL
分析发现,一共有三个URL,分别是thumbURL、middleURL、objURL,笔者尝试过都能打开,只不过图片质量最佳的是objURL,其他两个应该是缩略图。
我后来的代码爬取发现2个问题
采用objURL作为目标解析时,很快会被反爬虫,程序报错
objURL报错
使用thumbURL、middleURL大规模爬取是没有问题,但是,很多图片下载下来根本无法打开,也就是说图片的URL打开没有一张图片,更别提保存下来作为一个Image文件了,所以不能使用这两个中的URL
图片下载有问题
图片无法打开
打印输出某一个保存失败的图片url,发现打开竟然是,所以在下载时要跳过这些不正常的URL。
好了,至此,终于发现了怎么找到真实网页中的真实图片地址啦,愉快地解析是没有问题。(但愉快的下载会遇到反爬虫的问题,下面会讲到)
结果喜人呐!!!
图片地址
2 . 传统翻页式网站的下载问题
经过前面一番折腾,终于被我找到了图片的真实URL,当时就觉得可以通过老套路
先解析爬取每个分页的图片,然后再解析出nextPage的URL作为参数传入,然后接着爬取新的一页的所有图片…
看似没毛病,然而现实又再一次地啪啪啪打脸我…
翻页式爬取objURL被反爬虫
返回的结果是,看来翻页式浏览下载图片会被反爬虫,这就很尴尬了,不过想想也是毕竟人家也是BAT大厂啊,怎可能那么容易爬取。
于是我想啊,既然高清原图(objURL)无法爬取,那我就退而求其次,爬取thumbURL或middleURL吧,于是便修改imgURL的正则表达式。运行发现,诶!果然没有被反爬虫哦,正当我得意之时,打开我得图片文件夹,却发现…
非objURL图片很多存在无效
这就又回到了我前面分析网页源码遇到的那个问题,非objURL图片很多是打不开的,或者根本不存在,所以才会在此处没有反爬虫机制,所以任你下载多少多快,人家百度根本就不care你。
唉,看样子,以传翻页式连续爬取图片的想法注定是要凉凉,想起了那句话:你大爷还是你大爷,即使人家已经BAT掉队了…
目前为止,我们发现,如果采用传统翻页式爬取网页的话,会出现两个矛盾的问题
要么可以爬取高清原图,但是objURL很快就会被反爬虫
要么避开反爬虫机制,但是大量图片就根本下载不下来
我想到的解决方案有两个
针对objURL,采用反爬虫机制,使用代理或者浏览器模拟爬取
分析瀑布流布局的源码,因为它的数据是可以解析的(后面会说到)
我当然可以直接去针对objURL使用一个反爬虫机制躲避它,但是,我考虑到,现今越来越多的网站采用瀑布流布局动态加载内容,为了将来更好地爬取其他网站信息,我觉得应该去研究动态加载的Ajax技术。
于是便踏上了Ajax的征途…
3 . Ajax与JSON解析
在网上看了几篇大神的博客,慢慢地了解了一点Ajax动态加载的原理。至于啥是Ajax,此处不再赘言,上面有个蓝色粗体字外部链接点击可以查看。下面简单讲讲在百度图片动态加载中,Ajax是如何起作用的吧。
首先,当我们以瀑布流的布局打开某个图片搜索结果时,是不能一次性看到所有图片的,通常只会看到若干张图片(是网站而定,百度图片是每次加载30张)。
然后,随着用户的下拉刷新动作(电脑上就是鼠标向下滚动,手机上是触摸向下滚动),浏览器会监听到这一用户动作,当滚动条快要达到底部时,浏览器向服务器请求一个JSON数据,然后将返回的JSON数据通过浏览器解析出来。
最后,浏览器解析出数据之后,便开始动态加载局部这个页面,也就是说之前加载出来的图片不会消失,新的图片会添加到该网页尾部。一个显而易见的效果便是,电脑Chrome浏览器的右侧边滚动栏中的滚动条会越来越短,表示网页中加载的图片越来越多了。
基本原理搞懂后,让我们实际操作,看下效果吧!
首先,打开以瀑布流布局的方式打开网页,F12键进入Network界面查看XHR(英文全名XmlHttpRequest)查看,刚开始打开是,是没有显示请求JSON数据的Request URL的,就像下面这样
未刷新时的XHR
接着,我们向下刷新一下页面,很快就会发现有刷新时请求的Request URL了
请求4次RequestURL
刷新了4次,便会出现4个Request URL,分别是
用这个网站字符串比较工具,显示只有这几个参数不同,其他一样
URL比较
再分析4个URL
4个URL的不同之处
分析得出下面这几个参数的意义
pn: 起始加载位置数目
rn: 每次加载总数
gsm: 十六进制形式的当前加载起始位置
word: UTF-8编码的关键词参数
然后在浏览器打开任意一个URL,尝试删除或修改参数后的作用,得出了规律,构造出精简版的Request URL,只需要保留pn、rn、word便可以实现请求新的数据
理论上我们便可以开始构造很多Request URL了
构造RequestURL
经测试,构造出来的URL都是可以打开的,而且数据符合规律!
接着,当我打开一个Request URL,发现是这样的凌乱的画风
JSON数据
不过好在,thumbURL、middleURL、objURL还是可以看见的,但是!仔细一看,发现最关键的objURL这个URL似乎长得不怎么像一个正常的URL
放到浏览器中一探究竟,果然打不开!直觉告诉我,可能跟加密有关系,遂去百度该问题。感谢这篇博客,提供了百度图片URL解码方法(虽然不是很懂为什么是那个秘钥映射关系)
下面给出来Python版本的解码代码
尝试了一下,decode结果为
完美打开!
4 . 关键代码
为了达到,通过输入关键字来索引的效果,需要将键盘上输入的文字转换为UTF-8编码的文字添加到URL中
生成大量网址的无限迭代器的使用
5 . 尾声
理论上来说,经过以上分析以及关键代码,就已经可以开始愉快地爬取大量照片了,事实也的确如此!
虽然没有用到反爬虫技术,但是目的已经到达了就行了,正所谓软件开发要跟着需求走,而不是看程序员代码有多NB,需求目标达到了就行了。其他的就是后续技术完善的过程了,这也符合提前优化是万恶之源的基本原则。
代码有点长,所以直接放张运行结果的截图吧
11,086张照片
这次学习过程中遇到了诸多问题,但是在搜索引擎的帮助下,解决了很多问题,不禁感叹还是人民群众的智慧强大呀!所以说,学编程最好的方法不是天天抱着本书看,而是多动手多利用搜索引擎!
最后,感谢这几位大佬(xiligey、岁月如歌、Jimmy、xiaoshe)的博客的帮助!
OneMoreThing…
分享一首好歌
分享一本最近在看的好书,吴军老师的《大学之路》
纽曼大行之道
吴军老师的书每次看都让我收获颇丰,字里行间严谨地表达写作能力是我学习的榜样,以后有机会写一篇读后感吧。
领取专属 10元无门槛券
私享最新 技术干货