玩轉(zhuǎn)爬蟲:用Python搭建匿名代理池

01?寫在前面

? ? ? ?常聽到很多人抱怨自己的IP因爬蟲次數(shù)太多而被網(wǎng)站屏蔽,不得不頻繁使用各種代理IP,卻又因?yàn)榫W(wǎng)上的公開代理大部分都是不能使用,而又要花錢花精力去申請VIP代理,幾番波折又遭屏蔽。特此寫一篇如何利用Python搭建代理池的文章,以降低時(shí)間及精力成本,實(shí)現(xiàn)自動化獲取活躍代理IP的功能。


02?運(yùn)作原理

一、 網(wǎng)站代理獲取

1.?爬免費(fèi)代理網(wǎng)站的IP列表測試是否可用及是否是高匿

2.?若都是,則放進(jìn)數(shù)據(jù)庫,否則丟棄。

3.?重復(fù)第2步


二、 保證失效的代理能被盡快從代理池中挑出

1.?從爬蟲數(shù)據(jù)庫獲取IP

2.?測試IP的可用性和匿名性

3.?如果可用且匿名,則保留,否則丟棄。

4.?重復(fù)第1步


說明①:可建立一個爬蟲程序守護(hù)程序(Daemon),有此方面需要的小伙伴可自行谷歌,在此不多做介紹。

說明②:可建立一個對外代理信息接口,無論你用NodeJS或者Flask/Django或者PHP來寫都沒關(guān)系,在此也不多做介紹。


03?實(shí)現(xiàn)

? ? ? ?建議庫: requests, BeautifulSoup, re, sqlite3。

? ? ? ?其中,用requests庫獲取代理網(wǎng)站頁面,用BeautifulSoup和re兩庫來進(jìn)行代理信息獲取,用sqlite3來對這些信息進(jìn)行存取。

? ? ? ?如果必要(如代理網(wǎng)站有反爬蟲策略時(shí)),可用PhantomJS替代requests,或用相應(yīng)庫進(jìn)行數(shù)據(jù)清理(如base64解碼)。


下面簡單展示一下各部分的代碼:

? ? ? ?首先是選擇多個能爬取代理且不容易被屏蔽IP的網(wǎng)站,此處以proxy-list.org為例:

BASE_URL?=?"https://proxy-list.org/english/index.php?p="

#IP地址及端口的正則

Re_Pattern_IP?=?re.compile("(.*):")

Re_Pattern_PORT?=?re.compile(":(.*)")

#網(wǎng)站有11頁,所以循環(huán)11次獲取所有代理IP及端口

for?startingURL_Param?in?range(1,11):

HTML_ProxyPage?=?requests.get(BASE_URL+str(startingURL_Param)).content

soup?=?bs(HTML_ProxyPage,"html.parser")

? ?for?Raw_ProxyInfo?in?soup.find_all("ul",{"class":None}):

? ? ? ?#此網(wǎng)站有用Base64簡單對代理進(jìn)行了加密,所以這里對其解碼

ip_port?=?base64.b64decode(Raw_ProxyInfo.find("li",{"class":"proxy"}).text.replace("Proxy('","").replace("')",""))

? ? ? ?#接下來利用正則從網(wǎng)頁數(shù)據(jù)中提取我們需要的信息

IP?=?re.findall(Re_Pattern_IP,?ip_port)[0]

PORT?=?re.findall(Re_Pattern_PORT,?ip_port)[0]

TYPE?=?Raw_ProxyInfo.find("li",{"class":"https"}).text


? ? ? ?接下來是一段簡易代理池框架類的代碼,提供代理數(shù)據(jù)庫的添加、刪除、可連接性檢測、匿名性檢測:


class?ProxyPool:?

? ?#初始化爬蟲池?cái)?shù)據(jù)庫

? ?def?__init__(self,ProxyPoolDB):

? ? ? ?self.ProxyPoolDB?=?ProxyPoolDB

? ? ? ?self.conn?=?sqlite3.connect(self.ProxyPoolDB,?isolation_level=None)

? ? ? ?self.cursor?=?self.conn.cursor()

? ? ? ?self.TB_ProxyPool?=?"TB_ProxyPool"

