通过Flask和Redis构造一个动态维护的代理池
代理池的維護
目前有很多網(wǎng)站提供免費代理,而且種類齊全,比如各個地區(qū)、各個匿名級別的都有,不過質(zhì)量實在不敢恭維,畢竟都是免費公開的,可能一個代理無數(shù)個人在用也說不定。所以我們需要做的是大量抓取這些免費代理,然后篩選出其中可用的代理存儲起來供我們使用,不可用的進行剔除。
?
獲取代理的途徑
?維護一個代理池第一步就是要找到提供免費代理的站點,例如PROXY360,網(wǎng)頁內(nèi)容如下:
?
?
而且可以看到網(wǎng)頁里提供了一些免費代理列表,包括服務(wù)器地址、端口、代理種類、地區(qū)、更新時間等等信息。
當(dāng)前我們需要的就是代理服務(wù)器和端口信息,將其爬取下來即可。
維護代理
那么問題來了,當(dāng)我們把這些免費的代理爬取下來后,該怎么去保存他們?
首先我們需要確保這個數(shù)據(jù)庫可以是我們邊存邊取,另外還需要定時檢查隊列中那些過期的代理并將它們剔除,所以需要易于存取。
另外怎么區(qū)分代理的新舊,如果按照代理網(wǎng)站上給出的代理的修改時間來標(biāo)識是可行的,但是更簡單的方法就是維護一個隊列,確保只從一端存入,例如右端,這樣就能確保最新的代理一直處于隊列的右段,而在隊列左端的則是存取時間較長的,那么在使用時我們就可以提取隊列右端的代理來使用。
那么對于隊列左端的代理我們也不能就這么任其老化,還要做的操作就是把左端的代理提取出來,進行測試,將那些可以使用的放入隊列右端,不能使用了的則剔除隊列。
通過以上操作,就保證了隊列里的代理一直處于可用狀態(tài)。
所以從目前來看,既能高效處理,又可以做到隊列動態(tài)維護,合適的方法就是使用Redis數(shù)據(jù)庫的隊列。
?
下面這張流程圖就是整個代理隊列需要具備的功能:
?
可以定義一個類來維護一個Redis隊列,比如get方法是從左端取出,put方法是從右端放入,pop方法時從右端取出可用代理。
?
import redisfrom proxypool.error import PoolEmptyError
from proxypool.setting import HOST,PORT,PASSWORD
class RedisClient(object):
def __init__(self,host=HOST,port=PORT,password=PASSWORD):
if password:
self._db = redis.Redis(host,port,password)
else:
self._db = redis.Redis(host,port)
def get(self, count=1):
proxies = self._db.Irange("proxies",0, count - 1)
self._db.Itrim("proxis", count, -1)
return proxies
def put(self,proxy):
self._db.rpush("proxies", proxy)
def pop(self,self):
try:
self._db.rpop("proxies").decode('utf-8')
except:
raise PoolEmptyError
?
?
?
檢測代理
那么如何來檢測代理是否可用呢?可以使用這個代理來請求某個網(wǎng)站,如果返回的200則證明這個代理可用,否則代理不可使用。
?
conn = RedisClient() proxies = {'http': proxy} r = requests.get(url,proxies=proxies) if r.status_code == 200:conn.put(proxy)
例如在這里proxy就是要檢測的代理,使用requests庫設(shè)置好這個代理,然后請求百度,正常請求,那就可以將這個代理存入Redis。
?
?
獲取可用代理
現(xiàn)在我們維護了一個代理池,那么這個代理池需要是可以公用的。
比如現(xiàn)在有多個爬蟲項目都需要用到代理,而代理池的維護作為另外的一個項目,他們之間如果要建立連接,最恰當(dāng)?shù)姆绞骄褪墙涌凇?/span>
所以可以利用Web服務(wù)器來實現(xiàn)一個接口,其他的項目通過請求這個接口得到內(nèi)容獲取到一個可用代理,這樣保證了代理池的通用性。
所以要實現(xiàn)這個還需要一個Web服務(wù)器,例如Flask,Tornado等等。
例如使用Flask,定義一個路由,然后調(diào)用的RedisClient的pop方法,返回結(jié)果即可。
?
@app.route('/get') def get_proxy():conn = RedisClient() return conn.pop()
這樣一來,整個程序運行起來后,請求網(wǎng)頁就可以看到一個可用代理了。
?
?
使用代理
使用代理只需要請求這個站點,就可以拿到使用的代理了。
?
def get_proxy():r = requests.get('http://127.0.0.1:5000/get')proxy = r.textreturn proxydef crawl(url, proxy):proxies = {'http': get_proxy()}r = requests.get(url, proxies=proxies)#do something?
?
樣例實現(xiàn) ?
?
https://github.com/gzf1234/ProxyPool
?
轉(zhuǎn)載于:https://www.cnblogs.com/coder-gao/p/7559801.html
總結(jié)
以上是生活随笔為你收集整理的通过Flask和Redis构造一个动态维护的代理池的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Wecoach陈隽永:如何打造一款完美的
- 下一篇: jvm内存模型及分配