为什么你的爬虫能被识别到?

前言

反爬机制是网站和服务器采用的方法,用于防止恶意爬虫和机器人访问其内容或资源。以下是一些常见的反爬机制:

  • Robots.txt文件:Robots.txt文件用于指导搜索引擎爬虫以及其他网络爬虫哪些页面可以爬取,哪些不可以。虽然它是一个公开的标准,但一些爬虫可能会不遵守。
  • User-Agent检测:服务器会检查用户代理(User-Agent)标头,如果检测到它不是浏览器的标准User-Agent,就可能拒绝访问或限制访问。
  • IP封锁:服务器可以基于IP地址封锁恶意或频繁访问的IP地址。这会限制来自特定IP地址的访问。
  • 验证码:服务器可以要求用户或爬虫输入验证码以验证其人类身份。这可以有效地拦截自动化爬虫。
  • 频率限制:服务器可以限制相同IP地址的请求频率。如果请求过于频繁,服务器可能会拒绝额外的请求。
  • 登录要求:某些内容需要用户登录后才能访问。这可以防止未经授权的访问。
  • 动态内容加载:使用JavaScript等技术,页面可以在客户端上动态加载内容。这对爬虫来说更难以获取数据。
  • 数据分页:将内容拆分为多个页面,每页只包含一部分数据,导致爬虫需要遍历多个页面才能获取全部数据。
  • Honeypot陷阱:在网站中放置不可见链接或表单字段,如果爬虫尝试访问或填写这些字段,可以识别它们。
  • Referer检查:服务器可能会检查HTTP Referer标头,以确保请求来自合法来源。如果没有Referer或Referer不正确,可能会拒绝访问。
  • 反爬虫工具:有一些专门用于检测和对抗爬虫的工具和服务,如reCAPTCHA、Distil Networks、Akamai等。

请注意,这些反爬机制可能会影响合法的网络爬虫和数据采集。爬虫开发者需要遵守网站的规则和政策,确保他们的活动是合法的,并避免过度频繁地请求网站。

为什么采用了一些手段还是被识别到了?

在编写 web 爬虫时,一些人可能误以为只需轮流更换代理 IP 和模仿浏览器的 Headers,就能成功规避网站的监测机制。但实际上,还有一个不容忽视的因素,那就是“浏览器指纹”。浏览器指纹是一种独特的识别码,它不会因更换 IP 或 User-Agent 而改变,而且即使不使用模拟浏览器的方式,比如使用 Golang 或 Python,它们仍然会留下自己特有的指纹。更重要的是,这些指纹在每次请求时也是恒定不变的。

因此,无论你如何努力模拟请求,只要你的请求带有特定的浏览器指纹、频繁地访问网站,网站就有可能将你的行为识别并采取封锁措施。这是需要认真考虑和处理的问题,因为网站的监测系统会关注多个因素,包括 IP、Headers 和浏览器指纹。

下面来演示一下使用代理的情况:

import requests

proxy_url = "http://xxxxxx"
# 创建代理配置
proxies = {
    "http": proxy_url,
    "https": proxy_url,
}

url = 'https://tls.browserleaks.com/json'

resp = requests.get(url)
print(resp.json())

resp = requests.get(url, proxies=proxies)
print(resp.json())

