啊~嗯~用力~啊~啊~~动态图_gogo亚洲肉体艺术照片9090_公厕偷拍直男撒尿全集_女攻男受肉文

全國服務熱線:400-080-4418

您現(xiàn)在的位置是:首頁 > 新聞資訊 > 網(wǎng)站建設常識

互聯(lián)網(wǎng)網(wǎng)站的反爬蟲策略淺析2009/9/11 8:35:52 瀏覽:79

因為搜索引擎的流行,網(wǎng)絡爬蟲已經(jīng)成了很普及網(wǎng)絡技術,除了專門做搜索的Google,Yahoo,微軟,百度以外,幾乎每個大型門戶網(wǎng)站都有自己的搜索引擎,大大小小叫得出來名字得就幾十種,還有各種不知名的幾千幾萬種,對于一個內容型驅動的網(wǎng)站來說,受到網(wǎng)絡爬蟲的光顧是不可避免的。

一些智能的搜索引擎爬蟲的爬取頻率比較合理,對網(wǎng)站資源消耗比較少,但是很多糟糕的網(wǎng)絡爬蟲,對網(wǎng)頁爬取能力很差,經(jīng)常并發(fā)幾十上百個請求循環(huán)重復抓取,這種爬蟲對中小型網(wǎng)站往往是毀滅性打擊,特別是一些缺乏爬蟲編寫經(jīng)驗的程序員寫出來的爬蟲破壞力極強。曾經(jīng)有一次我在JavaEye的日志里面發(fā)現(xiàn)一個User-Agent是Java的爬蟲一天之內爬取了將近100萬次動態(tài)請求。這是一個用JDK標準類庫編寫的簡單爬取網(wǎng)頁程序,由于JavaEye網(wǎng)站內部鏈接構成了回環(huán)導致程序陷入了死循環(huán)。對于JavaEye這種百萬PV級別的網(wǎng)站來說,這種爬蟲造成的訪問壓力會非常大,會導致網(wǎng)站訪問速度緩慢,甚至無法訪問。

此外,相當數(shù)量的的網(wǎng)頁爬蟲目的是盜取目標網(wǎng)站的內容。比方說JavaEye網(wǎng)站就曾經(jīng)被兩個競爭對手網(wǎng)站爬取論壇帖子,然后在自己的論壇里面用機器人發(fā)帖,因此這種爬蟲不僅僅影響網(wǎng)站訪問速度,而且侵犯了網(wǎng)站的版權。

對于一個原創(chuàng)內容豐富,URL結構合理易于爬取的網(wǎng)站來說,簡直就是各種爬蟲的盤中大餐,很多網(wǎng)站的訪問流量構成當中,爬蟲帶來的流量要遠遠超過真實用戶訪問流量,甚至爬蟲流量要高出真實流量一個數(shù)量級。像JavaEye網(wǎng)站雖然設置了相當嚴格的反爬蟲策略,但是網(wǎng)站處理的動態(tài)請求數(shù)量仍然是真實用戶訪問流量的2倍。可以肯定的說,當今互聯(lián)網(wǎng)的網(wǎng)絡流量至少有2/3的流量爬蟲帶來的。因此反爬蟲是一個值得網(wǎng)站長期探索和解決的問題。

一、手工識別和拒絕爬蟲的訪問

有相當多的爬蟲對網(wǎng)站會造成非常高的負載,因此識別爬蟲的來源IP是很容易的事情。簡單的辦法就是用netstat檢查80端口的連接:

netstat -nt | grep youhostip:80 | awk '{print $5}' | awk -F":" '{print $1}'| sort | uniq -c | sort -r -n   


這行shell可以按照80端口連接數(shù)量對來源IP進行排序,這樣可以直觀的判斷出來網(wǎng)頁爬蟲。一般來說爬蟲的并發(fā)連接非常高。

如果使用lighttpd做Web Server,那么就更簡單了。lighttpd的mod_status提供了非常直觀的并發(fā)連接的信息,包括每個連接的來源IP,訪問的URL,連接狀態(tài)和連接時間等信息,只要檢查那些處于handle-request狀態(tài)的高并發(fā)IP就可以很快確定爬蟲的來源IP了。

