有些web伺服器對於同一ip在一段時間內的訪問次數是有限制的,即禁止爬蟲頻數抓取以影響訪問體驗。
建立乙個有效的http**列表,每次以其中的乙個ip來訪問乙個站點,這樣能很好的避免被伺服器認定為爬蟲程式。
1.定義http**結構。建立乙個長度為m的http**結構陣列。結構struct shttpproxy;m_cip為**主機或ip,m_nport為**埠號,m_nfailednum訪問失敗次數,定義乙個閾值h,如果m_nfailednum>h則認定該**被禁用。
2.定義http**選擇方式。定義乙個隨機生成函式randm(m),每次隨機生成乙個1-m的下標l,取陣列中第l個http**作為本次訪問的位址。
**:冬天鄉下人喜歡烤火取暖,常見的情形就是四人圍著麻將桌,桌底放一盆碳火。有人覺得火不夠大,那加點木炭吧,還不夠,再加點。片刻之後,又覺得火太大,腳都快被烤熟了,那就取出一些木碳……直到火盆裡的火剛剛合適。這樣乙個看似簡單的情形中就包括pid控制系統的四個主要過程:設定目標,測量,比較和執行。結合pid控制器這四個過程來重新闡述上述情形是這樣的:人烤火時所期待的最合適的溫度是我們設定的目標;每個人都是乙個感測器,能感知到溫度的大小(雖然只是模糊的感知)——這是乙個測量的過程;我們感知到的溫度是不是最適合我們,是大還是小——這是乙個比較的過程;比較之後,我們知道火是大還是小了,小了就加點木炭,大了就取出部分木炭——這是乙個執行的過程。不斷重複最後三個過程(如圖1所示),直至使人能感覺到溫度比較合適。
圖1 pid控制過程迴圈
為什麼要控制爬蟲速度,難道像高鐵一樣快不好嗎?其中有兩方面原因:一、對於目標**來說是一種禮貌,如果速度太快,將給伺服器造成過大的負載;二、對於本人來說,抓取速度太快將導致致伺服器禁止訪問,從而丟失大量有效資料,甚至需要重新抓取。那麼如何控制爬蟲抓取網頁的速度,使它不至於太快?
通常情況下,在每個頁面抓取之間設定較大的延時等待以限制最大訪問頻率,可以保證既不會給伺服器造成過重負擔,也不會因訪問太頻繁而被伺服器禁止,然而這樣的方法將導致網路利用率低,抓取速度慢,對於大量網頁的抓取任務來說,往往是無法忍受的。
圖2 網路流暢和網路較差時網頁抓取時間對比
圖2是乙個簡化的理想模型,可以很好的說明這個問題,假設某**允許的最大訪問頻率為6頁/分鐘,於是最小時間間隔為10s,這個時間要通過很多次重複試驗來確定(**管理員肯定不會告訴你的)。網路流暢時每個網頁讀取時間為0.5s,為了保證不被伺服器遮蔽,至少要等待9.5s的間隔時間才繼續抓取下乙個頁面,這個9.5s的間隔時間是固定的,即使網路較差時也要等待這麼長的時間。網路較差時,網頁讀取時間為9.5s,再延時等待9.5s,於是每個網頁的讀取時間變為19s,幾乎是網路流暢時的兩倍。而實際上網路較差時的理想情況下,只需要等待0.5s,這時便保持和網路流暢時相同的抓取速度,由此可見這種限制最大速度的方法是很低效的。另外延時等待時間對抓取頻率的影響是很模糊的,延時1s時抓取頻率是100頁/分鐘,那麼延時10s就是10頁/分鐘嗎?很難確定,尤其是在複雜的網路環境中。
要改進上述方法,一種很自然的解決方案就是:使等待時間動態變化,即等於最小時間間隔減去網頁讀取時間,這樣就能保證網頁平均抓取時間在網路流暢和網路較差時都為最小時間間隔。這種方法對於單執行緒的爬蟲訪問小規模**來說也許可行,但在多執行緒分布式的爬蟲訪問大規模**時,整體上的抓取時間由許多並行的抓取任務共同決定,並且各種異常情況(頁面無效或者連線超時)使得抓取時間更加不可計算,這種方法就顯得相當笨拙了。綜合考慮各種因素,顯然我們需要一種模糊的,不需要精確計算的方法來控制爬蟲抓取速度,而且這個速度是很直觀的以頻率(頁/分鐘)來表示——pid控制演算法就是其中一種。
pid控制器控制爬蟲速度的原理簡單來說就是:速度快了,增加延時時間;速度慢了,減小延時時間——是否已經看到了其中與本文開始所描述的烤火情形之間的相似性?模擬烤火的情形,我設想pid控制爬蟲速度的方案是:
1)初始化:設定初始延時時間t0和比例係數kp(典型值-0.05)
2)目標設定:設定爬蟲速度s,比如40頁/分鐘
3)測量:統計每分鐘內爬蟲抓取網頁的數量n,可能是32,也可能是100等
4)比較:比較n和s的大小
5)執行:n如果比s大,說明太快了,於是增加延時時間;n如果比s小,說明太慢了,於是減小延時時間。
該方案的公式化表示如下,
tk=tk-1+kp*(s-n)(3.1)
其中k=1, 2, 3 ... ,tk是第k次設定的延時時間。
不要被表示式嚇住了,它所傳達的意思其實就是5)所描述的執行過程:速度太快 (s-n小於0,kp*(s-n)為正
),增加延時 (tk大於tk-1);速度太慢 (s-n大於0,kp*(s-n)為負
),減小延時 (tk小於tk-1)。
假設初始延時時間t0為1.0s, 比例係數kp為-0.05,爬蟲速度s設定為40頁/分鐘。如果某次爬蟲抓取網頁的數量n=100,根據3.1式計算的延時值為t1=t0+kp*(s-n)=1.0+(-0.05)*(40-100)=4.0。下一次可能的測量值n=30,則計算的延時值t2=4.0-0.05*10=3.5。
圖3 pid控制曲線
圖3是某次試驗中pid控制曲線,下面的資料是這次實驗的詳細記錄,第一列([2012/5/21 1:31:00]
)是當前時間,第二列(80)是前一分鐘內爬蟲抓取網頁的數量n,第三列(3799)是根據3.1式(實際計算中加入了乙個積分項,稍後詳細說明)計算出來的延時時間(單位為ms),爬蟲速度最終穩定在40頁/分鐘(允許一定的波動)
[2012/5/21 1:31:00] 80 3799
[2012/5/21 1:32:00] 32 4039
[2012/5/21 1:33:00] 30 3980
[2012/5/21 1:34:00] 30 3720
[2012/5/21 1:35:00] 32 3400
[2012/5/21 1:36:00] 36 3200
[2012/5/21 1:37:00] 36 2920
[2012/5/21 1:38:00] 42 2980
[2012/5/21 1:39:00] 40 2980
[2012/5/21 1:40:00] 40 2980
[2012/5/21 1:41:00] 40 2980
[2012/5/21 1:42:00] 40 2980
[2012/5/21 1:43:00] 40 2980
[2012/5/21 1:44:00] 40 2980
[2012/5/21 1:45:00] 40 2980
[2012/5/21 1:46:00] 40 2980
[2012/5/21 1:47:00] 40 2980
[2012/5/21 1:48:00] 40 2980
[2012/5/21 1:49:00] 39 2910
[2012/5/21 1:50:00] 40 2910
[2012/5/21 1:51:00] 41 2980
[2012/5/21 1:52:00] 39 2930
[2012/5/21 1:53:00] 41 3000
[2012/5/21 1:54:00] 40 3000
[2012/5/21 1:55:00] 39 2930
有了pid控制器,在網路環境允許的範圍內,想讓爬蟲每分鐘抓幾個網頁它就抓幾個,是不是很方便?
式3.1是乙個簡化版本的pid控制器,只用到了比例項(p),加入積分項(i)和微分項(d)後才是乙個完整的pid控制器。pid是三個英文單詞的縮寫,分別代表比例單元(proportion),積分單元(integral)和微分單元(differential),每個單元分別對應著乙個乘積因子kp,ki,kd。加入積分單元和微分單元後,式3.1擴充套件為式4.1,其中sum是誤差項(s-n)的積分(其實就是所有誤差值的和),diff是誤差項的微分(在單位時間內就是前後兩次誤差項的差值)
tk=tk-1+kp*(s-n)+ki*sum+kd*diff
(4.1)
乘積因子kp,ki,kd的設定與具體的應用場景相關,並且需要通過實驗來確定其最佳值。
如果令ki=0,kd=0,那麼式4.1就是式3.1了。
網頁資料抓取 爬蟲
資料抓取其實從字面意思就知道它是抓取資料的,在網際網路世界中,資料量是乙個非常大的。有時候靠人為去獲取資料這是乙個非常不明智的。尤其是你需要的資料來自很多不同的地方。網路爬蟲是是一種按照一定的規則,自動地抓取網際網路 資訊的程式或者指令碼。它主要抓取形式有兩種 1種是抓取網頁鏈結,通過url鏈結得到...
網頁抓取 PHP實現網頁爬蟲方式小結
抓取某乙個網頁中的內容,需要對dom樹進行解析,找到指定節點後,再抓取我們需要的內容,過程有點繁瑣。lz總結了幾種常用的 易於實現的網頁抓取方式,如果熟悉jquery選擇器,這幾種框架會相當簡單。一 ganon 文件 測試 抓取我的 首頁所有class屬性值是focus的div元素,並且輸出clas...
網頁抓取 PHP實現網頁爬蟲方式小結
抓取某乙個網頁中的內容,需要對dom樹進行解析,找到指定節點後,再抓取我們需要的內容,過程有點繁瑣。lz總結了幾種常用的 易於實現的網頁抓取方式,如果熟悉jquery選擇器,這幾種框架會相當簡單。一 ganon 文件 測試 抓取我的 首頁所有class屬性值是focus的div元素,並且輸出clas...