# 输出
"""
{'hash': '8d9f7747675e24454cd9b7ed35c58707', 'fingerprint': '771,4866-4867-4865-49196-49200-49195-49199-52393-52392-159-158-52394-49327-49325-49326-49324-49188-49192-49187-49191-49162-49172-49161-49171-49315-49311-49314-49310-107-103-57-51-157-156-49313-49309-49312-49308-61-60-53-47-255,0-11-10-16-22-23-49-13-43-45-51-21,29-23-30-25-24,0-1-2', 'ciphers': 'TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_GCM_SHA256,ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-CHACHA20-POLY1305,ECDHE-RSA-CHACHA20-POLY1305,DHE-RSA-AES256-GCM-SHA384,DHE-RSA-AES128-GCM-SHA256,DHE-RSA-CHACHA20-POLY1305,ECDHE-ECDSA-AES256-CCM8,ECDHE-ECDSA-AES256-CCM,ECDHE-ECDSA-AES128-CCM8,ECDHE-ECDSA-AES128-CCM,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-RSA-AES256-CCM8,DHE-RSA-AES256-CCM,DHE-RSA-AES128-CCM8,DHE-RSA-AES128-CCM,DHE-RSA-AES256-SHA256,DHE-RSA-AES128-SHA256,DHE-RSA-AES256-SHA,DHE-RSA-AES128-SHA,AES256-GCM-SHA384,AES128-GCM-SHA256,AES256-CCM8,AES256-CCM,AES128-CCM8,AES128-CCM,AES256-SHA256,AES128-SHA256,AES256-SHA,AES128-SHA,TLS_EMPTY_RENEGOTIATION_INFO_SCSV', 'curves': '001D:0017:001E:0019:0018', 'protocol': 'TLSv1.3', 'user_agent': 'python-requests/2.31.0'}
{'hash': '8d9f7747675e24454cd9b7ed35c58707', 'fingerprint': '771,4866-4867-4865-49196-49200-49195-49199-52393-52392-159-158-52394-49327-49325-49326-49324-49188-49192-49187-49191-49162-49172-49161-49171-49315-49311-49314-49310-107-103-57-51-157-156-49313-49309-49312-49308-61-60-53-47-255,0-11-10-16-22-23-49-13-43-45-51-21,29-23-30-25-24,0-1-2', 'ciphers': 'TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,TLS_AES_128_GCM_SHA256,ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-CHACHA20-POLY1305,ECDHE-RSA-CHACHA20-POLY1305,DHE-RSA-AES256-GCM-SHA384,DHE-RSA-AES128-GCM-SHA256,DHE-RSA-CHACHA20-POLY1305,ECDHE-ECDSA-AES256-CCM8,ECDHE-ECDSA-AES256-CCM,ECDHE-ECDSA-AES128-CCM8,ECDHE-ECDSA-AES128-CCM,ECDHE-ECDSA-AES256-SHA384,ECDHE-RSA-AES256-SHA384,ECDHE-ECDSA-AES128-SHA256,ECDHE-RSA-AES128-SHA256,ECDHE-ECDSA-AES256-SHA,ECDHE-RSA-AES256-SHA,ECDHE-ECDSA-AES128-SHA,ECDHE-RSA-AES128-SHA,DHE-RSA-AES256-CCM8,DHE-RSA-AES256-CCM,DHE-RSA-AES128-CCM8,DHE-RSA-AES128-CCM,DHE-RSA-AES256-SHA256,DHE-RSA-AES128-SHA256,DHE-RSA-AES256-SHA,DHE-RSA-AES128-SHA,AES256-GCM-SHA384,AES128-GCM-SHA256,AES256-CCM8,AES256-CCM,AES128-CCM8,AES128-CCM,AES256-SHA256,AES128-SHA256,AES256-SHA,AES128-SHA,TLS_EMPTY_RENEGOTIATION_INFO_SCSV', 'curves': '001D:0017:001E:0019:0018', 'protocol': 'TLSv1.3', 'user_agent': 'python-requests/2.31.0'}
"""

神奇不,完全一致。
可以看到,虽然使用了隧道代理,每次请求的 IP 都是不一样的,但是这个网站返回的内容始终是一样的。所以如果这不是一个测试网站,而是一个加了这个检测机制的网站,那么它轻松就能把我给屏蔽了。

JA3(Just Another 3-Letter Acronym)是一种用于 SSL/TLS 客户端 “Hello” 消息的散列算法,用于创建 SSL/TLS 客户端的指纹。它的原理基于 SSL/TLS 握手协议,具体原理如下:

  1. 握手消息捕获:JA3 的原理是基于捕获 SSL/TLS 握手过程中客户端发送的 “Client Hello” 消息。“Client Hello” 消息是 SSL/TLS 握手的第一个消息,其中包含了客户端的配置信息,如支持的 TLS 版本、密码套件、扩展等。

  2. 提取关键信息:JA3 根据 “Client Hello” 消息中包含的关键信息来生成散列。这些关键信息通常包括:

    • TLS 版本:握手消息中指定的 TLS 协议版本(例如,TLS 1.2)。
    • 密码套件:客户端支持的加密算法和密钥交换算法。
    • 扩展:客户端支持的扩展,如服务器名指示(SNI)和应用层协议协商(ALPN)。
  3. 构建 JA3 字符串:JA3 根据上述提取的信息构建一个 JA3 字符串,该字符串将这些信息按照特定格式组合在一起。通常,JA3 字符串的格式为 “TLS版本,密码套件,扩展”,其中这些信息以逗号分隔。

  4. 计算散列:生成的 JA3 字符串被用作输入,通过哈希函数(通常使用 MD5 或 SHA-1)计算出 JA3 散列。这个散列值是 JA3 的唯一标识,用于表示 SSL/TLS 客户端的配置。