拒絕爬蟲請求既可以通過內核防火墻來拒絕,也可以在web server拒絕,比方說用iptables拒絕:

iptables -A INPUT -i eth0 -j DROP -p tcp --dport 80 -s 84.80.46.0/24   


直接封鎖爬蟲所在的C網(wǎng)段地址。這是因為一般爬蟲都是運行在托管機房里面,可能在一個C段里面的多臺服務器上面都有爬蟲,而這個C段不可能是用戶寬帶上網(wǎng),封鎖C段可以很大程度上解決問題。

有些人提出一種腦殘的觀點,說我要懲罰這些爬蟲。我專門在網(wǎng)頁里面設計動態(tài)循環(huán)鏈接頁面,讓爬蟲掉進陷阱,死循環(huán)爬不出來,其實根本用不著設置陷阱,弱智爬蟲對正常網(wǎng)頁自己就爬不出來,這樣做多此一舉不說,而且會讓真正的搜索引擎降低你的網(wǎng)頁排名。而且運行一個爬蟲根本不消耗什么機器資源,相反,真正寶貴的是你的服務器CPU資源和服務器帶寬,簡單的拒絕掉爬蟲的請求是反爬蟲有效的策略。

二、通過識別爬蟲的User-Agent信息來拒絕爬蟲

有很多爬蟲并不會以很高的并發(fā)連接爬取,一般不容易暴露自己;有些爬蟲的來源IP分布很廣,很難簡單的通過封鎖IP段地址來解決問題;另外還有很多各種各樣的小爬蟲,它們在嘗試Google以外創(chuàng)新的搜索方式,每個爬蟲每天爬取幾萬的網(wǎng)頁,幾十個爬蟲加起來每天就能消耗掉上百萬動態(tài)請求的資源,由于每個小爬蟲單獨的爬取量都很低,所以你很難把它從每天海量的訪問IP地址當中把它準確的挖出來。[Page]

這種情況下我們可以通過爬蟲的User-Agent信息來識別。每個爬蟲在爬取網(wǎng)頁的時候,會聲明自己的User-Agent信息,因此我們就可以通過記錄和分析User-Agent信息來挖掘和封鎖爬蟲。我們需要記錄每個請求的User-Agent信息,對于Rails來說我們可以簡單的在app/controllers/application.rb里面添加一個全局的before_filter,來記錄每個請求的User-Agent信息:

Ruby代碼

logger.info "HTTP_USER_AGENT #{request.env["HTTP_USER_AGENT"]}"  


然后統(tǒng)計每天的production.log,抽取User-Agent信息,找出訪問量大的那些User-Agent。要注意的是我們只關注那些爬蟲的User-Agent信息,而不是真正瀏覽器User-Agent,所以還要排除掉瀏覽器User-Agent,要做到這一點僅僅需要一行shell:

Ruby代碼

grep HTTP_USER_AGENT production.log | grep -v -E 'MSIE|Firefox|Chrome|Opera|Safari|Gecko' | sort | uniq -c | sort -r -n | head -n 100 > bot.log 


統(tǒng)計結果類似這樣:

C代碼

