利用 Flask+Redis 維護 IP 代理池

代理池的維護

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

獲取代理途徑

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

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

當前我們需要的就是代理服務器和端口信息,將其爬取下來即可。

維護代理

那麼爬取下代理之後怎樣保存呢?

首先我們需要確保的目標是可以邊取邊存,另外還需要定時檢查隊列中不可用的代理將其剔除,所以需要易於存取。

另外怎樣區分哪些是最新的可用的,哪些是舊的,如果用修改時間來標註是可以的,不過更簡單的方法就是維護一個隊列,只從一端存入,例如右端,這樣就能確保最新的代理在隊列右端,而在左端則是存入時間較長的代理,如果要取一個可用代理,從隊列右端取一個就好了。

那麼對於隊列的左端,不能讓它一直老化下去,還需要做的操作就是定時從隊列左端取出代理,然後進行檢測,如果可用,重新將其加入右端。

通過以上操作,就保證了代理一直是最新可用的。

所以目前來看,既能高效處理,又可以做到隊列動態維護,合適的方法就是利用Redis數據庫的隊列。

可以定義一個類來維護一個Redis隊列,比如get方法是批量從左端取出代理,put方法是從右端放入可用代理,pop方法是從右端取出最新可用代理。

import redis
from proxypool.error import PoolEmptyError
from proxypool.setting import HOST, PORT

class RedisClient(object):
    def __init__(self, host=HOST, port=PORT):
        self._db = redis.Redis(host, port)

    def get(self, count=1):
        proxies = self._db.lrange("proxies", 0, count - 1)
        self._db.ltrim("proxies", count, -1)
        return proxies

    def put(self, proxy):
        self._db.rpush("proxies", proxy)

    def pop(self):
        try:
            return self._db.rpop("proxies").decode('utf-8')
        except:
            raise PoolEmptyError

檢測代理

那麼如何來檢測代理是否可用?可以使用這個代理來請求某個站點,比如百度,如果獲得正常的返回結果,那證明代理可用,否則代理不可用。

conn = RedisClient()
proxies = {'http': proxy}
r = requests.get('https://www.baidu.com', proxies=proxies)
if r.status_code == 200:
    conn.put(proxy)

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

獲取可用代理

現在我們維護了一個代理池,那麼這個代理池需要是可以公用的。

比如現在有多個爬蟲項目都需要用到代理,而代理池的維護作爲另外的一個項目,他們之間如果要建立連接,最恰當的方式就是接口。

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

所以要實現這個還需要一個Web服務器,例如Flask,Tornado等等。

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

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

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

使用代理

使用代理時只需要請求這個站點,就可以拿到可使用的代理了。

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

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

可以定義一個簡單的方法,返回網頁內容即代理,然後在爬取方法裏設置代理使用即可。

樣例實現

https://github.com/Germey/ProxyPool

此文已由作者授權騰訊雲技術社區發佈,轉載請註明文章出處

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章