? ? ? ?self.cursor.execute("CREATE TABLE IF NOT EXISTS "+self.TB_ProxyPool+"(ip TEXT UNIQUE, port INTEGER, protocol TEXT)")

? ?#添加代理IP進(jìn)代理池的接口

? ?def?addProxy(self,?IP,?PORT,?PROTOCOL):?

? ? ? ?self.cursor.execute("INSERT OR IGNORE INTO "?+?self.TB_ProxyPool+"(ip, port, protocol) VALUES (?,?,?)",?[IP,PORT,PROTOCOL])

? ?#檢查代理的匿名性及可連接性

? ?def?testConnection(self,?IP,?PORT,?PROTOCOL):

proxies?=?{?PROTOCOL:?IP+":"+PORT?}

? ? ? ?try:

? ? ? ? ? ?OrigionalIP?=?requests.get("http://icanhazip.com",timeout=REQ_TIMEOUT).content

? ? ? ? ? ?MaskedIP?=?requests.get("http://icanhazip.com",?timeout=REQ_TIMEOUT,proxies=proxies).content

? ? ? ? ? ?if?OrigionalIP?!=?MaskedIP:

? ? ? ? ? ? ? ?return?True

? ? ? ? ? ?else:

? ? ? ? ? ? ? ?return?False

? ? ? ?except:?

? ? ? ? ? ?return?False

? ?#刪除代理IP對應(yīng)的數(shù)據(jù)庫記錄

? ?def?delRecord(self,?IP):

? ? ? ?self.cursor.execute("DELETE FROM "+self.TB_ProxyPool+" WHERE ip=?",(IP,))

下面是對代理池進(jìn)行去“失效IP”的代碼:?

? ?#循環(huán)代理池,逐行測試IP地址端口協(xié)議是否可用

def?cleanNonWorking(self):

? ?for?info?in?self.cursor.execute("SELECT * FROM "+self.TB_ProxyPool).fetchall():

IP?=?info[0]

PORT?=?str(info[1])

PROTOCOL?=?info[2].lower()

isAnonymous?=?self.testConnection(IP,PORT,PROTOCOL)

? ? ? ?if?isAnonymous?==?False:

? ? ? ? ? ?#這條代理的可用性失效了,從數(shù)據(jù)庫里刪除

? ? ? ? ? ?self.delRecord(IP)

#通過檢測icanhazip.com回顯來檢測可用性及匿名性

def?testConnection(self,?IP,?PORT,?PROTOCOL):

proxies?=?{?PROTOCOL:?IP+":"+PORT?}

? ? ? ?try:

? ? ? ? ? ?OrigionalIP?=?requests.get("http://icanhazip.com",timeout=REQ_TIMEOUT).content

? ? ? ? ? ?MaskedIP?=?requests.get("http://icanhazip.com",?timeout=REQ_TIMEOUT,proxies=proxies).content

? ? ? ? ? ?if?OrigionalIP?!=?MaskedIP:

? ? ? ? ? ? ? ?return?True

? ? ? ? ? ?else:

? ? ? ? ? ? ? ?return?False

? ? ? ?except:?

? ? ? ? ? ?return?False

04?反思

? ? ? ?這個項(xiàng)目是我年初時(shí)用Python練手寫的,以現(xiàn)在的程度再來回顧,邏輯不夠嚴(yán)謹(jǐn),各類功能太過耦合,不少段落需要重寫,因?yàn)榇a是在校園網(wǎng)內(nèi)所跑,所以還需要考慮到網(wǎng)絡(luò)連接的穩(wěn)定性,這就造成部分代碼之間的混亂關(guān)系。

? ? ? ?通過icanhazip.com來檢測代理匿名性的方法或許有效,但卻忽略了X-Forwarded-For的HTTP頭,所以有很大風(fēng)險(xiǎn),必須改進(jìn)。

? ? ? ?驗(yàn)證代理池內(nèi)代理的有效性,需要多線程,目前的方案效率太低。


05?完整代碼

? ? ? ?放在此文章中的是代理池的核心代碼,旨在提供各位讀者能夠自己實(shí)現(xiàn)的思路及參考。完整代碼可在作者的Github主頁中找到,Ubuntu 16.04及Kali下用Python 2.7測試可運(yùn)行。

加群:731233835? ? 可獲得:10本py? ?PDF

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容