57335 HTTP_USER_AGENT Baiduspider+(+http://www.baidu.com/search/spider.htm)   
56639 HTTP_USER_AGENT Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)   
42610 HTTP_USER_AGENT Mediapartners-Google   
19131 HTTP_USER_AGENT msnbot/2.0b (+http://search.msn.com/msnbot.htm)  
 


從日志就可以直觀的看出每個爬蟲的請求次數(shù)。要根據(jù)User-Agent信息來封鎖爬蟲是件很容易的事情,lighttpd配置如下:

C代碼

$HTTP["useragent"] =~ "qihoobot|^Java|Commons-HttpClient|Wget|^PHP|Ruby|Python" {   
  url.rewrite = ( "^/(.*)" => "/crawler.html" )   
}  
 


使用這種方式來封鎖爬蟲雖然簡單但是非常有效,除了封鎖特定的爬蟲,還可以封鎖常用的編程語言和HTTP類庫的User-Agent信息,這樣就可以避免很多無謂的程序員用來練手的爬蟲程序對網(wǎng)站的騷擾。

還有一種比較常見的情況,就是某個搜索引擎的爬蟲對網(wǎng)站爬取頻率過高,但是搜索引擎給網(wǎng)站帶來了很多流量,我們并不希望簡單的封鎖爬蟲,僅僅是希望降低爬蟲的請求頻率,減輕爬蟲對網(wǎng)站造成的負載,那么我們可以這樣做:

C代碼

$HTTP["user-agent"] =~ "Baiduspider+" {   
    connection.delay-seconds = 10   
}
 


對百度的爬蟲請求延遲10秒鐘再進行處理,這樣就可以有效降低爬蟲對網(wǎng)站的負載了。

三、通過網(wǎng)站流量統(tǒng)計系統(tǒng)和日志分析來識別爬蟲

有些爬蟲喜歡修改User-Agent信息來偽裝自己,把自己偽裝成一個真實瀏覽器的User-Agent信息,讓你無法有效的識別。這種情況下我們可以通過網(wǎng)站流量系統(tǒng)記錄的真實用戶訪問IP來進行識別。

主流的網(wǎng)站流量統(tǒng)計系統(tǒng)不外乎兩種實現(xiàn)策略:一種策略是在網(wǎng)頁里面嵌入一段js,這段js會向特定的統(tǒng)計服務器發(fā)送請求的方式記錄訪問量;另一種策略是直接分析服務器日志,來統(tǒng)計網(wǎng)站訪問量。在理想的情況下,嵌入js的方式統(tǒng)計的網(wǎng)站流量應該高于分析服務器日志,這是因為用戶瀏覽器會有緩存,不一定每次真實用戶訪問都會觸發(fā)服務器的處理。但實際情況是,分析服務器日志得到的網(wǎng)站訪問量遠遠高于嵌入js方式,極端情況下,甚至要高出10倍以上。

現(xiàn)在很多網(wǎng)站喜歡采用awstats來分析服務器日志,來計算網(wǎng)站的訪問量,但是當他們一旦采用Google Analytics來統(tǒng)計網(wǎng)站流量的時候,卻發(fā)現(xiàn)GA統(tǒng)計的流量遠遠低于awstats,為什么GA和awstats統(tǒng)計會有這么大差異呢?罪魁禍首就是把自己偽裝成瀏覽器的網(wǎng)絡爬蟲。這種情況下awstats無法有效的識別了,所以awstats的統(tǒng)計數(shù)據(jù)會虛高。[Page]

其實作為一個網(wǎng)站來說,如果希望了解自己的網(wǎng)站真實訪問量,希望精確了解網(wǎng)站每個頻道的訪問量和訪問用戶,應該用頁面里面嵌入js的方式來開發(fā)自己的網(wǎng)站流量統(tǒng)計系統(tǒng)。自己做一個網(wǎng)站流量統(tǒng)計系統(tǒng)是件很簡單的事情,寫段服務器程序響應客戶段js的請求,分析和識別請求然后寫日志的同時做后臺的異步統(tǒng)計就搞定了。

通過流量統(tǒng)計系統(tǒng)得到的用戶IP基本是真實的用戶訪問,因為一般情況下爬蟲是無法執(zhí)行網(wǎng)頁里面的js代碼片段的。所以我們可以拿流量統(tǒng)計系統(tǒng)記錄的IP和服務器程序日志記錄的IP地址進行比較,如果服務器日志里面某個IP發(fā)起了大量的請求,在流量統(tǒng)計系統(tǒng)里面卻根本找不到,或者即使找得到,可訪問量卻只有寥寥幾個,那么無疑就是一個網(wǎng)絡爬蟲。

分析服務器日志統(tǒng)計訪問多的IP地址段一行shell就可以了:

C代碼

grep Processing production.log | awk '{print $4}' | awk -F'.' '{print $1"."$2"."$3".0"}' | sort | uniq -c | sort -r -n | head -n 200 > stat_ip.log   


然后把統(tǒng)計結果和流量統(tǒng)計系統(tǒng)記錄的IP地址進行對比,排除真實用戶訪問IP,再排除我們希望放行的網(wǎng)頁爬蟲,比方Google,百度,微軟msn爬蟲等等。后的分析結果就就得到了爬蟲的IP地址了。以下代碼段是個簡單的實現(xiàn)示意:

Ruby代碼

whitelist = []   
IO.foreach("#{RAILS_ROOT}/lib/whitelist.txt") { |line| whitelist << line.split[0].strip if line }   
  
realiplist = []   
IO.foreach("#{RAILS_ROOT}/log/visit_ip.log") { |line|  realiplist << line.strip if line }   
  
iplist = []   
IO.foreach("#{RAILS_ROOT}/log/stat_ip.log") do |line|   
  ip = line.split[1].strip   
  iplist << ip if line.split[0].to_i > 3000 && !whitelist.include?(ip) && !realiplist.include?(ip)   
end    
  
Report.deliver_crawler(iplist)  
 


分析服務器日志里面請求次數(shù)超過3000次的IP地址段,排除白名單地址和真實訪問IP地址,后得到的就是爬蟲IP了,然后可以發(fā)送郵件通知管理員進行相應的處理。

四、網(wǎng)站的實時反爬蟲防火墻實現(xiàn)策略

通過分析日志的方式來識別網(wǎng)頁爬蟲不是一個實時的反爬蟲策略。如果一個爬蟲非要針對你的網(wǎng)站進行處心積慮的爬取,那么他可能會采用分布式爬取策略,比方說尋找?guī)装偕锨國外的代理服務器瘋狂的爬取你的網(wǎng)站,從而導致網(wǎng)站無法訪問,那么你再分析日志是不可能及時解決問題的。所以必須采取實時反爬蟲策略,要能夠動態(tài)的實時識別和封鎖爬蟲的訪問。

