上次写的教程让女票高兴了很久,但她高兴的原因恐怕并不是学会了爬虫,这点我还是非常清醒的。这篇教程的续集我很早就想好,但碍于实在没有时间将它写出来,终于咖啡馆的网络不好用,又没带书,只好耐着性子写完它,算给自己为了爬虫痴迷那几天一个交代。我还是尽量写的通俗,以求能让更多的人看懂,比如我可爱的女票。
重要的前提,我假定你们已经看过第一篇爬虫教程,并且已经实操了,那么我们跳过环境设置,直入主题。最近开了博客(www.readlist.cn),我将教程放在那里,欢迎大家有空去看看,涨个人气。
我们的目的是爬取网页中的图片,可能你已经发现了,我们只能下载网页中的20张图片。实际上,我们用浏览器浏览该网页时,页面中的照片不止20张,随着滚动条的滚动,好像网页在不断的加载新的照片,可不可以贪心的把所有的照片下载下来呢?当然可以!
还用用chorme打开我们爬虫的目标网页,页面上右击选择显示网页源代码,我们在新打开的标签页看到了该网页的源代码。
显示源代码有了前面的基础,我们可以轻松的找到我们需要的图片地址,<img class="pic" src="
后面跟着的就是我们需要的图片地址。按command+F
搜索这串代码,发现chrome在该源代码中找到20个对象,这与我们第一篇教程得到的结果是相符的。接下来,你可以试试,无论你怎么滚动滚动条,源代码不变,也就是源代码只有前20张照片的地址,那么后面的图片地址在哪里?
异步加载
其实,这个网页用到了一种常见的网页加载技术——异步加载。试想一下,该网页可能有成千上万的照片,如果当浏览器访问时,全部显示显然要花很长时间才能全部加载,浪费时间浪费带宽,解决这一不合理状况的就是异步加载技术。你浏览该网页时,浏览器只会加载前20张照片,当你滚动条滑动最下面时,浏览器认为你还需要阅读更多的内容,就会向服务器提出申请说,“这个用户想看更多的,再来些“,服务器会再发20张图片的内容给浏览器,以此类推。
上述过程,你可以通过在网页空白处右键点击检查
,下面的chrome工具栏中的Network
标签会告诉你浏览器是怎么实现我们上面所述的异步加载。滚动滚动条至最下面,你会发现工具栏中出现了21个对象,其中20个为图片,就是页面新加载的20张图片,剩下1个是json文件。继续滚动,这里会再增加21个,以此类推,有没有很有意思。
我们可以将json理解为一个包裹,这个包裹里放着的就是20张图片的地址,我们每滚动到页尾,就会向服务器申请一个包裹,然后浏览器拆开包裹,将里面的内容显示在网页上。可是,服务器里存放了无数个包裹,它怎么知道我们需要哪个包裹,有过网购经验的MM肯定可以想到,每个包裹都有一个唯一的身份证,我们称之为“快递单号”。这样,一切就可以解释,浏览器将我们需要的包裹号发送给服务器,服务器然后如实将该包裹发送回来。我们可以仔细看下json,选中json文件,在右侧的工具栏中选择Preview标签,里面的html中放着的是有新增加图片地址的源代码,last_key是下一段代码的包裹号,所以不难推测,源代码中有一个last_key指向本包裹。
JsonPreview我们重新捋一下思路,首先爬取源代码中的图片,然后向服务器发送包裹号,获取包裹,解析其中的内容,然后再发送包裹号,再解析包裹中的内容,以此类推。接下来,终于可以上代码了。
#-*-coding:utf8-*-
import re
import requests
import json
url = 'http://www.qdaily.com/categories/17'
url_more = 'http://www.qdaily.com/categories/categorymore/17/'
html = requests.get(url).text
last_key = re.search('lastKey="(.*?)"',html,re.S).group(1)
for i in range(3):
pic_url = re.findall('"pic" src="(.*?)"',html,re.S)
j = 0
for each in pic_url:
url = 'http://www.qdaily.com' + each
print('now downloading:' + url)
pic = requests.get(url)
fp = open('pic//' + str(i) +str(j) + '.jpg','wb')
fp.write(pic.content)
fp.close()
j += 1
url = url_more + last_key + 'json'
data = requests.get(url)
html = json.loads(data.text)[u'data'][u'html']
last_key = str(json.loads(data.text)[u'data'][u'last_key'])
代码解析
#-*-coding:utf8-*-
的意思上字符编码是utf-8
。
import re
import requests
import json
的意思上导入re
、requests
和json
库,告诉电脑,我们下面要用这三个库中的程序了。
前面我们分析得到下一个包裹的包裹号,但是到底怎么获取它呢?可以在检查工具栏中,点击Headers
,查看到json的地址。
接下来定义两个变量(就是存储容器)存放两个地址,我们接下来需要用到这两个地址。
url = 'http://www.qdaily.com/categories/17'
url_more = 'http://www.qdaily.com/categories/categorymore/17/'
然后获取url中地址的源代码,并且在源代码中查找last_key
。
html = requests.get(url).text
last_key = re.search('lastKey="(.*?)"',html,re.S).group(1)
下面的代码是我们这篇教程的核心,用循环来不断向获取新的包裹,拆开它,通过里面的图片地址下载图片,我们这里只循环3次,下载60张图片,当然你想循环多少次就改一下数字即可,相信你可以办到。for i in range(3):
就是循环语句,表示接下来的语句要执行三次。
逻辑是非常清楚的:
- 从源代码中获取图片地址
pic_url = re.findall('"pic" src="(.*?)"',html,re.S)
- 将图片下载到指定文件夹
j = 0
for each in pic_url:
url = 'http://www.qdaily.com' + each
print('now downloading:' + url)
pic = requests.get(url)
fp = open('pic//' + str(i) +str(j) + '.jpg','wb')
fp.write(pic.content)
fp.close()
j += 1
- 获取下一批图片的源代码
url = url_more + last_key + 'json'
data = requests.get(url)
html = json.loads(data.text)[u'data'][u'html']
- 获取下一批图片源代码中包含的last_key
last_key = str(json.loads(data.text)[u'data'][u'last_key'])
我没有详细解释代码的具体含义,因为接下来我要去逛书店,没有耐心了。如果你有疑问,欢迎到我的博客留言提问,有问必答。
执行程序
将上面到代码保存为picdownloader2.py
,置于根目录下,并且新建文件夹pic。打开终端
,写下如下代码,回车即可
python picdownloader2.py
终于完成了“教女朋友爬虫”的续集,关于爬虫的教程先告一段落。上次的教程让女票(领导)甚是开心,顺便提出了新要求,要我继续写教程,因为她还要学很多,学markdown,学印象笔记,学Hexo博客。。。再一次硬广,欢迎关注我的博客,微博。
今天是女票麻麻的生日,未来丈母娘生日快乐。
欢迎关注公众号“百杏果阁”
网友评论