寫作背景
自上一篇 Node 爬蟲心得來,有爬蟲自然也會有反爬蟲,爬蟲這事就如道高一尺魔高一丈。
常用的有幾種手段
- 針對請求頭處理
- 針對 IP 限頻
- JS 渲染頁面
- 驗證碼
針對請求頭處理
- Referer: https://www.mzitu.com/
- User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36
Referer 最常用於防盜鏈,但若有需要,也可以去 Nginx 配置只允許自身網站的域名訪問。
User-Agent 這個就常用了,像是搜索引擎的機器人常常是帶着 spider、robot 等說明,而一些拙劣的爬蟲腳本,連這個也不帶。比方說去請求妹子圖網,會直接被 403 拒絕就是這種防御
$ curl https://www.mzitu.com/230184
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx</center>
</body>
</html>
這時候加上 UA 就搞定了
$ curl --location --request GET 'https://www.mzitu.com/230184' \
> --header 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36'
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>性感妹子 - 妹子圖</title>
<meta name="keywords" content="" />
<meta name="description" content="妹子圖每日分享最新最全的高清性感美女圖片" />
<script type="text/javascript" src="https://ip.ws.126.net/ipquery?"></script>
<script type="text/javascript" src="https://www.mzitu.com/static/mb/u.js?0211"></script>
<link rel="canonical" href="https://www.mzitu.com/230184" />
<link rel="alternate" media="only screen and(max-width: 640px)" href="https://m.mzitu.com/230184" >
<meta name="mobile-agent" content="format=html5;url=https://m.mzitu.com/230184" />
<meta name="applicable-device" content="pc">
......
請求頭的防御手段,反爬蟲手段肯定得加上,然太容易被繞過,篡改請求頭成本太低。
針對 IP 限頻
這個比較難操控,本人以前用一台機器爬取時,就遭到過被封 IP 的問題。
防御方可以對 IP 的請求資源限速,判定在若干時間內流量超過某個閾值就攔截此 IP 的請求一段時間,若此有關聯的用戶賬號的話,也可以對賬號進行封禁。
對 IP 處理,如果閾值調低點,可能會誤傷到用戶,因為總有許多用戶用的一個網絡。並且對於攻擊者,想繞過出現了一些成本,但做起來卻也沒那么難,可以使用代理 IP 池,用多個 IP 去抓取。
JS 渲染頁面
大多數的爬蟲請求它都只是抓去 HTML 並解析獲取想要的資源,極少數會去執行目標網站的 JS 腳本。基於這點,就有一些防御策略可以做,這些策略都可以被歸為 JS 來渲染頁面,讓攻擊者拿到的 HTML 並非真正的用戶能看到的內容。
比如目前最常見的是單頁應用,舉個例子,除了拿到一堆腳本,其他啥也拿不到。
$ curl https://zhiyun.souche.com/welcome
<!DOCTYPE html><html><head><meta charset=utf-8><link href=/public/favicon.ico rel=mask-icon color=#ff571a></head><body><div id=root></div><div style=display:none><a href=https://www.dasouche.com/zh/ rel=nofollow>大搜車</a> <a href=https://www.souche.com/index>大搜車家選</a> <a href=https://www.chehang168.com/ rel=nofollow>車行168</a> <a href=https://www.tangeche.com/ rel=nofollow>彈個車</a> <a href=https://www.24che.com/ >24車汽車資訊</a> <a href=https://www.cheyipai.com/ rel=nofollow>車易拍</a></div><script>(function () {
var src = "https://jspassport.ssl.qhimg.com/11.0.1.js?d182b3f28525f2db83acfaaf6e696dba";
document.write('<script src="' + src + '" id="sozz"><\/script>');
})();
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?4f39064ba41b08e411d9c9f60a3303ea";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();</script><script>(function () {
var bp = document.createElement('script');
var curProtocol = window.location.protocol.split(':')[0];
if (curProtocol === 'https') {
bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'';
}
else {
bp.src = 'http://push.zhanzhang.baidu.com/push.js'';
}
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(bp, s);
})();</script><script src=https://assets.souche.com/projects/bdc_group/disp-fe-wf/js/chunk-vendors.69b2172d.js></script><script src=https://assets.souche.com/projects/bdc_group/disp-fe-wf/js/app.75e4cd5b.js></script></body></html>
插嘴說一句,單頁應用天然帶這個問題,這也導致 SEO 困難的麻煩,不過這個處理起來簡單。可以抽離一個服務出來,專門處理 user-agent 為 spider 或者 robot 的搜索引擎機器人,給他們看另外一個靜態的頁面就好了,當然你可以做一些處理屏蔽掉數字之類的可能敏感的數據再輸出。
還有一個典型解法是使用 font 做字體反爬,把 123 和一二三之類的常用字符放入自定義的字體庫中,爬蟲收集到的是“獵豹以時速公里/小時的速度奔跑在非洲的大草原上”,關鍵的那個時速因為用的是自定義字體,而使得爬蟲爬頁面是無法直接得出結果的。
對此有一篇文章講的不錯 反爬終極方案總結—字體反爬,下圖出自這篇文章。
當然還有故意喂爬蟲方假數據的做法,筆者就遇到過,爬下來的 HTML 解析得某商品價格為 1234 元,然而真的用瀏覽器訪問這個頁面得到的商品價格數據明明是 5678 元。這其實是 HTML 里寫着 1234,但 JS 里有着某個變量,執行后會計算重寫那個價格。
這一層也是花樣最多的地方,但谷歌出的無頭瀏覽器是個大殺器,參照下Headless Chrome
驗證碼
超頻的訪問可以彈出驗證碼輸入,要求輸入,若來者沒有輸入那自然就會被判定成機器人了。
通常驗證碼是一張圖片,文本自然抓不出是什么,這一度難倒了大多數的攻擊方,直到 OCR 的出現,JS 已經有許多開源的庫了,就如 tesseract,只要調用一次 API,就能破解簡單的驗證碼。
圍繞驗證碼的攻防也是一個巨大的話題。防御方發覺驗證碼輕松被破,那么就要上難度更高的驗證碼,可以是更扭曲變形的文字,加入干擾線,混淆背景和文字的圖片。越來越難的驗證碼,機器人自然很難識別,但是人類也是不堪其苦,筆者見到過最變態的驗證碼是 NGA 論壇的登陸驗證碼。
NGA 似乎調整過了,原先的更加變態。它讓筆者每次都得定睛看個好幾秒才能認出,而且還經常可能輸錯。可能會換成滑動的驗證碼,但其實滑動驗證碼破解起來並沒有復雜的圖形驗證碼困難。
攻擊方發覺單單的 OCR 已經無法拿取到圖片內容了,新的玩法就產生了,上機器學習+OCR的模式了,或者打碼平台,但這里不多說。
結語
不計成本的說,防方最后還是搞不過攻方。雖然如此,我們也可以極力提升攻擊方的成本,攔住那些低級的爬蟲腳本。