反爬虫,到底是怎么回事儿?

tech2024-06-25  71

有位被爬虫摧残的读者留言问:「网站经常被外面的爬虫程序骚扰怎么办,有什么方法可以阻止爬虫吗? 」

这是个好问题,自从 Python 火了起来,编写爬虫程序的门口越来越低,爬取别人网站数据也越来越猖獗。

阻止爬虫也就是我们这次要说的「反爬虫」,「反爬虫」涉及到的技术比较综合,说简单也简单,说复杂也复杂,看具体要做到哪种保护程度了。

下面我们说说常见的「反爬虫」技术。

一、前置知识

1. 动态网页和网页源码

传统的静态网页是指没有数据库和不可交互的纯 HTML 网页,它的页面生成后,如果不修改代码,网页的显示内容和显示效果基本上不会发生变化。

传统的动态网页是指在不改变页面 HTML 代码的情况下,能够根据不同用户或者不同操作而显示不同内容的网页。动态网页在开发、管理和交互性方面的优势远超静态网页。

在爬虫领域中,静态网页与动态网页的定义与传统定义是完全不同的。

静态网页指的是网页主体内容的渲染工作在服务器端完成,并通过响应正文返回的网页。

动态网页指的是主体内容或者全部内容都需要客户端执行 JavaScript 代码来计算或渲染的网页。

网页源码,是指未经过浏览器解释和 JavaScript 引擎渲染的文本,它的文本内容与 HTML 原文中的内容是相同的。

爬虫并不是一种“所见即所得”的程序,它通过网络请求的方式获取资源。在得到的资源中,最

重要的就是响应正文。但是由于 Python、 Java 和 PHP等编程语言没有 JavaScript 解释器和渲染引擎,所以使用编程语言编写的爬虫程序无法渲染页面,它们只能爬取响应正文中的内容,也就是网页源代码中的内容。

如果想要爬取动动态网页中的数据,那么就需要借助 JavaScript 解释器和渲染引擎将渲染后的网页代码以文本的形式传给爬虫。

有一些工具已经集成了渲染页面所需的组件,并且开放 API 允许编程语言操作页面以获取渲染后的页面代码。爬虫工程师常用的渲染工具如下。

Splash:异步的 JavaScript 渲染服务。

Selenium:自动化测试框架。

Puppeteer:一个通过 DevTools 协议控制 Chrome 的 Node js库。

2. 爬虫

爬虫指的是按照一定规则自动抓取网络信息的程序,分为通用爬虫和聚焦爬虫两大类,前者的

目标是在保持一定内容质量的情况下爬取尽可能多的站点;而后者的目标则是在爬取少量站点的情况下尽可能保持精准的内容质量。

爬虫通常从一个或多个 URL 开始,在爬取的过程中不断将新的并且符合要求的 URL 放人待爬队列,直到满足程序的停止条件。

爬虫的的爬取过程可以分为下面3个步骤。

(1)请求指定的 URL 以获取响应正文。

(2)解析响应正文内容并从中提取所需信息。

(3)将上一步提取的信息保存到数据库或文件中。

二、反爬虫

爬虫程序的访问速率和目的与正常用户的访间速率和目的是不同的,大部分爬虫会无节制地对目

标应应用进行爬取,这给目标应用的服务器带来巨大的压力。爬虫程序发出的网络请求被运营者称为“垃圾流量”。

开发者为了保证服务器的正常运转或降低服务器的压力与运营成本,不得不使出各种各样的技术

手段来限制爬虫对服务器资源的访问。因为爬虫和反爬虫是综合技术的应用,反爬虫的现象与爬虫工程师所用的工具和开发语言有关,甚至与爬虫工程师的个人能力也有一定关联,所以反爬虫的概念非常模糊,业内并没有明确的定义。

