专栏首页Python绿色通道爬虫进阶 | 点评网的反爬再也不是烦恼

爬虫进阶 | 点评网的反爬再也不是烦恼

文章之前:其实做爬虫并不难,但难的是一些反爬,每个爬虫师都有要与反爬师做斗争,所以很多时候,爬虫易学难精就是这个缘故,你不知道那天工程师又弄出一种新的反爬策略,无止无尽的斗争让人身心交瘁.

下面来看看点评网使用的一些反爬手段!

点评网的反爬设置在我们爬取点评网页的时候给我们造成了不小的障碍。在网页上我们看到的是这样的

网页上可以看到这家餐厅有1405条评论,人均387。但在分析页面源码的时候,我们却看不到网页上的数字,看到是这样的代码

点评网对数字做了处理,一些数字的信息像评论条数、人均、评分等都做了反爬保护。上面的网页中评论条数是1405条,但在页面源码中,除了第一个数字1以外,后面的数字我们看不到,都是一些像随机编码一样的css class。

如果我们仔细分析这个css class,其实是不难发现背后的原理的。

通过开发者工具,我们找到这个css的定义,可以看到是下面这样的

background-image属性里面是一个url,我们在浏览器里打开它,看到它的内容是

lc-mY1i 这个css class里面是一个background属性,定义了背景图片偏移的位置。

所以点评网上显示数字的原理就是通过设置不同的偏移位置,显示背景图片相应位置上的数字。我们可以想象背景图片的前面有一个窗口,窗口的大小刚好够显示一个数字。窗口是固定不动的,背景图片在后面移动,移动到不同的位置就能显示这个位置上的数字。

进一步分析背景图片,我们可以发现,这是一个SVG图片,图片中的数字可以在svg的源码中看到,如下

理解了原理后,我们用代码来实现一下解析的过程。

首先我们从点评的网页上找出css文件的url,代码如下

def get_css():
    url = "http://www.dianping.com/shanghai/ch10"
    r = requests.get(url, headers=headers)
    content = r.content.decode("utf-8")
    matched = re.search(r'href="([^"]+svgtextcss[^"]+)"', content, re.M)
    if not matched:
        raise Exception("cannot find svgtextcss file")
    css_url = matched.group(1)
    css_url = fix_url(css_url)
    return css_url

随后我们从css里找到背景图片的路径,并获取SVG图片中的每个数字

def get_svg(css_url):
    r = requests.get(css_url, headers=headers)
    content = r.content.decode("utf-8")
    matched = re.search(r'span\[class\^="lc\-"\].*?background\-image: url\((.*?)\);', content)
    if not matched:
        raise Exception("cannot find svg file")
    svg_url = matched.group(1)
    svg_url = fix_url(svg_url)
    r = requests.get(svg_url, headers=headers)
    content = r.content.decode("utf-8")
    matched = re.search(r'class="textStyle">(\d+)</text>', content)
    if not matched:
        raise Exception("cannot find digits")
    digits = list(matched.group(1))
    return digits

这个函数返回一个数组,数组的内容是SVG图片中的所有数字。

对于点评网页中的用css class表示的数字,我们来解析一下css class和数字之间的对应关系

def get_class_offset(css_url):
    r = requests.get(css_url, headers=headers)
    content = r.content.decode("utf-8")
    matched = re.findall(r'(\.[a-zA-Z0-9-]+)\{background:(\-\d+\.\d+)px', content)
    result = {}
    for item in matched:
        css_class = item[0][1:]
        offset = item[1]
        result[css_class] = offset   
   return result

这个函数返回的是一个字典,它的key是css class的名字,value是css class对应的数字在背景图片中的偏移量。

接下来,我们以评论条数为例,来获取点评上一个页面里每家餐厅的评论条数。先定义函数,用于获取评论条数

def get_review_num(page_url, class_offset, digits):
    r = requests.get(page_url, headers=headers)
    content = r.content.decode("utf-8")
    root = etree.HTML(content)
    shop_nodes = root.xpath('.//div[@id="shop-all-list"]/ul/li')
    for shop_node in shop_nodes:
        name_node = shop_node.xpath('.//div[@class="tit"]/a')[0]
        name = name_node.attrib["title"]
        review_num_node = shop_node.xpath('.//div[@class="comment"]/a[@class="review-num"]/b')[0]
        num = 0
        if review_num_node.text:
            num = num * 10 + int(review_num_node.text)
        for digit_node in review_num_node:
            css_class = digit_node.attrib["class"]
            offset = class_offset[css_class]
            index = int((float(offset)+7)/-12)
            digit = int(digits[index])
            num = num * 10 + digit
        last_digit = review_num_node[-1].tail        if last_digit:
            num = num * 10 + int(last_digit)
        print("restaurant: {}, review num: {}".format(name, num))

