python模擬TLS指紋實(shí)現(xiàn)反爬取
相信大家在做爬蟲(chóng)的時(shí)候,都有過(guò)被反爬的經(jīng)歷,一旦網(wǎng)站識(shí)別是爬蟲(chóng),就會(huì)拒絕請(qǐng)求。反爬機(jī)制有很多,最常見(jiàn)的便是通過(guò)請(qǐng)求頭里的 User-Agent,舉個(gè)例子。
import requests
import httpx
response = requests.get("http://www.baidu.com")
print(response.request.headers["User-Agent"])
"""
python-requests/2.28.0
"""
response = httpx.get("http://www.baidu.com")
print(response.request.headers["User-Agent"])
"""
python-httpx/0.23.3
"""如果 User-Agent 不符合瀏覽器的格式,那么一定不是瀏覽器發(fā)出的,于是網(wǎng)站便可認(rèn)定這屬于爬蟲(chóng)。當(dāng)然通過(guò) User-Agent 識(shí)別屬于最低級(jí)的方式,因?yàn)榕老x(chóng)可以偽造自己的 User-Agent。
import requests
import httpx
response = requests.get("http://www.baidu.com",
headers={"User-Agent": "Chrome User-Agent"})
print(response.request.headers["User-Agent"])
"""
Chrome User-Agent
"""
response = httpx.get("http://www.baidu.com",
headers={"User-Agent": "IE User-Agent"})
print(response.request.headers["User-Agent"])
"""
IE User-Agent
"""除了 User-Agent 之外,還可以通過(guò)請(qǐng)求頭中的 Refer 字段判斷是否為爬蟲(chóng)。比如你在 A 頁(yè)面點(diǎn)擊某個(gè)標(biāo)簽跳轉(zhuǎn)到 B 頁(yè)面,那么 Refer 就是 A 頁(yè)面的地址。如果你直接訪問(wèn)的 B 頁(yè)面,那么 Refer 就是空。
如果 B 頁(yè)面必須通過(guò)點(diǎn)擊 A 頁(yè)面的標(biāo)簽才能跳轉(zhuǎn),那么網(wǎng)站便可以通過(guò) Refer 來(lái)判斷是否為爬蟲(chóng)。
當(dāng)然啦,反爬機(jī)制還有很多,不同網(wǎng)站使用的策略不一樣。但現(xiàn)在大部分的網(wǎng)站都使用了 HTTPS,在建立 HTTPS 連接的時(shí)候要先進(jìn)行 TLS 握手,在握手的過(guò)程中會(huì)協(xié)商加密算法、交換密鑰和驗(yàn)證雙方的身份。
而將 TLS 握手產(chǎn)生的信息收集起來(lái),并使用 JA3 算法生成一個(gè)哈希值,便得到了 TLS 指紋,基于該指紋可以標(biāo)識(shí)、分類和跟蹤使用特定 TLS 配置的客戶端。
因此通過(guò) JA3 哈希生成指紋便可以確定哪些是惡意流量,從而將其拒絕掉。換句話說(shuō),通過(guò) TLS 指紋可以識(shí)別哪些是瀏覽器發(fā)出的正常請(qǐng)求,哪些是爬蟲(chóng)。
那么 TLS 指紋如何查看呢?可以通過(guò)以下幾個(gè)網(wǎng)站。
https://tls.browserleaks.com/json

這是我基于瀏覽器訪問(wèn)的,它的字段都不是空,我們使用 Python 訪問(wèn)一下。
import requests
import httpx
user_agent = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) " \
"AppleWebKit/537.36 (KHTML, like Gecko) " \
"Chrome/118.0.0.0 Safari/537.36"
response = requests.get("https://tls.browserleaks.com/json",
headers={"User-Agent": user_agent})
print(response.json())
"""
{'ja3_hash': '8d9f7747675e24454cd9b7ed35c58707',
'ja3_text': '771,4866-4867-4865-49196-49200-49195...',
'ja3n_hash': 'a790a1e311289ac1543f411f6ffceddf',
'ja3n_text': '771,4866-4867-4865-49196-49200-49195...',
'akamai_hash': '',
'akamai_text': ''}
"""
response = httpx.get("https://tls.browserleaks.com/json",
headers={"User-Agent": user_agent})
print(response.json())
"""
{'ja3_hash': '76f01df912881a05228c70b7f61bcbaa',
'ja3_text': '771,4866-4867-4865-49196-49200-49195...',
'ja3n_hash': '80a9bea1db8ce3a18047816ba1ee07e5',
'ja3n_text': '771,4866-4867-4865-49196-49200-49195...',
'akamai_hash': '',
'akamai_text': ''}
"""如果使用爬蟲(chóng),那么多次請(qǐng)求時(shí)的 ja3_hash 是不變的,并且 akamai_hash 和 akamai_text 均是空,基于該特征很容易識(shí)別是不是爬蟲(chóng)。即使我們更換代理,設(shè)置請(qǐng)求頭,也無(wú)法改變這一點(diǎn)。
于是為了完美模擬瀏覽器,國(guó)外大佬開(kāi)發(fā)出了 curl-impersonate,將 curl 底層依賴的庫(kù)全部換成了瀏覽器使用的庫(kù),并且版本也是一致的,這樣生成的指紋就和瀏覽器完全一樣了。
而 curl_cffi 正是 curl-impersonate 的 Python binding,我們直接使用 pip 安裝即可。
# 和 requests 接口是一致的
from curl_cffi import requests
# 但是多了一個(gè) impersonate 參數(shù),用于指定模擬哪個(gè)瀏覽器
response = requests.get("https://tls.browserleaks.com/json",
impersonate="chrome101")
print(response.json())
"""
{'ja3_hash': 'cd08e31494f9531f560d64c695473da9',
'ja3_text': '771,4865-4866-4867-49195-49199-49196...',
'ja3n_hash': 'aa56c057ad164ec4fdcb7a5a283be9fc',
'ja3n_text': '771,4865-4866-4867-49195-49199-49196...',
'akamai_hash': '8a32ff5cb625ed4ae2d092e76beb6d99',
'akamai_text': '1:65536;3:1000;4:6291456;6:262144|15663105||m,a,s,p'}
"""
# 當(dāng)然也可以先創(chuàng)建 session
session = requests.Session()
# 然后基于 session 發(fā)請(qǐng)求總共支持如下版本的瀏覽器:

我們選擇 chrome110 即可,然后 curl_cffi 還支持異步發(fā)請(qǐng)求,可以和 asyncio 輕松集成。
import asyncio
from curl_cffi import requests
async def send_req():
async with requests.AsyncSession() as session:
response = await session.get(
"https://tls.browserleaks.com/json",
impersonate="chrome101"
)
print(response.json())
asyncio.run(send_req())
"""
{'ja3_hash': 'cd08e31494f9531f560d64c695473da9',
'ja3_text': '771,4865-4866-4867-49195-49199-49196...',
'ja3n_hash': 'aa56c057ad164ec4fdcb7a5a283be9fc',
'ja3n_text': '771,4865-4866-4867-49195-49199-49196...',
'akamai_hash': '8a32ff5cb625ed4ae2d092e76beb6d99',
'akamai_text': '1:65536;3:1000;4:6291456;6:262144|15663105||m,a,s,p'}
"""由于指紋特征很難更改,因此通過(guò)指紋可以防御一大批爬蟲(chóng),而通過(guò) curl_cffi 模擬指紋則可以繞過(guò)這道防線。
到此這篇關(guān)于python模擬TLS指紋實(shí)現(xiàn)反爬取的文章就介紹到這了,更多相關(guān)python模擬TLS指紋內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python multiprocessing模塊中的Pipe管道使用實(shí)例
這篇文章主要介紹了Python multiprocessing模塊中的Pipe管道使用實(shí)例,本文直接給出使用實(shí)例,需要的朋友可以參考下2015-04-04
python調(diào)用tcpdump抓包過(guò)濾的方法
這篇文章主要為大家詳細(xì)介紹了python調(diào)用tcpdump抓包過(guò)濾的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-07-07
python創(chuàng)建ArcGIS shape文件的實(shí)現(xiàn)
今天小編就為大家分享一篇python創(chuàng)建ArcGIS shape文件的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-12-12
Jetson?NX?配置?pytorch的問(wèn)題及解決方法
這篇文章主要介紹了Jetson?NX?配置?pytorch的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-03-03
Python中數(shù)組,列表:冒號(hào)的靈活用法介紹(np數(shù)組,列表倒序)
下面小編就為大家分享一篇Python中數(shù)組,列表:冒號(hào)的靈活用法介紹(np數(shù)組,列表倒序),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-04-04
Python2.7基于淘寶接口獲取IP地址所在地理位置的方法【測(cè)試可用】
這篇文章主要介紹了Python2.7基于淘寶接口獲取IP地址所在地理位置的方法,涉及Python調(diào)用淘寶IP庫(kù)接口進(jìn)行IP查詢的簡(jiǎn)單操作技巧,需要的朋友可以參考下2017-06-06
Python實(shí)現(xiàn)的簡(jiǎn)單模板引擎功能示例
這篇文章主要介紹了Python實(shí)現(xiàn)的簡(jiǎn)單模板引擎功能,結(jié)合具體實(shí)例形式分析了Python模版引擎的定義與使用方法,需要的朋友可以參考下2017-09-09
python使用for循環(huán)計(jì)算0-100的整數(shù)的和方法
今天小編就為大家分享一篇python使用for循環(huán)計(jì)算0-100的整數(shù)的和方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-02-02
解決pytorch load huge dataset(大數(shù)據(jù)加載)
這篇文章主要介紹了解決pytorch load huge dataset(大數(shù)據(jù)加載)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-05-05
macos搭建python3虛擬環(huán)境全過(guò)程
macOS搭建Python3虛擬環(huán)境,可以避免與系統(tǒng)自帶的Python2.7兼容性問(wèn)題,通過(guò)Pycharm創(chuàng)建虛擬環(huán)境,工程在Pycharm里運(yùn)行正常,但命令行需要手動(dòng)激活虛擬環(huán)境,手動(dòng)創(chuàng)建虛擬環(huán)境時(shí),需要執(zhí)行激活命令2025-12-12