本文所说,限制爬虫程序访问服务器资源和获取数据的行为称为反爬虫。限制手段包括但不限于请求限制、拒绝响应、客户端身份验证、文本混淆和使用动态渲染技术。这些限制根据出发点可以分为主动型反爬虫和被动型反爬虫。

主动型反爬虫:开发者有意识地使用技术手段区分正常用户和爬虫,并限制爬虫对网站的访问行为,如验证请求头信息、限制访问频率、使用验证码等。

被动型反爬虫:为了提升用户体验或节省资源,用一些技术间接提高爬虫访问难度的行为,比如数据分段加载、点击切换标签页、鼠标悬停预览数据等。

除此之外,还可以从特点上对反爬虫进行更细致的划分,如信息校验型反爬虫、动态渲染型反爬虫、文本混淆型反爬虫、特征识别型反爬虫等。

需要注意的是,同一种限制现象可以被归类到不同的反爬虫类型中,比如通过 JavaScript 生成随机字符串并将字符串放在请求头中发送给服务器,由服务器校验客户端身份的这种限制手段既可以说是信息校验型反爬虫,又可以说是动态渲染反爬虫。

反爬虫不仅要了解网站流量情况,还需要了解爬虫工程师常用的手段,并从多个方面进行针对性的防护。

反爬虫的方案设计、实施和测试等都需要耗费大量的时间,而且往往需要多个部门配合才能完成。从这个角度来看,除了技术难度外,时间成本也是非常高的。

三、信息校验型爬虫

信息校验中的“信息”指的是客户端发起网络请求时的请求头和请求正文,而“校验”指的是服务器端通过对信息的正确性、完整性或唯一性进行验证或判断,从而区分正常用户和爬虫程序的行为。

1. User-Agent 反爬虫

User-Agent 是请求头域之一,服务器从 User-Agent 对应的值中识别客户端的使用信息。User-Agent 的角色就是客户端的身份标识。服务器可以使用黑名单结合条件判断实现针对性较强的反爬虫。

除了 User-Agent 之外,可利用的头域还有 Host 和 Referer。这种验证请求头信息中特定头域 的方式既可以有效地屏蔽长期无人维护的爬虫程序,也可以将一些爬虫初学者发起的网络请求拒之门 外,但是对于一些经验丰富的爬虫工程师,或许还需要更巧妙的反爬虫手段。

2. Cookie 反爬虫

Cookie 反爬虫指的是服务器端通过校验请求头中的 Cookie 值来区分正常用户和爬虫程序的手段,也可以把 Cookie 和 JavaScript 结合起来实现反爬虫,提高爬虫难度,这种手段被广泛应用在 Web 应用中。

例如,在 HTML 代码中引入一个可以将浏览器重定向到目标页面的 JavaScript 文件,并且在这个文件中实现随机字符串生成和 Cookie 设置的功能,那么服务器端只需要校验 Cookie 值的规则即可。避免了通过将 Cookie 值从浏览器的请求头中复制,就可以一直使用这个简单的方法。

User-Agent 和 Cookie 都是请求头的默认头域,在值的设定方面有一定的局限性,但是与JavaScript 结合后,就会变得很灵活。

相对服务器软件来说,后端程序的校验更为灵活且准确,但使用后端程序进行校验所需的步骤较多,在实际应用时可以根据需求选择合适的校验方式。

3. 签名验证反爬虫

签名是根据数据源进行计算或加密的过程,签名的结果是一个具有唯一性和一致性的字符串。签名结果的特性使得它成为验证数据来源和数据完整性的条件,可以有效避免服务器端将伪造的数据或被篡改的数据当成正常数据处理。

签名验证是防止恶意连接和数据被篡改的有效方式之一,也是目前后端 API 最常用的防护方式之 一。与 Cookie、User-Agent 请求头域不同,用于签名验证的信息通常被放在请求正文中发送到服务器端。