总之,JA3算法收集了SSL请求中的多个参数,包括但不限于SSL/TLS版本、密码套件数量、浏览器扩展列表、椭圆曲线等等。这些参数被综合组合成一个独特的指纹字符串。虽然你可能与一些人具有相同的密码套件数量、浏览器扩展数,甚至TLS版本号,但所有这些参数完全相同的人却相对较少。而在这小众人群中,他们同时访问同一网站的概率更低。因此,通过JA3算法,网站可以近似确定,在一段时间内,拥有相同指纹字符串的连续请求很可能来自同一个用户。

如何使用Python突破JA3限制?

requests

现在有很多网站,已经能够通过JA3或者其他指纹信息,来识别请求是不是Requests发起的。这种情况下,你无论怎么改Headers还是代理,都没有任何意义。

使用一个第三方库:

 pip install curl_cffi

代码如下:

from curl_cffi import requests as request_cffi

resp = request_cffi.get(url, impersonate="chrome110")
print(resp.json())
# 输出
"""
{'hash': '6cc593a36386ff801a9304392b84426d', 'fingerprint': '771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,10-13-51-65281-18-45-27-23-35-5-11-0-43-17513-16-21,29-23-24,0', 'ciphers': 'TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256,ECDHE-ECDSA-AES256-GCM-SHA384,ECDHE-RSA-AES256-GCM-SHA384,ECDHE-ECDSA-CHACHA20-POLY1305,ECDHE-RSA-CHACHA20-POLY1305,ECDHE-RSA-AES128-SHA,ECDHE-RSA-AES256-SHA,AES128-GCM-SHA256,AES256-GCM-SHA384,AES128-SHA,AES256-SHA', 'curves': '001D:0017:0018', 'protocol': 'TLSv1.3', 'user_agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36'}
"""

另外一个网站信息更全:

# https://tls.browserleaks.com/json
{'ja3_hash': '8d9f7747675e24454cd9b7ed35c58707', 'ja3_text': '771,4866-4867-4865-49196-49200-49195-49199-52393-52392-159-158-52394-49327-49325-49326-49324-49188-49192-49187-49191-49162-49172-49161-49171-49315-49311-49314-49310-107-103-57-51-157-156-49313-49309-49312-49308-61-60-53-47-255,0-11-10-16-22-23-49-13-43-45-51-21,29-23-30-25-24,0-1-2', 'ja3n_hash': 'a790a1e311289ac1543f411f6ffceddf', 'ja3n_text': '771,4866-4867-4865-49196-49200-49195-49199-52393-52392-159-158-52394-49327-49325-49326-49324-49188-49192-49187-49191-49162-49172-49161-49171-49315-49311-49314-49310-107-103-57-51-157-156-49313-49309-49312-49308-61-60-53-47-255,0-10-11-13-16-21-22-23-43-45-49-51,29-23-30-25-24,0-1-2', 'akamai_hash': '', 'akamai_text': ''}
{'ja3_hash': 'b3f3441b7ab96e4c7b503bcdf85e366f', 'ja3_text': '771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,13-16-17513-0-65281-51-43-10-18-27-23-45-5-35-11-21,29-23-24,0', 'ja3n_hash': 'aa56c057ad164ec4fdcb7a5a283be9fc', 'ja3n_text': '771,4865-4866-4867-49195-49199-49196-49200-52393-52392-49171-49172-156-157-47-53,0-5-10-11-13-16-18-21-23-27-35-43-45-51-17513-65281,29-23-24,0', 'akamai_hash': 'b7c68e9109d979eceed22f28cad1f034', 'akamai_text': '1:65536;2:0;3:1000;4:6291456;6:262144|15663105||m,a,s,p'}

asyncio

import asyncio
import random
import ssl

import aiohttp

ORIGIN_CIPHERS = ('ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
                  'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES')


class SSLFactory:
    def __init__(self):
        self.ciphers = ORIGIN_CIPHERS.split(":")

    def __call__(self, *args, **kwargs) -> ssl.SSLContext:
        random.shuffle(self.ciphers)
        ciphers = ":".join(self.ciphers)
        ciphers = ciphers + ":!aNULL:!eNULL:!MD5"

        context = ssl.create_default_context()
        context.set_ciphers(ciphers)
        return context


async def main():
    sslgen = SSLFactory()
    async with aiohttp.ClientSession() as session:
        for _ in range(3):
            async with session.get("https://tls.browserleaks.com/json", headers={}, ssl=sslgen()) as response:
                data = await response.json()
            print(data)


if __name__ == '__main__':
    asyncio.get_event_loop().run_until_complete(main())
