經過Flask和Redis構造一個動態維護的代理池

代理池的維護

目前有不少網站提供免費代理,並且種類齊全,好比各個地區、各個匿名級別的都有,不過質量實在不敢恭維,畢竟都是免費公開的,可能一個代理無數我的在用也說不定。因此咱們須要作的是大量抓取這些免費代理,而後篩選出其中可用的代理存儲起來供咱們使用,不可用的進行剔除。python

 

獲取代理的途徑

 維護一個代理池第一步就是要找到提供免費代理的站點,例如PROXY360,網頁內容以下:git

 

 

並且能夠看到網頁裏提供了一些免費代理列表,包括服務器地址、端口、代理種類、地區、更新時間等等信息。github

當前咱們須要的就是代理服務器和端口信息,將其爬取下來便可。redis

維護代理

那麼問題來了,當咱們把這些免費的代理爬取下來後,該怎麼去保存他們?
數據庫

首先咱們須要確保這個數據庫能夠是咱們邊存邊取,另外還須要定時檢查隊列中那些過時的代理並將它們剔除,因此須要易於存取。服務器

另外怎麼區分代理的新舊,若是按照代理網站上給出的代理的修改時間來標識是可行的,可是更簡單的方法就是維護一個隊列,確保只從一端存入,例如右端,這樣就能確保最新的代理一直處於隊列的右段,而在隊列左端的則是存取時間較長的,那麼在使用時咱們就能夠提取隊列右端的代理來使用。app

那麼對於隊列左端的代理咱們也不能就這麼任其老化,還要作的操做就是把左端的代理提取出來,進行測試,將那些可使用的放入隊列右端,不能使用了的則剔除隊列。測試

經過以上操做,就保證了隊列裏的代理一直處於可用狀態。網站

因此從目前來看,既能高效處理,又能夠作到隊列動態維護,合適的方法就是使用Redis數據庫的隊列。url

 

下面這張流程圖就是整個代理隊列須要具有的功能:

 

能夠定義一個類來維護一個Redis隊列,好比get方法是從左端取出,put方法是從右端放入,pop方法時從右端取出可用代理。

 

import redis
from 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

 

 

  

 

檢測代理

那麼如何來檢測代理是否可用呢?可使用這個代理來請求某個網站,若是返回的200則證實這個代理可用,不然代理不可以使用。

 

conn = RedisClient()
proxies = {'http': proxy}
r = requests.get(url,proxies=proxies)
if r.status_code == 200:
  conn.put(proxy)

  

例如在這裏proxy就是要檢測的代理,使用requests庫設置好這個代理,而後請求百度,正常請求,那就能夠將這個代理存入Redis。

 

 

獲取可用代理

如今咱們維護了一個代理池,那麼這個代理池須要是能夠公用的。

好比如今有多個爬蟲項目都須要用到代理,而代理池的維護做爲另外的一個項目,他們之間若是要創建鏈接,最恰當的方式就是接口。

因此能夠利用Web服務器來實現一個接口,其餘的項目經過請求這個接口獲得內容獲取到一個可用代理,這樣保證了代理池的通用性。

因此要實現這個還須要一個Web服務器,例如Flask,Tornado等等。

例如使用Flask,定義一個路由,而後調用的RedisClient的pop方法,返回結果便可。

 

@app.route('/get')
def get_proxy():
   conn = RedisClient()    
  return conn.pop()

  

這樣一來,整個程序運行起來後,請求網頁就能夠看到一個可用代理了。  

 

 

使用代理

使用代理只須要請求這個站點,就能夠拿到使用的代理了。

 

def get_proxy():
    r = requests.get('http://127.0.0.1:5000/get')
    proxy = r.text
    return proxy

def crawl(url, proxy):
    proxies = {'http': get_proxy()}
    r = requests.get(url, proxies=proxies)
    #do something
    

 

  

 

  

樣例實現  

 

https://github.com/gzf1234/ProxyPool

相關文章
相關標籤/搜索