要自己編寫一個這樣的實時反爬蟲系統(tǒng)其實也很簡單。比方說我們可以用memcached來做訪問計數(shù)器,記錄每個IP的訪問頻度,在單位時間之內,如果訪問頻率超過一個閥值,我們就認為這個IP很可能有問題,那么我們就可以返回一個驗證碼頁面,要求用戶填寫驗證碼。如果是爬蟲的話,當然不可能填寫驗證碼,所以就被拒掉了,這樣很簡單就解決了爬蟲問題。

用memcache記錄每個IP訪問計數(shù),單位時間內超過閥值就讓用戶填寫驗證碼,用Rails編寫的示例代碼如下:

Ruby代碼

ip_counter = Rails.cache.increment(request.remote_ip)   
if !ip_counter   
  Rails.cache.write(request.remote_ip, 1, :expires_in => 30.minutes)   
elsif ip_counter > 2000   
  render :template => 'test', :status => 401 and return false   [Page]
end  
 


這段程序只是簡單的示例,實際的代碼實現(xiàn)我們還會添加很多判斷,比方說我們可能要排除白名單IP地址段,要允許特定的User-Agent通過,要針對登錄用戶和非登錄用戶,針對有無referer地址采取不同的閥值和計數(shù)加速器等等。

此外如果分布式爬蟲爬取頻率過高的話,過期就允許爬蟲再次訪問還是會對服務器造成很大的壓力,因此我們可以添加一條策略:針對要求用戶填寫驗證碼的IP地址,如果該IP地址短時間內繼續(xù)不停的請求,則判斷為爬蟲,加入黑名單,后續(xù)請求全部拒絕掉。為此,示例代碼可以改進一下:

Ruby代碼

before_filter :ip_firewall, :except => :test  
def ip_firewall   
  render :file => "#{RAILS_ROOT}/public/403.html", :status => 403 if BlackList.include?(ip_sec)   
end  
 


我們可以定義一個全局的過濾器,對所有請求進行過濾,出現(xiàn)在黑名單的IP地址一律拒絕。對非黑名單的IP地址再進行計數(shù)和統(tǒng)計:

Ruby代碼

