技术深扒丨没点想象力都看不透这个网站的反扒措施!

所谓万物皆可爬,写一段Python代码,就能让程序自动进行网站访问、解析数据并保存下来,再进行下一步分析,这是一项很酷的技能。

当然各网站也有自己的反爬方式,比如判断用户IP在短时间内是否频繁访问对应网站,比如通过动态页面增加爬取的难度等。

某点评网的反爬可以说是非常有创意了,它使用svg和乱码来防止被爬。难爬不说,就算拿到数据,使用者也不知道是什么意思。

点评网的文字甚至都是不能复制粘贴的。

今天我们就来看看,这一网站的反爬措施到底是多么的具有想象力。

1

观察网站

我们以某商家的电话号码为例,先看看某点评的反爬措施。

在浏览器里按F12打开开发者工具,并使用select工具选中电话,可以看到电话数字除了1以外都是乱码。

通过仔细观察发现该电话最后两个数字都是9,我们对应看到d标签里面的两个class是相同。

这说明该class是用来代表某个数字的。我们先把这几个class和这个数字1弄下来,上Xpath!上正则!

def get_code(url):

    response = requests.get('url',headers=headers).text

    item = etree.HTML(response)
    item = item.xpath('//p[@class="expand-info tel"]')[0]
    item=etree.tostring(item).decode('utf-8')
    item = re.sub('<span.*?</span>','',item,re.S)

    items = re.findall('<d class=(.*?)/>|(d+)',item,re.S)
    phone_list=[]
    for i in items:
        phone_list.append(i[0] if i[0]!='' else i[1])
    return phone_list
  • XPath 是一门在 XML 文档中查找信息的语言,可用于HTML。XPath 可在HTML文档中对元素和属性进行遍历。
  • 正则表达式(Regular Expression,在代码中常简写为regex、regexp或re),是计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。关于python正则表达式的更多资料,大家可以查看文末的资料福利。

通过正则表达式和xpath我们拿到了一个带有数字和乱码的列表,代表的是商家电话号码。这里把原有的数字放在这里是为了保留原来的顺序不变,以便我们后面处理:

再仔细观察,点击每个代表数字的d标签后background里面的两个数字有变化,说明这里就是控制着数字变化的地方。

我们继续找,上方还有个background-image,里面有一个以svg结尾的url。直接打开发现,里面不正是我们想要的数字吗?

2

获取css数据

同样按F12打开开发者工具,我们发现这个svg里面包含了4个text标签,里面有一个x和一个y,里面包含了一堆数字。除此之外,里面还有一段数字文本。

经过我严密的推理,这些数字文本应该就是我们需要找的最终目标了,这里面的x和y应该和上面的background有些关系,我们先把这几个数字拿到手。

首先获取css

def get_css(url):

    response = requests.get(url,headers=headers).text

    html = etree.HTML(response)
    css_url = html.xpath('//link[@rel="stylesheet"]/@href')
    return 'http:'+css_url[1]

用requests获取到css文本,然后print看一下,搜索下上面的class,确保我们找到的css文本正确无误。

css_url = get_css(url)
css_header={'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8', 'Accept-Encoding': 'gzip, deflate', 'Accept-Language': 'zh-CN,zh;q=0.9', 'Cache-Control': 'max-age=0', 'Connection': 'keep-alive', 'Host': 's3plus.meituan.net', 'If-Modified-Since': 'Wed, 06 Mar 2019 14', 'If-None-Match': '"4684b1c3dee8f4d172b2ac0c11e827a1"', 'Upgrade-Insecure-Requests': '1', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
css=requests.get(css_url,headers=css_header)
css.encoding='utf-8'
print(css)

继续用正则表达式根据传入的class定位到backgrount后面的两个数字

def get_xy(code):

    return re.search(code+'{background:-(.*?)px -(.*?)px;}',css.text,re.S).groups()

3

反爬原理

之后就是将text和电话号码对应起来了。经过我天(wu)才(shu)地(ci)尝试,电话号码配对方法是这样的:这是一个需要三次定位的密码,分别是y值定位、x值定位,x[index]值定位。

先说说y定位,还记得数字对应的background数字吗?将后面的数字绝对值(此处是122)加上文字height(此处是30)得到y定位(152)。

使用y定位(152)与前面svg页面里的text标签中的y值进行对比,y定位(152)与哪个y值离得最近就取那个分组。本案例中y定位(152)最靠近第四个text标签(y='145'),所以我们会从第四个分组寻找x定位。

x定位和y定位相似,取的数字是background里面的第一个数字绝对值(302)加上6,得到对应的x定位(308),和x定位数值相同的text里面的数字所在的位置(index)就是我们最后需要的数字(该案例是21)。

最后查看text标签里的数字(num),x定位的index位置上的数字就是我们要的数字(数字5)。

以上是一份破解点评网反爬的秘籍,请大家多次阅读理解,也可以在文末找到视频资料和完整代码。

要实现上面的揭秘过程,先构建Python函数。这里用到了numpy库,主要是处理起来比较方便。先xpath得到所有的y值,存储到array数组中。

def get_svg(svg_url,x_,y):

    response = requests.get(svg_url)

    html = etree.HTML(response.content)
    y_list = html.xpath('//text/@y')//获取到所有的y

    y_list = np.array(y_list)
    y_list=y_list.astype(np.int64)
    y_index = np.abs(y_list-y).argsort()[0]
    y_ = y_list[y_index]
    x=html.xpath('//text[@y="{y}"]/@x'.format(y=y_))
    num = html.xpath('//text[@y="{y}"]/text()'.format(y=y_))

    dict_x = dict(zip(x[0].split(),list(num[0])))
    return dict_x[str(x_)]

这里传入的y值是我们上面background得到的第二个数字,和array数组做个差值,用abs取绝对值,排序,取到差值最小的index,再根据这个Index获取到我们需要的y值。

之后得到我们对应的那组数,然后继续xpath,得到了num和x,将他们组装成一个字典,获取到正确的数字。遍历一下codes, 就可以得到最终需要的电话号码。

自此,我们破解了某点评网的字体反爬。本文用电话号码举例,其实抓取网站中的的口味,环境,服务等字段也是同样的方法。

作为技术,爬虫是合法合理的。诸如谷歌百度这样搜索引擎,也都利用爬虫技术进行全网扫阅,供用户筛选信息,做成产品。网站和爬虫之间,有一个类似道德规范的robots协议。

原文发布于微信公众号 - Python数据科学(PyDataScience)

原文发表时间:2019-03-18

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

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券