关于这里提出的爬虫

目前来说,爬虫大多是利用一些免费的接口获取一些数据信息(文字,图片,音频,视频等),这种爬虫大多都有指向性(单纯的获取专门的消息)。

从最简单的基础来说,这种爬虫无非就是模拟一个http请求向服务器请求一个页面(资源)然后再获取响应中想要的数据。 指向性的爬虫通常是一个入门者(比如我)经常写的,但是这里提出的爬虫有些许不同。 这里使用的爬虫是对网站进行遍历的爬虫,也就是目的是对网站整个结构进行爬取整理,与这种类似的爬虫就是搜索引擎的爬虫了。

这里可能有人就会问了,为什么要防止这种爬虫对网站进行遍历?如果搜索引擎爬取了自己的网站不是很好么? 的确,如果是搜索引擎这种正当行为的爬虫的爬取,对网站的SEO很有利,站长门可能还会使用sitemap去帮助搜索引擎进行爬取。 但是,如果对方是利用爬虫去遍历你的网站寻找你的后台,或者未做访问控制的路径呢,或者去访问你暴露的配置文件呢,或者是通过URL对你的网站进行自动化漏洞扫描呢?

前段时间一直在做这一块的毕业论文,查过一些资料,这些资料的思路基本都是通过爬虫以网页的主页为入口进行或深度遍历或广度遍历的URL获取。这样就可以短时间获取整站的所有链接,然后在进行后续的测试。

关于常见的反爬虫机制

首先买个关子,先不说新思路,先来看一下常见的反爬虫的一些机制和对策。

  1. 判断User-Agent的进行反爬虫机制:

    这种反爬机制说实话就像一层纸,做过爬虫的人都知道,大部分的网站都会判断用户是不是”正常”的浏览器,只要在爬虫爬取之前给请求中加入适当的User-Agent即可放心大胆的进行爬取。

  2. 判断爬取速度(频率)的反爬虫机制:

    很多人也知道,爬虫这个东西其实对网站整体的业务其实影响非常大,如果有几个爬虫长期对一个网站进行不间断爬取会影响到服务器的响应。于是乎,我在服务端判断你是不是一个爬虫就通过你的IP对页面的爬取频率来看,你要是以唯一的IP进行一种恒定的速度进行爬取,我就判定你是爬虫,ban掉你。然后对策就是,随机的爬取间隔时间,不定期的短时间暂停+代理的爬取模式。虽然直接效率下降了,但是对于反爬机制又是一种很好的bypass。

  3. 由爬取速度再引申出来的反爬虫机制:

    既然上面的反反爬虫的机制已经有点模拟正常用户的行为了,那我就直接引入人机验证,通过验证码,人机验证(我觉得google的reCaptcha就非常到位,但是不幸的事情,国内这个东西用不了)。但是,道高一尺,魔高一丈。随着现在图像识别技术的飞速发展,目前简单的图像失真验证码已经很容易就被攻克了,爬虫继续肆虐。

  4. 动态页面带来的反爬虫:

    现在很多页面使用了ajax请求去完成页面的加载,更高级点的会使用一些加密接口,那么解决办法也来了。如果是固定目标,爬虫开发者可以通过先分析ajax请求再处理json爬取的方式继续爬取。那么通过用加密接口等方式就封杀了遍历网站的爬虫吗,并不…selenium这种自动化测试框架以及PhantomJS这种神器的诞生似乎又打消了反爬虫最后的一点希望,但是唯一带来的好处就是爬虫的效率低下来了。

所以,就我来看,相对成功的反爬机制就是使用Google的reCaptcha。但是种种原因,国内并不支持这种好东西,后来了解了一下国内有一个叫极验的做的也挺好【不过没见过也不知道具体怎么样。

关于”新”的反爬虫思路、简单实现及目前的不足

“新”反爬虫思路。

说白了,爬虫并不是用户,尤其是像我说到的扫描工具的爬虫,它只会进行无脑的广度或深度爬取,可能他会做到爬取所有链接,简单去重,但是它并不能识别这个链接是否是真正”有用”的链接。这样的话,可以通过给页面中加入一些隐藏的链接地址,也就是说正常用户看不见的(不可点击的)链接,通过诱导爬虫爬取这种链接,然后再ban掉访问这些链接的IP,这样就达到了一种防止爬虫继续爬取简单有效的方法。

简单实现

最简单的情况,爬虫以正则表达式的方式去匹配链接的话,那么只要在html页面中插入一个注释就能伪造一个链接去诱导爬虫进行爬取,比如

<!--<a href="/trap.html">this is a trap</a>-->

简单界面-1

# re演示
import re
import requests

def get_href(page):

    url_list = re.findall('href="(.*?)"', page)
    print url_list

if __name__ == "__main__":

    page = requests.get("http://127.0.0.1/index.html").text
    get_href(page)

简单演示结果-1

然后把这种代码插入到网站主页(通常扫描器爬虫的入口页面)中,偌大的页面中可供点击的链接只有一个,正常的用户可能只会点击这个超链接跳转到百度。而使用正则表达是的爬虫则是访问到了这个trap链接,被后台ban掉,问题看似迎刃而解。

但是如果爬虫使用bs4或者其他框架解析页面的怎么办?稍加将上面的代码进行改变:

# BeautifulSoup演示
import re
import requests
from bs4 import BeautifulSoup

def get_href(page):

    soup = BeautifulSoup(page, 'lxml')
    url_list = [link["href"] for link in soup.find_all('a')]
    print url_list

if __name__ == "__main__":

    page = requests.get("http://127.0.0.1/index.html").text
    get_href(page)

相同页面:

反爬失效了-1

或者是Xpath:

# Xpath演示
import re
import requests
from lxml import etree

def get_href(page):

    tree = etree.HTML(page)
    url_list = [link for link in tree.xpath("//@href")]
    print url_list

if __name__ == "__main__":

    page = requests.get("http://127.0.0.1/index.html").text
    get_href(page)

相同的页面:

反爬失效了-2

看来这种解析器不能解析埋下的陷阱,那应该怎么让爬虫上钩?

html中支持hidden属性,也就是我们主动将某个a标签置于隐藏,用户自然看不见这种隐藏的标签,但是相对与爬虫这种对整个HTML做遍历的工作过程中自然是不会忽略上述代码的。下面就实验下:

<p hidden><a href="https://www.bing.com">bing</a></p>

在第一个测试的页面中,插入这样的一个隐藏的p标签,页面的效果变成这样:

页面中隐藏了一个链接

继续看看上面三种爬虫的结果怎么样:

test1

这样就能诱导爬虫上钩了。

“新”思路的不足

但是问题就来了,这样粗枝大叶的去ban爬虫很容易误伤搜索引擎的爬虫,这样怎么办?

现在各家的搜索引擎爬虫都有各自的特征值,可以判断这些特征值来解决问题。下面是google爬虫使用的特征:

User-agent: Googlebot

更多特征请看->Top 10 搜索引擎爬虫和 User-Agents

但是这样如果爬虫伪装成了搜索引擎的特征值又怎么办?

于是,反爬机制又回到了人机校验这一块。

我认为,目前来讲除了人机校验没有一种成功的防止爬虫肆虐的方法。【reCaptcha

随着这两年机器学习人工智能两个方向的不断发展,同样的反爬机制也会像爬虫一样在进步,如果有一天真的突破了效率的问题,我相信人机校验也抵挡不住爬虫的进步。


Monburan

好奇|爱折腾