用python做点好玩的之爬虫
众所周知,python语言还有一个很强大的用途,就是用来做数据爬虫,之前自己做着玩,用分布式爬虫框架scrapy爬取了很多电影数据(为爱发电)。
直到我开始学习爬取某众点评,我才知道,什么是小巫见大巫。这里我们选择PC端爬取,因为h5爬取的话不稳定偶尔会跳重定向到下载app页面导致返回为空,app移动端的话我抓了个包后看了一下,不仅是静默登陆,而且所有包都加密了,直接放弃,所以我选择PC端爬取。
下面我们来详细看看。
简介页页数限制
1
首先我们访问一下某众dian评的简介页,第一页还能完美访问。
看起来也很正常,其实不然,如果你点击第二页,就会发现需要你登陆才可以访问。所以如果你想要爬更多的数据,需要登陆凭证才可以。
想必你会问,不能绕过登陆凭证带来的数据限制吗,很抱歉,这里我暂时没有更好的办法绕过它,只能通过一些办法,让一个登陆凭证可以慢点失效。
解析简介页
需要登陆的cookie
2
上面说了简介页需要登陆才能绕过限制,那么我们就登陆后看看吧。登陆后发现页面也只有50页,为了能爬到更多数据,这里我用的反反爬策略是:将分类调到比较细。
但是远远没有那么简单,打开开发者工具,然后选择查看一下评分,就发现事情没那么简单了(如下图)。这些评分的数字去哪儿了呢?
其实这些数字是SVG矢量图,SVG矢量图是基于可扩展标记语言,用于描述二维矢量图形的一种图形格式,通过使用不同的偏移量就能显示不同的字符,这样就能很巧妙地隐藏信息了,如果我们用xpath去解析网页得到的就是一个个""。这次爬虫的难点就在于如何得到这些评分的信息,既然我们能够知道它是怎么反爬的,那我们是不是就能想办法实现反反爬呢?先说下破解思路吧:首先要解析网页,找到这个网页使用的SVG矢量图,拿到这个矢量图后,如果我们能得到每个数字对应的偏移量,那就能将这些偏移量转化成图片中的数字了。所以这里我们得到我们面临的第一个问题:SVG矢量图如何解密(SVG的加密又叫图文混编)。
SVG加密的原理网上很多,篇幅有限,大家请自行百度。我总结了一下,就是利用CSS中的Class做了偏移量,所以在我们得到网页的源码之后,需要先把css文件的url提取出来(以下内容理解原理即可,代码最后会提供):
1. 提取css文件的url css_url = "http:" re.search('(//. svgtextcss. .css)', html).group()
然后将以"un"开头的class名称和对应的偏移量全部提取出来,以供后面使用:
css_res = requests.get(css_url)
2.这一步得到的列表内容为css中class的名字及其对应的偏移量 css_list =re.findall('(unw ){background:(. )px (. )px;', ' '.join(css_res.text.split('}')))
这里还要对得到的数据进行一下处理,因为y方向上的偏移量并不参与计算,最终得到的y_dict中的键是y方向上的偏移量,值是y方向上的偏移量对应的行数:
3. 过滤掉匹配错误的内容,并对y方向上的偏移量初步处理 css_list = [[i[0], i[1], abs(float(i[2]))] for i in css_list if len(i[0]) == 5]
4. y_list表示在y方向上的偏移量,完成排序和去重 y_list = [i[2] for i in css_list] y_list = sorted(list(set(y_list)))
5. 生成一个字典 y_dict = {y_list[i]: i for i in range(len(y_list))}
然后我们要提取以”un“开头的class所对应svg图片的url,并访问这个url,将图片中的数字都提取出来:
6. 提取svg图片的url svg_url="http:" re.findall('class^="un". (//. svgtextcss. .svg)', ' '.join(css_res.text.split('}')))[0] svg_res = requests.get(svg_url)
7. 得到svg图片中的所有数字 digits_list = re.findall('>(d )<', svg_res.text)
进行到这一步,我们就已经得到了所有以un开头的class对应的偏移量和所有的数字了,然后我们就可以利用前面的计算方法将这些偏移量转变成对应的数字了。
解析详情页
依然需要登陆的cookie
3
在很多情况下,我们不仅需要简介,也需要店铺的详情,比如营业时间以及具体的地点等等信息,那么这些信息如何获取呢,首先我们随便点开一个店铺详情,打开开发者工具,你会发现,这里也用到了字体加密。
详情页连店铺的名字都加密了。
这里剧透一下,当你解密完页面后,手机号最后两位也是被米掉的。所以这里还有一个问题,获取不到完整手机号的问题。我这里采用api获取,最后的代码里会有。
请输入验证码
4
这里也是最难的一点,就是某众点评的反爬策略十分的严格。不仅会根据ip限制频率,还会对用户做访问次数的限制。第一次超过这个限制会输入验证码,第二次就直接无法访问直接403了。
首先我们先来看看输入验证码的问题,我也尝试了使用自动化测试框架selenium去模拟人为操作,但是大众点评可以识别出selenium框架,直接就进入到了验证中心,输入验证码后仍然会报服务拒绝。就果断弃之(貌似有阉割版的浏览器驱动,可以跳过大众点评的验证)。大家可以踊跃尝试,我这里因为成本问题,没有尝试。而是注册了多个账号,然后用到了cookie池。
ip频率限制
5
这也是最常见的反爬策略之一,就是对访问ip做了限制。这个解决起来很简单就不用记小本本了,就是用ip代理池,每次请求就换一个ip,很多地方都有免费代理可以用,如果是自己爬着玩,学习为主呢,有一个本地代理服务的开源项目可以分享给大家。链接:
https://github.com/jhao104/proxy_pool.git
原理很简单,就是获取市面上的免费的代理做成代理池。在本地直接运行就可以了,具体文档里都有介绍。
但是如果你是想更稳定,我建议还是买匿名代理,毕竟免费的ip不是被封了就是连接不上,请求多了会发生不稳定的现象,我用的是在快代理买的隧道代理,就是每请求一次,就换一次ip。
开始运行后
6
反反爬并不能从根本解决问题,因为策略是服务器端提供的,我们只是通过一些手段让代码更流畅,爬取的数据量更多,可能服务器端策略变化了,你就也要调整相关代码。
总结一下我们用到的反反爬策略。首先图文混编加密,我们需要找到class对应的偏移量的映射字典,然后解密。针对于ip的频率限制,选择使用代理池。针对于对于用户的访问频次的限制,选择注册多个账号然后使用cookie池。
我的代码是在下面的开源框架修改而来的,比如针对于cookie和css做了缓存化。大家直接阅读源码即可,需要一定的阅读门槛。
源码地址:https://github.com/Sniper970119/dianping_spider
思考
爬虫虽好,也不要瞎用哦。特意查了下关于爬虫的一些法律知识,其实在我国,爬取有些信息商用是犯法的。
之前有个朋友觉得好玩爬警察局官网的信息,直接被请去"喝茶"了。所以大家在学习技能之外也要了解一下关于网络安全的高压线,维护网络安全需要大家共同努力。