大家好,我是四毛,好久没有写东西了,欢迎大家关注我的公众号。
今天的文章是关于如何使用 requests 来爬取大众点评的数据。 看完本文,你可以:
1、了解大众点评的 CSS 反爬虫机制 2、破解反爬虫机制 3、使用 requests 即可正确获取到评论数,平均价格,服务,味道,环境数据,评论文本数据;
如果你想跟我继续交流的话,欢迎加我的个人微信,二维码在最后。 如果你想获取更多的代码,请关注我的公众号,并发送 “大众点评”即可。 同时,代码我并没有做太多的优化,因为没有大量的代理,爬不了太多的内容。 这里只是跟大家分享一下处理的流程。欢迎来公众号留言探讨。
正文开始。
1.前言
在工作生活中,发现越来越多的人对大众点评的数据感兴趣,而大众点评的反爬又是比较严格的。采取的策略差不多是宁可错杀一万,也不放过一个。有的时候正常浏览都会跳出验证码。 另外,在 PC 端的展示数据是通过 CSS 来控制的,从网页上看不出来太大的区别,但是用普通的脚本取获取时,会发现数据是获取不到的,具体的源代码是下面这样的: 然,在搜资料的时候,你会发现,很多教程都是用的 selenium 之类的方法,效率太低,没有啥技术含量。 所以,这篇文章的面向的对象就是 PC 端的大众点评;目标是解决这种反爬虫措施,使用 requests 获取到干净正确的数据; 跟着我,绝不会让你失望。
2.正文开始
相信搞过大众点评网站的同学都应该知道上面的这种是一个 css 反爬的方法,具体的解析操作,即将开始。
找到藏着秘密的 css
当我们的鼠标在上面框框内的 span 上面点击时,会发现右边部分会相应的发生变化: 这张图片很重要,很重要,很重要 ,我们要的值,几乎都从这里匹配出来。 这里我们看到了“vxt20 ”这个变量对应的两个像素值,前面的是控制用哪个数字,后面的是控制用哪一段的数字集合 ,先记下,后面要用,同时这里的值应该是 6; 这里其实就是整个破解流程最关键的一步了。在这里我们看到了一个链接。 瞎猫当死耗子吧,点进去看看。 https://s3plus.meituan.net/v1/mss_0a06a471f9514fc79c981b5466f56b91/svgtextcss/f556c0559161832a4c6192e097db3dc2.svg 你会发现,返回的是一些数字,我一开始是不知道这是啥玩意的,看过一些大神的解析才知道,其实这里就是我们看到的数字的来源,也就是整个破解的源头,知道了这些数字的含义,也就可以直接破解了整个反爬的流程。 现在直接看源代码: 可以看到这里面的几个关键数字:font-size:字体大小;还有几个 y 的值,我到后面才知道原来这个 y 是个阈值,起的是个控制的作用。 所以,这一反爬的原理就是:
获取属性值与偏移量和阈值映射,然后从 svg 文件中找到真数据。
现在我们就要用到上面的像素值了。
1.把所有的值取绝对值; 2.用后面的值来选择用哪个段的数字,这里的值是 103,所以使用第三个段的数字集合; 3.因为每个字体是 12 个像素,所以用 163/12=13.58,约等于 14,那么我们数一下第 14 个数字是啥,没错,是 6,和预期一样。你可以多试验几次。
以上,就是整个破解的逻辑过程。 画个流程图,装个逼:
3.Show Code
下面开始晒代码,俗话说得好,天下代码一大抄。 这里对主要的步骤代码进行解释, 如果你想获取更多的代码,请关注我的公众号,并发送 “大众点评”即可。 。 1.获取 css_url 及 span 对应的 TAG 值;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
def get_tag (_list, offset=1 ) : _new_list = [data[0 :offset] for data in _list] if len(set(_new_list)) == 1 : offset += 1 return get_tag(_list, offset) else : _return_data = [data[0 :offset - 1 ] for data in _list][0 ] return _return_data def get_css_and_tag (content) : """ :param url: 待爬链接 :return: css链接,该span对应的tag """ find_css_url = re.search(r'href="([^"]+svgtextcss[^"]+)"' , content, re.M) if not find_css_url: raise Exception("cannot find css_url ,check" ) css_url = find_css_url.group(1 ) css_url = "https:" + css_url class_tag = re.findall("<b class=\"(.*?)\"></b>" , content) _tag = get_tag(class_tag) return css_url, _tag
2.获取属性与像素值的对应关系
1 2 3 4 5 6 7 8 9 10 11 12 13
def get_css_and_px_dict (css_url) : con = requests.get(css_url, headers=headers).content.decode("utf-8" ) find_datas = re.findall(r'(\.[a-zA-Z0-9-]+)\{background:(\-\d+\.\d+)px (\-\d+\.\d+)px' , con) css_name_and_px = {} for data in find_datas: span_class_attr_name= data[0 ][1 :] offset = data[1 ] position = data[2 ] css_name_and_px[span_class_attr_name] = [offset, position] return css_name_and_px
3.获取 svg 文件的 url
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
def get_svg_threshold_and_int_dict (css_url, _tag) : con = requests.get(css_url, headers=headers).content.decode("utf-8" ) index_and_word_dict = {} find_svg_url = re.search(r'span[class\^="%s"].*?background\-image: url\((.*?)\);' % _tag, con) if not find_svg_url: raise Exception("cannot find svg file, check" ) svg_url = find_svg_url.group(1 ) svg_url = "https:" + svg_url svg_content = requests.get(svg_url, headers=headers).content root = H.document_fromstring(svg_content) datas = root.xpath("//text" ) last = 0 for index, data in enumerate(datas): y = int(data.xpath('@y' )[0 ]) int_data = data.xpath('text()' )[0 ] index_and_word_dict[int_data] = range(last, y+1 ) last = y return index_and_word_dict
4. 获取最终的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
def get_data(url ): "" " :param page_url: 待获取url :return: " "" con = requests.get(url, headers=headers).content.decode("utf-8") css_url, _tag = get_css(con) css_and_px_dict = get_css_and_px_dict(css_url) svg_threshold_and_int_dict = get_svg_threshold_and_int_dict(css_url, _tag) doc = etree.HTML(con) shops = doc.xpath('//div[@id="shop-all-list"]/ul/li') for shop in shops: name = shop.xpath('.//div[@class="tit"]/a')[0].attrib["title"] print name comment_num = 0 comment_and_price_datas = shop.xpath('.//div[@class="comment"]') for comment_and_price_data in comment_and_price_datas: _comment_data = comment_and_price_data.xpath('a[@class="review-num"]/b/node()') for _node in _comment_data: if isinstance(_node, etree._ElementStringResult): comment_num = comment_num * 10 + int(_node) else : span_class_attr_name = _node.attrib["class" ] offset, position = css_and_px_dict[span_class_attr_name] index = abs(int(float(offset) )) position = abs(int(float(position))) for key, value in svg_threshold_and_int_dict.iteritems(): if position in value: threshold = int(math.ceil(index/12 )) number = int(key[threshold]) comment_num = comment_num * 10 + number print comment_num
4.结果展示
评论条数数据
其实,其他的我都写好了,就不贴了
评论具体数据
5.结语
以上就是大众点评 Css 反爬破解的全部步骤和部分代码。 如果你想获取更多的代码,请关注我的公众号,并发送 “大众点评”即可。