反爬蟲策略,表面上看似乎跟WEB系統優化沒有關系,經過分析,發現該策略是可以歸到WEB性能優化的系列之中。
通過分析apache日志發現,某系統40%的帶寬和服務器資源都消耗在爬蟲上,如果除去10%-15%搜索引擎的爬蟲,做好反爬蟲策略,能節省20%-25%的資源,其實是變向優化了web系統。
一、爬蟲請求與正常用戶請求的區別
爬蟲請求是類似httpClient的機制或curl,wget的命令,用戶請求一般走瀏覽器。
區別:爬蟲請求一般不會執行頁面里的異步JavaScript操作,而用戶請求則執行Jquery提供的異步JavaScript操作,具體如下:
<script type="text/javascript">
$(document).ready(function(){
alertFunTest();
}
function alertFunTest() {
alert(“異步”);
}
</script >
代碼alert(“異步”)一般不會被爬蟲請求執行。
二、分析系統有多少爬蟲行為
某系統某天的日志分析如下:
cat access20110421.log | wc -l
2156293
cat page_access20110421.log | sort | uniq -c | sort -nr | head -n20
441421 /讀帖頁 20.4%
374274 /彈出框 17.3%
266984 /帖子點擊數 12.3%
213522 /讀取支持數和反支持數 9.9%
207269 /其它 9.6%
203567 /帖子列表頁 9.4%
185138 /刷新功能 8.5%
164884 /帖子列表點擊 7.6%
如上所示,帖子點擊數請求是不會被爬蟲執行的。
(讀帖頁數-帖子點擊數)/ 讀帖頁數=爬蟲執行讀帖頁次數的比例
(441421 - 266984 )/ 441421=39.6%
結論:近40% 帖子的讀取操作是爬蟲行為,讀帖占系統85%以上的操作,也就是說近1/3以上的網絡和服務器資源在為爬蟲服務。
三、請求在不同層面對應的反抓策略
(一)防火牆層面
通過netstat80端口的tcp連接量判斷IP是否非法。
WEB系統都是走http協議跟WEB容器連通的,每次請求至少會產生一次客戶端與服務器的tcp連接。通過netstat命令,就可以查看到當前同時連接服務器所對應的IP以及連接量。
命令 /bin/netstat -nat -n | grep 80 一般都幾百或幾千個。
同一個IP對應的連接數超過我們觀察到的一個閥值時,就可判斷為非正常的用戶請求。閥值設定至關重要,大型網吧或同一個學校、公司出來的IP也可能會被誤判為非法請求。
此策略我寫了兩個定時腳本去,一個定時封IP( tcpForbidCmd.sh ),一個定時釋放IP ( tcpReleaseCmd.sh ),分別是每隔5分鍾和40分鍾各執行一次
tcpForbidCmd.sh參考代碼如下:
#!/bin/sh
file=/home/songlin.lu/shell/log/forbid-ips-tmp.log
myIps=/home/songlin.lu/shell/log/noforbid_ips.log
today=`date +'%Y%m%d'`
logForbidIp=/home/songlin.lu/shell/log/forbid-iptables-logs-$today.log
netstatFile=/home/songlin.lu/shell/log/forbid-netstat-nat-tmp.log
/bin/netstat -nat -n > $netstatFile
nowDate=`date +'%Y-%m-%d %H:%M'`
/bin/awk -F: '/tcp/{a[$(NF-1)]++}END{for(i in a)if(a[i]>90)print i}' $netstatFile > $file
drop_ip=`cat $file |awk '{print $2}'`
for iptables_ip in $drop_ip
do
if [ $iptables_ip != $0 ] && [ -z "` iptables -L -n | grep DROP | awk '{print$4}'|grep $iptables_ip`" ] && [ -z "` cat $myIps |grep $iptables_ip`"];then
/sbin/iptables -A INPUT -s $iptables_ip -p tcp --dport 80 -j DROP
echo $iptables_ip >> /home/songlin.lu/shell/log/release-forbid-logs-tmp.log
echo '--------------------'$nowDate'----'$iptables_ip >> $logForbidIp
fi
done
文件/home/songlin.lu/shell/log/noforbid_ips.log為白名單列表
tcpReleaseCmd.sh參考代碼如下:
#!/bin/sh
today=`date +'%Y%m%d'`
logReleaseIpLog=/home/songlin.lu/shell/log/release-iptables-log-$today.log
iptables=/home/songlin.lu/shell/log/release-iptables-save-tmp.log
tmpFile=/home/songlin.lu/shell/log/release-forbid-logs-tmp.log
/sbin/iptables-save > $iptables
drop_ips=`cat $tmpFile`
nowDate=`date +'%Y-%m-%d %H:%M'`
for iptables_ip1 in $drop_ips
do
if [ ! -z "`cat $iptables |awk /DROP/'{print $4}' | grep $iptables_ip1`" ]
then
/sbin/iptables -D INPUT -s $iptables_ip1 -p tcp --dport 80 -j DROP
echo '--------------------'$nowDate'----'$iptables_ip1 >> $logReleaseIpLog
fi
done
> $tmpFile
此策略相當於給我們的系統設定了門檻,類似公路交通系統內,某馬路設定限高4米欄桿,高於4米的車不能在此通行。該策略能預防惡意的或新手寫的請求頻率不規則的爬蟲。
(二)WEB服務器容器層面
a.User-Agent判斷 b. connlimit模塊判斷
每個爬蟲會聲明自己的User-Agent信息,我們可以通過判斷爬蟲的User-Agent信息來識別,具體查看相關文檔
Apache作connlimit需要mod_limitipconn來實現,一般需要手動編譯。
編輯httpd.conf文件,添加如下配置
ExtendedStatus On
LoadModule limitipconn_module modules/mod_limitipconn.so
< IfModule mod_limitipconn.c >
< Location / > # 所有虛擬主機的/目錄
MaxConnPerIP 20 # 每IP只允許20個並發連接
NoIPLimit image/* # 對圖片不做IP限制
< /Location>
< /IfModule>
Nginx作connlimit,限制ip並發數,比較簡單
添加limit_conn 這個變量可以在http, server, location使用 如:limit_conn one 10;
(三)日志層面
通過日志和網站流量分析識別爬蟲
用awstats分析服務器日志,用流量統計工具,如Google Analytics來統計IP對應的流量記錄,流量統計在網頁里面嵌入一段js代碼。把統計結果和流量統計系統記錄的IP地址進行對比,排除真實用戶訪問IP,再排除我們希望放行的網頁爬蟲,比如Google,百度,youdao爬蟲等。最后的分析結果就得到爬蟲的IP地址。
(四)程序層面
時時反爬蟲過濾機制
實現起來也比較簡單,我們可以用memcached或本地內存來做訪問計數器,在緩存過期之前的時間段內(如3分鍾),每個IP訪問一次,計數器加1,緩存的KEY包括IP,通過計數器得到的值,判斷超過一個閥值,這個IP很可能有問題,那么就可以返回一個驗證碼頁面,要求用戶填寫驗證碼。如果是爬蟲的話,當然不可能填寫驗證碼,就被拒掉了,保護了后端的資源。
閥值的設定也是很重要的,不同的系統不一樣。
我們將這個過濾機制改進一下,將更加准確。 即我們在網頁的最下面添加一個JS的異步請求,此異步請求用來減計數器的值,進頁面時對IP進行加值,出頁面時減值,生成一個差值。 根據我們之前的分析,爬蟲不會執行異步JS減值請求。 這樣可以從生成的值的大小上判斷這個IP是否為爬蟲。
程序邏輯如下圖所示:
[文章作者:狂奔的鹿(陸松林)本文版本:v1.0 轉載請注明原文鏈接:http://www.cnblogs.com/dynamiclu/]