# 输出
"""
{'ja3_hash': '8d40a03f3d26a49e8881f5aa25eafc69', 'ja3_text': '771,4866-4867-4865-49196-49200-52393-52392-49327-49325-49245-49249-49195-49199-49326-49324-49244-49248-49188-49192-49267-49271-49187-49191-49266-49270-49162-49172-49161-49171-163-159-49315-49311-162-158-49314-49310-107-106-103-64-57-56-51-50-157-49313-49309-156-49312-49308-61-60-53-47-52394-49239-49235-49238-49234-196-195-190-189-136-135-69-68-49233-49232-192-186-132-65-255,0-11-10-35-22-23-13-43-45-51-21,29-23-30-25-24,0-1-2', 'ja3n_hash': '15e37cb3a99d7d4a5e30d20a3caf465c', 'ja3n_text': '771,4866-4867-4865-49196-49200-52393-52392-49327-49325-49245-49249-49195-49199-49326-49324-49244-49248-49188-49192-49267-49271-49187-49191-49266-49270-49162-49172-49161-49171-163-159-49315-49311-162-158-49314-49310-107-106-103-64-57-56-51-50-157-49313-49309-156-49312-49308-61-60-53-47-52394-49239-49235-49238-49234-196-195-190-189-136-135-69-68-49233-49232-192-186-132-65-255,0-10-11-13-21-22-23-35-43-45-51,29-23-30-25-24,0-1-2', 'akamai_hash': '', 'akamai_text': ''}
{'ja3_hash': 'd162146d9c2773d7dd831f9079e31f1a', 'ja3_text': '771,4866-4867-4865-49196-49200-49195-49199-157-49313-49309-156-49312-49308-61-60-53-47-49233-49232-192-186-132-65-163-159-49315-49311-162-158-49314-49310-107-106-103-64-57-56-51-50-49327-49325-49188-49192-49162-49172-52393-52392-49245-49249-49326-49324-49244-49248-49267-49271-49187-49191-49266-49270-49161-49171-52394-49239-49235-49238-49234-196-195-190-189-136-135-69-68-255,0-11-10-35-22-23-13-43-45-51-21,29-23-30-25-24,0-1-2', 'ja3n_hash': '7f71e78e23f68358d46d75a926e9ab4f', 'ja3n_text': '771,4866-4867-4865-49196-49200-49195-49199-157-49313-49309-156-49312-49308-61-60-53-47-49233-49232-192-186-132-65-163-159-49315-49311-162-158-49314-49310-107-106-103-64-57-56-51-50-49327-49325-49188-49192-49162-49172-52393-52392-49245-49249-49326-49324-49244-49248-49267-49271-49187-49191-49266-49270-49161-49171-52394-49239-49235-49238-49234-196-195-190-189-136-135-69-68-255,0-10-11-13-21-22-23-35-43-45-51,29-23-30-25-24,0-1-2', 'akamai_hash': '', 'akamai_text': ''}
{'ja3_hash': '3d09497efab600bd2de80c795969f777', 'ja3_text': '771,4866-4867-4865-163-159-49315-49311-107-106-57-56-157-49313-49309-156-49312-49308-61-60-53-47-49196-49200-49327-49325-49188-49192-49162-49172-49233-49232-192-186-132-65-49195-49199-49326-49324-49187-49191-49161-49171-162-158-52394-49239-49235-49314-49310-49238-49234-196-195-103-64-190-189-136-135-51-50-69-68-52393-52392-49245-49249-49244-49248-49267-49271-49266-49270-255,0-11-10-35-22-23-13-43-45-51-21,29-23-30-25-24,0-1-2', 'ja3n_hash': 'f18f3a028f49d706daa16a9ea2e8b7d1', 'ja3n_text': '771,4866-4867-4865-163-159-49315-49311-107-106-57-56-157-49313-49309-156-49312-49308-61-60-53-47-49196-49200-49327-49325-49188-49192-49162-49172-49233-49232-192-186-132-65-49195-49199-49326-49324-49187-49191-49161-49171-162-158-52394-49239-49235-49314-49310-49238-49234-196-195-103-64-190-189-136-135-51-50-69-68-52393-52392-49245-49249-49244-49248-49267-49271-49266-49270-255,0-10-11-13-21-22-23-35-43-45-51,29-23-30-25-24,0-1-2', 'akamai_hash': '', 'akamai_text': ''}
"""

可以看到输出了3次都不一样。
为什么你的爬虫能被识别到?_第1张图片

你可能感兴趣的:(爬虫总结,爬虫)