签名验证反爬虫利用 JavaScript 生成随机值,与之前的随机值不同,这次的随机值中包含时间戳和 MD5 加密值。签名验证有很多种实现方式,但原理都是相同的:由客户端生成一些随机值和不可逆的 MD5 加密字符串,并在发起请求时将这些值发送给服务器端。服务器端使用相同的方式对随机值进行 计算以及 MD5 加密,如果服务器端得到的 MD5 值与前端提交的 MD5 值相等,就代表是正常请求, 否则返回 403。

4. WebSocket 握手验证反爬虫

WebSocket 握手时使用的协议是 HTTP 协议,所有基于 HTTP 协议的反爬虫都可以用在 WebSocket 协议上。

客户端按照 WebSocket 规范生成握手信息并向服务器端发送握手请求,然后读取服务器端推送的消息,最后验证握手结果。WebSocket 协议规范只作为参考,服务器端和客户端实际上可以不遵守这些约定。

比如服务器端可以在校验握手信息时增加对客户端 User-Agent 或 Referer 的验证,如果客户端发送的握手请求中并没有对应的信息,则拒绝连接。想要实现这个功能,只需要 在服务器端的代码中增加相关的信息验证代码即可。

5. WebSocket 消息校验反爬虫

如果握手验证成功,双端就可以开始互推消息了。WebSocket 只需要完成 1 次握手,就可以保持长期连接,在后续的消息互发阶段是不需要用到 HTTP 协议的,那么如何在 WebSocket 通信过程中实现反 爬虫呢?

其实消息互发阶段也是可以对客户端身份进行校验的,这是因为客户端所获取的消息是由服务器端主动推送的,如果服务器端不主动推送,那么客户端就无法获取消息。我们可以在服务器端新增一个校验逻辑:握手结束后客户端发送特定的消息,服务器端对该消息进行校验,校验通过则将服务器端的数据推送给客户端,否则不作处理。

6. WebSocket Ping 反爬虫

WebSocket 是可以保持长期连接的。但是服务器端不可能保持所 有客户端永久连接,这太耗费资源了,有没有一种办法可以检查客户端的状态呢?

WebSocket 协议规范中约定,服务器端可以向客户端发送 Ping 帧,当客户端收到 Ping 帧时应当回复 Pong 帧。如果客户端不回复或者回复的并不是 Pong 帧,那么服务器端就可以认为客户端异常,主动关闭该连接。 

通常,Ping 帧和 Pong 帧的 Payload Data 中是没有内容的,所以只要目标服务器发送 Ping 帧时,客户端回复没有任何内容的 Pong 帧即可。

WebSocket 协议中的规范并不强制遵守,所以开发者可以自定义 Ping 帧和 Pong 帧,这就为反爬虫提供了条件。

假如开发者在编写服务器端代码时,将 Ping 帧定义为有一定内容的数据帧,同时对 Pong 帧的 Payload Data 进行校验,就可以将不符合规则的连接关闭。

四、动态渲染反爬虫

由 JavaScript 改变 HTML DOM 导致页面内容发生变化的现象称为动态渲染。很多时候开发者只是想完成某个交互功能,而不是特意区分正常用户和爬虫程序,但这在不经意间限制了爬虫对数据的获取。

由于编程语言没有像浏览器一样内置JavaScript解释器和渲染引擎,所以动态渲染是天然的反爬虫手段。

1. 自动执行的异步请求

异步请求能够减少网络请求的等待时间,从而提升网页加载速度。为了追求用户体验、提升网站加载速度和减少用户等待时间,开发者会将内容较多的综合信息页面拆分成多个部分,然后使用异步请求的方式获取资源。

2. 点击事件和计算

点击事件指的是用户在浏览网页的过程中使用鼠标点击按钮或标签等页面元素的操作,这类事件通常会与一个 JavaScript 方法绑定到一起,当事件触发时浏览器就会执行事件绑定的方法。

这里提到的计算是指使用 JavaScript 计算数值并将结果渲染到网页。开发者使用 JavaScript 计算数据有可能是为了反爬虫,也有可能是为了提高用户体验,因为客户端本地的计算速度远远超过网络请求的速度。

