@IT·互联网

花瓣一日游

2019-02-02  本文已影响8人  慕长风啊

朋友工作上有需求,要在花瓣上采集1w+的图片,于是我就帮忙写了个爬虫。


初拿到账号,登上去看了眼网站布局。是这个样子:

花瓣用户主页

布局简洁明了,爬取思路也很清晰:

先拿到一个board(画板)链接

board

进入一个board后拿到所有pin(图片)的链接就ok了

pins

按照以前写爬虫的套路,抓包,分析网络请求,模拟网络请求,数据提取等一套操作下来,这种小爬虫,十来分钟,保准交差!

然而...flag立得有些早了(/捂脸)

刚开始提取数据的时候就遇到了点小阻碍

F12下看到的页面中想提取的数据长这个样子:

html

但是响应的数据包里的数据格式却是这个样子:

response

看来页面是经过JavaScript动态渲染过了,这下惯用的bs4库是派不上用场了。
看到网上有人用Selenium库来模拟浏览器操作,我觉得没有必要,太影响性能了。

不如首先确定下要爬取的board链接在响应数据中的位置吧,Ctrl+F在页面源代码里搜一下。
有点小坑,直接搜索“/boards/45651489/”还搜不到,还得截取board_id才能搜到:

board_link

不过既然在源码里找到了要爬取的数据就好说了,直接上正则提取吧:

r = requests.get("http://login.meiwu.co/{}/".format(USER_NAME),
                 cookies=self.cookies, headers=self.headers)
result = re.search(
    r'app.page\[\"user\"\] = (.*?)};', r.text).group(1) + "}"
boards = json.loads(result)['boards']
for board in boards:
    self.boards.put((board['board_id'], board['title'])) # 用队列存储board_id和board_title

本以为数据提取这部分就算大功告成了,后面就可以松一口气了,没想到...

loading

花瓣还用上了Ajax异步加载...

简单科普一下,有时候我们用requests库模拟请求的时候,返回数据和浏览器中看到的不一样,一种情况就是上面那样经过JS渲染了,还有一种情况是返回的数据好像不完整,比如这里页面下拉能看到更多的board,但是我们一次request是看不到后来的这些数据的,这种数据加载是一种异步加载方式,原始页面不包含后续的数据,当你下拉的时候,页面会向后台请求某个接口获取数据,然后才会被处理呈现到浏览器上,这其实就是发送了一个Ajax请求。

幸好不是第一次遇到了,以前爬小密圈的时候还觉得蛮棘手,现在也算有些经验了,就是又要费把子力气。

先打开F12,筛选XHR类型的请求,然后加载下一页board,提取XHR请求的特征

XHR

分析后发现,主要参数为max,其他几个参数可以不用管
其值是上一页中最后一个board_id
类比我之前爬过的小密圈,其中一个关键值是上一页最后一条帖子的发言时间
找到这个规律后,接下来的工作就容易很多了:
提取每一页board的最后一个board_id,然后构造下一页的request

r = requests.get("http://login.meiwu.co/{}/?jrkb9krs&limit=10&wfl=1&max={}".format(
    USER_NAME, board['board_id']), cookies=self.cookies, headers=self.headers)

经过以上的工作,用户页面的所有画板链接就都提取到手了,接着就是对board页面里的所有图片进行链接提取了,套路和上面是一模一样的,这里就不赘述了。

总的说来,如果有前端基础,再加上些Python功底,写爬虫是件很easy的事情。
我自己其实不懂前端,全凭着些Python编程的经验,所以上面写的可能有些错漏之处,有大牛看到的话还望多指点。

最后补充两点

  1. 数据存储和查重
    为了方便后面对图片进行多线程断点下载,保存数据的时候需要注意下,其实每个pin(图片)都有个key,这个key可以定位到图片的下载地址,同样也可以用于图片查重操作。
    这里我将代码分成了两部分去写:
    第一部分遍历每个board,并获取其中每张图片的key, raw_text(图片描述)和对应的board_title(用于图片分类),然后将所有图片信息保存成json文件。
    第二部分就是读取json文件,获取每张图片的下载链接,完成一个简单的多线程图片下载任务就行了,单张图片下载前会借助os模块读取文件目录,依据key或者图片名判断图片是否已经存在。

  2. 反反爬虫
    其实最令我头疼的是这个问题,写代码前的准备工程中我就发现,花瓣的访问很不稳定,尤其用爬虫模拟访问时,经常出现连接错误,而且摸不清规律。
    为此代码中对大部分request都用上了while语句加上随机数休眠,由于不清楚其反爬虫机制,暂时只是加上了headers和休眠措施,目前测试情况来看已经满足需求了,后面有空尝试搭建代理池再试试效果。

附完整代码:
https://github.com/Moofeng/Spider/tree/master/huaban

上一篇下一篇

猜你喜欢

热点阅读