然后调用函数,爬一下页面中每家餐厅的评论条数

css_url = get_css()digits = get_svg(css_url)class_offset = get_class_offset(css_url)url = "http://www.dianping.com/shanghai/ch10/g116"get_review_num(url, class_offset, digits)

运行代码后,得到如下的结果

restaurant: 1886汽车主题德国餐厅(环宇荟店), review num: 1021
restaurant: Mia Fringe迷芬奇餐厅&酒吧, review num: 152
restaurant: Oyster EXPO江月蚝庭西餐生蚝吧(世博源店), review num: 1405
restaurant: 宝莱纳餐厅(陆家嘴店), review num: 7854
restaurant: Pizza Marzano玛尚诺(港汇店), review num: 7527
restaurant: love&salt牛排馆, review num: 86
restaurant: Da Ivo 意大利魔镜餐厅, review num: 3497
restaurant: Mr Nice好好先生餐厅(月星环球港店), review num: 9052
restaurant: L'ATELIER de Joël Robuchon, review num: 2821
restaurant: Stone Sal 言盐西餐厅, review num: 62
restaurant: 夏朵花园, review num: 3031
restaurant: 壳里西餐厅Coquille Seafood Bistro, review num: 322
restaurant: ICHA Chateau Bar & Restaurant(酒吧创意料理), review num: 496
restaurant: 菲斯特花园西餐厅, review num: 655
restaurant: 宝丽嘉酒店Cafe Bellagio(宝丽嘉西餐厅), review num: 598

对照网页上的数据,可以看到,餐厅的评论条数都被正确的解析出来了。

本文分享自微信公众号 - Python绿色通道(Future_coder)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-12-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 叮!你要的Python脱单攻略已送达

    年关将至,学妹却因为男朋友不愿意带她回家过年而难过,我劝学妹主动点,自己多提几次,但是学妹觉得身为女孩子不能太主动。

    叫我龙总
  • Scrapy实战6:CSS选择器实战训练

    上一篇文章Scrapy实战5:Xpath实战训练中给大家讲解并带着大家实战训练了Xpath,爬取了伯乐在线文章的基本信息,并且介绍scrapy里的shell调试...

    叫我龙总
  • Scrapy实战7: 分类爬取医疗信息网站图片

    今天X先生带大家正真的实战:爬取医疗信息网站的图片及分类存储到本地和存储到MySql数据库。

    叫我龙总
  • 通过欧拉计划学Rust编程(第71题)

    由于研究Libra等数字货币编程技术的需要,学习了一段时间的Rust编程,一不小心刷题上瘾。

    申龙斌
  • Linux巩固记录(2) java项目的编译和执行

    以前只在linux上配置J2EE项目执行环境,无非配置下jdk,部署tomcat,再通过docker或者jenkins自动部署上去

    肖哥哥
  • 加载远程图片

    根据默认图片的大小和位置,显示远程图片,只需要把组件挂载在Sprite上,需要更新的时候,调用以下方法即可。

    一枚小工
  • 什么是物联网操作系统?

    物联网(IoT)是目前最新最热的技术热点之一,也是这个信息化时代的重要发展节点。相对于互联网而言,物联网的本质在于“万物相连” 。物联网的核心和基础仍然是互联网...

    AI 电堂
  • VR影视先锋Jaunt宣布裁员,关闭VR业务

    近日,VR视频公司Jaunt表示,他们已经关闭了“一系列”VR相关业务,并且裁撤了“相当一部分”员工。未来,Jaunt将会更加注重AR领域的开拓。

    镁客网
  • 【绘图】高维数据可视化必备图形-平行坐标图

    正如在这个图形中,可以清晰的看到,某些观察值随着组别的变化而产生的变化。不过,随着基因组大数据的不断发展和应用,在很多科研绘图场景中,高维数据的处理变得越来越重...

    用户6317549
  • keras.callbacks

    Callbacks: utilities called at certain points during model training.

    于小勇

扫码关注云+社区

领取腾讯云代金券