3. 下拉加载和异步请求

网页中下拉加载实际上是一种翻页操作,当我们点击下一页或指定页码按钮的时候,浏览器会跳转到对应页码,这个跳转造成了页面的刷新,也就是向其他页面发起请求。

而下拉加载通过异步请求和局部渲染避免刷新整个页面,局部渲染既避免了重复请求资源,又减少了用户等待的时间,这对于网站来说是一件很有意义的事。

文本混淆反爬虫

文本混淆可以有效地避免爬虫获取 Web 应用中重要的文字数据,使用文本混淆限制爬虫获取文字数据的方法称为文本混淆反爬虫。

反爬虫的前提是不能影响用户正常浏览网页和阅读文字内容,直接混淆文本很容易被看出来,所以开发者通常是利用 CSS 的特性来实现混淆。

1. 图片伪装反爬虫

图片伪装指的是将带有文字的图片与正常文字混合在一起,以达到“鱼目混珠”的效果。这种混淆方式并不会影响用户阅读,但是可以让爬虫程序无法获得“所见”的文字内容。

2. CSS偏移反爬虫

CSS 偏移反爬虫指的是利用 CSS 样式将乱序的文字排版为人类正常阅读顺序的行为。

例如:

HTML 文本中的文字:我的学号是 1308205,我在北京大学读书。

浏览器显示的文字:我的学号是 1380205,我在北京大学读书。

爬虫提取到的学号是 1308205,但用户在浏览器中看到的却是 1380205。

如果不细心观察,爬虫工程师很容易被爬取结果糊弄。这种混淆方法和图片伪装一样,是不会影响用户阅读的。

3. SVG映射反爬虫

SVG 是用于描述二维矢量图形的一种图形格式。它基于 XML 描述图形,对图形进行放大或缩小操作都不会影响图形质量。矢量图形的这个特点使得它被广泛应用在 Web 网站中。

这种反爬虫手段用矢量图形代替具体的文字,不会影响用户正常阅读,但爬虫程序却无法像读取文字那样获得 SVG 图形中的内容。

由于 SVG 中的图形代表的也是一个个文字,所以在使用时必须在后端或前端将真实的文字与对应的 SVG 图形进行映射和替换,这种反爬虫手段被称为 SVG 映射反爬虫。

4. 字体反爬虫

在 CSS3 之前,Web 开发者必须使用用户计算机上已有的字体。但是在 CSS3 时代,开发者可以使用 @font-face 为网页指定字体,对用户计算机字体的依赖。

开发者可将心仪的字体文件放在 Web 服务器上,并在 CSS 样式中使用它。用户使用浏览器访问 Web 应用时,对应的字体会被浏览器下载到用户的计算机上。

我们知道 CSS 的作用是修饰 HTML ,所以在页面渲染的时候不会改变 HTML 文档内容。

由于字体的加载和映射工作是由 CSS 完成的,所以即使我们借助 Splash、Selenium 和 Puppeteer 工具也无法获得对应的文字内容。

字体反爬虫正是利用了这个特点,将自定义字体应用到网页中重要的数据上,使得爬虫程序无法获得正确的数据。

结尾

虽然反爬虫措施有很多,但每一种都不是绝对安全的,爬虫高手依旧可以绕过反爬虫机制。在此之前也要做好一些基础的规则,比如说 robots 协议或者用户协议等。

如果你的网站被多进行高并发的程序被恶意爬虫时,这已经不是单纯的爬虫行为了,属于恶意破坏网络安全,必须要第一时间收集证据,用法律手段对抗那些非法的爬虫行为。

圈内常说「爬虫玩的好,牢饭吃得早」,善意地提醒 Python 玩得特别六的同学,不要随便爬取别人的隐私数据和有版权的内容,爬虫不是法外之地,技术也不是纯粹的无罪。

最新回复(0)