ip_counter = Rails.cache.increment(request.remote_ip)   
if !ip_counter   
  Rails.cache.write(request.remote_ip, 1, :expires_in => 30.minutes)   
elsif ip_counter > 2000   
  crawler_counter = Rails.cache.increment("crawler/#{request.remote_ip}")   
  if !crawler_counter   
    Rails.cache.write("crawler/#{request.remote_ip}", 1, :expires_in => 10.minutes)   
  elsif crawler_counter > 50   
    BlackList.add(ip_sec)   
    render :file => "#{RAILS_ROOT}/public/403.html", :status => 403 and return false  
  end  
  render :template => 'test', :status => 401 and return false  
end  
 


如果某個IP地址單位時間內訪問頻率超過閥值,再增加一個計數(shù)器,跟蹤他會不會立刻填寫驗證碼,如果他不填寫驗證碼,在短時間內還是高頻率訪問,就把這個IP地址段加入黑名單,除非用戶填寫驗證碼激活,否則所有請求全部拒絕。這樣我們就可以通過在程序里面維護黑名單的方式來動態(tài)的跟蹤爬蟲的情況,甚至我們可以自己寫個后臺來手工管理黑名單列表,了解網(wǎng)站爬蟲的情況。

這個策略已經(jīng)比較智能了,但是還不夠好!我們還可以繼續(xù)改進:

1、用網(wǎng)站流量統(tǒng)計系統(tǒng)來改進實時反爬蟲系統(tǒng)

還記得嗎?網(wǎng)站流量統(tǒng)計系統(tǒng)記錄的IP地址是真實用戶訪問IP,所以我們在網(wǎng)站流量統(tǒng)計系統(tǒng)里面也去操作memcached,但是這次不是增加計數(shù)值,而是減少計數(shù)值。在網(wǎng)站流量統(tǒng)計系統(tǒng)里面每接收到一個IP請求,就相應的cache.decrement(key)。所以對于真實用戶的IP來說,它的計數(shù)值總是加1然后就減1,不可能很高。這樣我們就可以大大降低判斷爬蟲的閥值,可以更加快速準確的識別和拒絕掉爬蟲。

2、用時間窗口來改進實時反爬蟲系統(tǒng)

爬蟲爬取網(wǎng)頁的頻率都是比較固定的,不像人去訪問網(wǎng)頁,中間的間隔時間比較無規(guī)則,所以我們可以給每個IP地址建立一個時間窗口,記錄IP地址近12次訪問時間,每記錄一次就滑動一次窗口,比較近訪問時間和當前時間,如果間隔時間很長判斷不是爬蟲,清除時間窗口,如果間隔不長,就回溯計算指定時間段的訪問頻率,如果訪問頻率超過閥值,就轉向驗證碼頁面讓用戶填寫驗證碼。

終這個實時反爬蟲系統(tǒng)就相當完善了,它可以很快的識別并且自動封鎖爬蟲的訪問,保護網(wǎng)站的正常訪問。不過有些爬蟲可能相當狡猾,它也許會通過大量的爬蟲測試來試探出來你的訪問閥值,以低于閥值的爬取速度抓取你的網(wǎng)頁,因此我們還需要輔助第3種辦法,用日志來做后期的分析和識別,就算爬蟲爬的再慢,它累計一天的爬取量也會超過你的閥值被你日志分析程序識別出來。[Page]

服務網(wǎng)絡

關于我們

網(wǎng)至普專注于網(wǎng)站建設/網(wǎng)站優(yōu)化,始終追求 “您的滿意,我的追求!”。懂您所需、做您所想!我們一直在思考如何為客戶創(chuàng)造更大的價值,讓客戶更省心!立足上海,服務全國。服務:上海,北京,廣州,深圳,成都,杭州,南京,蘇州,無錫等地

查看更多 >>

聯(lián)系我們

Copyright 2008 © 上海網(wǎng)至普信息科技有限公司 All rights reserved. 滬ICP備11006570號-13 滬公網(wǎng)安備 31011402007386號


關于我們 | 聯(lián)系我們 | 網(wǎng)站建設

返回頂部