用Node抓站(三) 防止被封

2021-09-11 09:43:52 字數 3400 閱讀 5831

抓取如果抓取的太快太頻繁會被源站封ip,本文會介紹下通過限流、限速和使用**的方式來防止被封

上篇文章,抓取「電影天堂」最新的170部電影,在抓取首頁電影list之後,會同時發出170個請求抓取電影的詳情頁,這樣在固定時間點集中爆發式的訪問頁面,很容易在日誌中被找出來,而且併發請求大了,很可能會中**的防火牆之類的策略,ip被加到黑名單就悲劇了

這裡我使用async模組限制併發次數,async主要有:集合、流程和工具三大類方法,這裡我使用eachlimit(arr, limit, iterator, [callback]),所有修改是上篇文章的fetchcontents方法,該方法接受抓取到的170個文章的url list,這次通過eachlimit將170個url按照3個一組併發,依次執行,具體**如下:

function

fetchcontents (urls) , ,

title:

}).then((d) => , () => )

}, () => )

})}複製**

限流只是控制了一次併發的請求數,並沒有讓抓取程式慢下來,所以還需要限速,在限流的基礎上限速就變得很簡單,只需要在執行eachlimitcallback的時候,加上個timer就好了,為了方便檢視限速的效果,每次抓取成功之後,都console.log顯示時間,所以改完的**如下:

function fetchcontents (urls) , ,

title:

}).then((d) => ===>success, $`)

results.push(d)

settimeout(callback, 2e3)

}, () => )

}, () => )

})}複製**

效果如下:

因為一些**更新比較慢,我們寫的抓取程式在定時指令碼任務(crontab)跑的時候,可能**還沒有更新,如果不做處理會造成資源的浪費,尤其國內不少vps都是有流量限制的,不做控制,真金**就打水漂了。。

繼續拿「電影天堂」最新更新的內容進行抓取,如果假設每五分鐘執行一次抓取指令碼,那麼需要記錄下已經抓取過的文章(電影),這裡我簡單處理一下,通過乙個_fetchedlist.json的檔案,記錄抓取完的文章(電影)。具體思路如下:

抓取每個電影詳情頁成功後,將抓取到的url放入乙個陣列array

等全部抓取結束,將這個陣列array,寫到檔案_fetchedlist.json下次抓取的時候,require這個_fetchedlist.json,得到陣列array,抓取之前判斷要抓取的url是否在這個陣列內

陣列保持長度是300(170個電影夠用了),保證先入先出,即超過300長度將最早的移出

具體**講解如下:

引入抓取的記錄檔案

var fs = require('fs-extra')

var path = require('path')

var uniquearray =

const unique_array_url = './_fetchedlist.json'

try catch (e) 複製**

改造url處理函式,過濾下url陣列,已經抓取過的就不要抓取了
function

deallistdata (data) ).filter(url => )

// 如果為空就reject

urls.length ? resolve(urls) : reject('empty urls')

} else

})}複製**

增加乙個處理方法,保持uniquearray長度是300,不要無限增加
function

adduniquearray (url)

}複製**

在抓取完之後,記錄新的uniquearray陣列內容到json檔案:
fetchlist().then(deallistdata).then(fetchcontents).then((d) => ).catch((e) => )複製**
為了迷惑被抓取的**,除了偽裝user-agent等方法,最重要的是使用**服務,如果有錢的主可以買**,然後用,對於我們做demo,那就直接抓取**吧!下面**是抓取快****的****:

var spider = require('../lib/spider')

function

fetchproxy () , )

if (proxy[0] && proxy[1] && /\d.\d.\d.\d/.test(proxy[0]) && /\d/.test(proxy[1])) else

return proxy}})

}fetchproxy().then(data => )複製**

抓取之後的**不一定直接就可以用,還需要測試下**是否可以訪問成功我們要抓取的**,先寫個checkproxy(proxy)的方法,用於檢測使用傳入的proxy是否抓取成功:

function

checkproxy (proxy) ,

})}複製**

fetchproxy().then(data => :$`).then(() => ).finally(done).catch(e =>

void (e))

})function

done ()

}})複製**

這裡最後console.log出來的就是通過**抓取成功的**,可以存入到資料庫,以後抓取使用。

**的維護

最後在簡單說下**的維護,抓取到了**,因為是免費的,一般過一段時間就會不能用了,所以在使用的時候,可以將**放到乙個資料庫中維護,資料庫中有字段:succcountfailcount用於記錄每次使用該**成功和失敗的次數。每次使用**抓取的時候,要有個反饋機制,如果成功就succcount+1 ,失敗就failcount+1。當失敗次數過多的時候,這個**就不要再使用了。

本系列寫到第三篇了,後面還會有一些常見問題解答。週末看到一篇用python抓知乎匯出txt或者markdown的文章,以後手癢就會放出番外篇 ?

關注三水清

App防止被抓包

1.使用https,可以初步防止一些只抓http包的軟體。2.如果網路框架使用的是okhttp,可以在builder中設定proxy proxy.no proxy 屬性,禁止使用 這樣一般使用中間人的 就使用不了,客戶端是直接訪問伺服器。3.判斷是否使用了 final boolean flag bu...

移動端防止被抓包

最近在除錯乙個bug的時候沒有其它好的辦法了,用到了抓包這麼個方式才發現問題,不過問題已經解決了 不過在抓包的時候突然想到了,我擦,我用的https也可以被抓到包啊。所以又看了一下https的鏈結建立的流程 ssl tls原理詳解 和相關的中間人攻擊的流程,想了一下其中的原理。1.客戶端首先要向遠端...

AF 配置https證書,防止被抓包

1.afsecuritypolicy customsecuritypolicy 需要伺服器提供乙個crt檔案 把.crt檔案 匯入 鑰匙串中,並匯出.cer證書 把.cer證書 放在 專案目錄下,並作如下操作。把第一段 放在你 網路請求的類中。順便 加上 在網上查到的資料 afsecuritypol...