【Python3爬虫】大众点评爬虫(破解CSS反爬)

本次爬虫的爬取目标是大众点评上的一些店铺的店铺名称、推荐菜和评分信息。css

 

1、页面分析

进入大众点评,而后选择美食(http://www.dianping.com/wuhan/ch10),能够看到一页有15家店铺,而除了店铺的名称,还能看到店铺的地址、推荐菜、评分等信息,看起来都没什么问题。html

打开开发者工具,而后选择查看一下评分,就发现事情没那么简单了(以下图)。这些评分的数字去哪儿了呢?git

其实这些数字是SVG矢量图,SVG矢量图是基于可扩展标记语言,用于描述二维矢量图形的一种图形格式,经过使用不一样的偏移量就能显示不一样的字符,这样就能很巧妙地隐藏信息了,若是咱们用xpath去解析网页获得的就是一个个""。此次爬虫的难点就在于如何获得这些评分的信息,既然咱们可以知道它是怎么反爬的,那咱们是否是就能想办法实现反反爬呢?先说下破解思路吧:首先要解析网页,找到这个网页使用的SVG矢量图,拿到这个矢量图后,若是咱们能获得每一个数字对应的偏移量,那就能将这些偏移量转化成图片中的数字了。github

 

 2、破解步骤

首先查看网页源码,既然使用的是SVG矢量图,那咱们搜索一下svg会不会有惊喜呢?果真有惊喜:dom

把这个连接复制一下,而后打开这个连接,会看到有不少的class名称和background,这么多的数据,怎么知道有没有咱们想要的东西呢?这时候搜索一下unbq2:ide

能够看到unbq2这个class对应的background为(-199.0px,-109.0px),可是咱们仍是没有办法获得具体的数字啊,怎么办呢?svg

咱们再搜索一下svg会有什么结果呢?这一步会获得几个以.svg结尾的连接,将这些连接提取出来:工具

span[class^="ma"]{background-image: url(//s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/9e045e6574fb7ae10b5aae4ae4a0c444.svg);
span[class^="yj"]{background-image: url(//s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/39510b070120e6a5b7c8754ab729ee2e.svg);
span[class^="dz"]{background-image: url(//s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/8eecf780b3c9ecefd5ad508502dd80a5.svg);
span[class^="un"]{background-image: url(//s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/39ecd4a57969825db02c38a01f4f34c6.svg);

能够看到以"un"开头的class使用的背景图片的连接就是//s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/39ecd4a57969825db02c38a01f4f34c6.svgurl

这就是咱们要找的SVG矢量图了,如今的问题就在于如何将偏移量转化成对应的数字呢?首先把这些数字提取出来:spa

99851465728255648017534661485297040380627087820023

03763928255311814779807306445209731282368541175419

06266544999197136339

而后打开开发者工具,能够发现每一个数字都有对应着一组x和y的值:

 

在前面的分析中咱们知道数字6对应的偏移量是(-199.0px,-109.0px),而后咱们也能够分析一下别的数字对应的偏移量,而后经过这些分析能够知道y方向上的偏移量只是为了肯定这个class对应的数字在哪一行,而x方向的偏移量须要进行一下处理,具体方法为:

(x方向上的偏移量+7)/(-12)

 好比(-199+7)/(-12)=16,这个16就表示对应的数字索引为16(第一个数字索引为0),而后y方向的偏移量对应的行数为3,最后从上面的数字中寻找第3行第17个数字--正好为6,也就是说unbq2这个class对应的数字就是6,这样咱们就已经成功实现了反反爬。

 

3、爬取步骤

因为大众点评会对咱们的UserAgent和Cookie进行检查,因此在爬取的时候要带上Cookie,并且若是一直用一个UserAgent也会被识别出来,因此得采用不一样的UserAgent。这里我要分析一个第三方模块:fake_useragent,没有安装这个模块的可使用pip命令进行安装。咱们经过使用这个模块就能获得随机的UserAgent了,使用方法以下:

1 from fake_useragent import UserAgent 2 
3 ua = UserAgent() 4 for i in range(3): 5     print(ua.random)

运行结果以下:

店铺名称和推荐菜的爬取相对简单,这里就不赘述了,主要说一下如何爬取店铺的评分信息。

在咱们获得网页的源码以后,须要先把css文件的url提取出来:

# 提取css文件的url
css_url = "http:" + re.search('(//.+svgtextcss.+\.css)', html).group()

而后将以"un"开头的class名称和对应的偏移量所有提取出来,以供后面使用:

css_res = requests.get(css_url)
# 这一步获得的列表内容为css中class的名字及其对应的偏移量
css_list = re.findall('(un\w+){background:(.+)px (.+)px;', '\n'.join(css_res.text.split('}')))

这里还要对获得的数据进行一下处理,由于y方向上的偏移量并不参与计算,最终获得的y_dict中的键是y方向上的偏移量,值是y方向上的偏移量对应的行数:

# 过滤掉匹配错误的内容,并对y方向上的偏移量初步处理
css_list = [[i[0], i[1], abs(float(i[2]))] for i in css_list if len(i[0]) == 5]
# y_list表示在y方向上的偏移量,完成排序和去重
y_list = [i[2] for i in css_list]
y_list = sorted(list(set(y_list)))
# 生成一个字典
y_dict = {y_list[i]: i for i in range(len(y_list))}

而后咱们要提取以”un“开头的class所对应svg图片的url,并访问这个url,将图片中的数字都提取出来:

# 提取svg图片的url
svg_url = "http:" + re.findall('class\^="un".+(//.+svgtextcss.+\.svg)', '\n'.join(css_res.text.split('}')))[0]
svg_res = requests.get(svg_url)
# 获得svg图片中的全部数字
digits_list = re.findall('>(\d+)<', svg_res.text)

进行到这一步,咱们就已经获得了全部以un开头的class对应的偏移量和全部的数字了,而后咱们就能够利用前面的计算方法将这些偏移量转变成对应的数字了,也就能获得每一个店铺的评分信息了。

 最终运行结果以下:

 

完整代码已上传到GitHub