Python3爬蟲如何維護代理池-創(chuàng)新互聯(lián)

這篇文章主要為大家展示了Python3爬蟲如何維護代理池,內(nèi)容簡而易懂,希望大家可以學(xué)習(xí)一下,學(xué)習(xí)完之后肯定會有收獲的,下面讓小編帶大家一起來看看吧。

成都創(chuàng)新互聯(lián)公司主營任丘網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,重慶App定制開發(fā),任丘h5重慶小程序開發(fā)搭建,任丘網(wǎng)站營銷推廣歡迎任丘等地區(qū)企業(yè)咨詢

1. 準(zhǔn)備工作

要實現(xiàn)代理池我們首先需要成功安裝好了 Redis 數(shù)據(jù)庫并啟動服務(wù),另外還需要安裝 Aiohttp、Requests、RedisPy、PyQuery、Flask 庫,如果沒有安裝可以參考第一章的安裝說明。

2. 代理池的目標(biāo)

代理池要做到易用、高效,我們一般需要做到下面的幾個目標(biāo):

基本模塊分為四塊,獲取模塊、存儲模塊、檢查模塊、接口模塊。

獲取模塊需要定時去各大代理網(wǎng)站抓取代理,代理可以是免費公開代理也可以是付費代理,代理的形式都是 IP 加端口,盡量從不同來源獲取,盡量抓取高匿代理,抓取完之后將可用代理保存到數(shù)據(jù)庫中。

存儲模塊負(fù)責(zé)存儲抓取下來的代理。首先我們需要保證代理不重復(fù),另外我們還需要標(biāo)識代理的可用情況,而且需要動態(tài)實時處理每個代理,所以說,一種比較高效和方便的存儲方式就是使用 Redis 的 Sorted Set,也就是有序集合。

檢測模塊需要定時將數(shù)據(jù)庫中的代理進行檢測,在這里我們需要設(shè)置一個檢測鏈接,最好是爬取哪個網(wǎng)站就檢測哪個網(wǎng)站,這樣更加有針對性,如果要做一個通用型的代理,那可以設(shè)置百度等鏈接來檢測。另外我們需要標(biāo)識每一個代理的狀態(tài),如設(shè)置分?jǐn)?shù)標(biāo)識,100 分代表可用,分?jǐn)?shù)越少代表越不可用,檢測一次如果可用,我們可以將其立即設(shè)置為100 滿分,也可以在原基礎(chǔ)上加 1 分,當(dāng)不可用,可以將其減 1 分,當(dāng)減到一定閾值后就直接從數(shù)據(jù)庫移除。通過這樣的標(biāo)識分?jǐn)?shù),我們就可以區(qū)分出代理的可用情況,選用的時候會更有針對性。

接口模塊需要用 API 來提供對外服務(wù)的接口,其實我們可以直接連數(shù)據(jù)庫來取,但是這樣就需要知道數(shù)據(jù)庫的連接信息,不太安全,而且需要配置連接,所以一個比較安全和方便的方式就是提供一個 Web API 接口,通過訪問接口即可拿到可用代理。另外由于可用代理可能有多個,我們可以提供隨機返回一個可用代理的接口,這樣保證每個可用代理都可以取到,實現(xiàn)負(fù)載均衡。

以上便是設(shè)計代理的一些基本思路,那么接下來我們就設(shè)計一下整體的架構(gòu),然后用代碼該實現(xiàn)代理池。

3. 代理池的架構(gòu)

根據(jù)上文的描述,代理池的架構(gòu)可以是這樣的,如圖 9-1 所示:

Python3爬蟲如何維護代理池

圖 9-1 代理池架構(gòu)

代理池分為四個部分,獲取模塊、存儲模塊、檢測模塊、接口模塊。

存儲模塊使用Redis的有序集合,用以代理的去重和狀態(tài)標(biāo)識,同時它也是中心模塊和基礎(chǔ)模塊,將其他模塊串聯(lián)起來。

獲取模塊定時從代理網(wǎng)站獲取代理,將獲取的代理傳遞給存儲模塊,保存到數(shù)據(jù)庫。

檢測模塊定時通過存儲模塊獲取所有代理,并對其進行檢測,根據(jù)不同的檢測結(jié)果對代理設(shè)置不同的標(biāo)識。

接口模塊通過 Web API 提供服務(wù)接口,其內(nèi)部還是連接存儲模塊,獲取可用的代理。

4. 代理池的實現(xiàn)

接下來我們分別用代碼來實現(xiàn)一下這四個模塊。

存儲模塊

存儲在這里我們使用 Redis 的有序集合,集合的每一個元素都是不重復(fù)的,對于代理代理池來說,集合的元素就變成了一個個代理,也就是 IP 加端口的形式,如 60.207.237.111:8888,這樣的一個代理就是集合的一個元素。另外有序集合的每一個元素還都有一個分?jǐn)?shù)字段,分?jǐn)?shù)是可以重復(fù)的,是一個浮點數(shù)類型,也可以是整數(shù)類型。該集合會根據(jù)每一個元素的分?jǐn)?shù)對集合進行排序,數(shù)值小的排在前面,數(shù)值大的排在后面,這樣就可以實現(xiàn)集合元素的排序了。

對于代理池來說,這個分?jǐn)?shù)可以作為我們判斷一個代理可用不可用的標(biāo)志,我們將 100 設(shè)為最高分,代表可用,0 設(shè)為最低分,代表不可用。從代理池中獲取代理的時候會隨機獲取分?jǐn)?shù)最高的代理,注意這里是隨機,這樣可以保證每個可用代理都會被調(diào)用到。

分?jǐn)?shù)是我們判斷代理穩(wěn)定性的重要標(biāo)準(zhǔn),在這里我們設(shè)置分?jǐn)?shù)規(guī)則如下:

分?jǐn)?shù) 100 為可用,檢測器會定時循環(huán)檢測每個代理可用情況,一旦檢測到有可用的代理就立即置為 100,檢測到不可用就將分?jǐn)?shù)減 1,減至 0 后移除。

新獲取的代理添加時將分?jǐn)?shù)置為 10,當(dāng)測試可行立即置 100,不可行分?jǐn)?shù)減 1,減至 0 后移除。

這是一種解決方案,當(dāng)然可能還有更合理的方案。此方案的設(shè)置有一定的原因,在此總結(jié)如下:

當(dāng)檢測到代理可用時立即置為 100,這樣可以保證所有可用代理有更大的機會被獲取到。你可能會說為什么不直接將分?jǐn)?shù)加 1 而是直接設(shè)為最高 100 呢?設(shè)想一下,我們有的代理是從各大免費公開代理網(wǎng)站獲取的,如果一個代理并沒有那么穩(wěn)定,平均五次請求有兩次成功,三次失敗,如果按照這種方式來設(shè)置分?jǐn)?shù),那么這個代理幾乎不可能達(dá)到一個高的分?jǐn)?shù),也就是說它有時是可用的,但是我們篩選是篩選的分?jǐn)?shù)最高的,所以這樣的代理就幾乎不可能被取到,當(dāng)然如果想追求代理穩(wěn)定性的化可以用這種方法,這樣可確保分?jǐn)?shù)最高的一定是最穩(wěn)定可用的。但是在這里我們采取可用即設(shè)置 100 的方法,確保只要可用的代理都可以被使用到。

當(dāng)檢測到代理不可用時,將分?jǐn)?shù)減 1,減至 0 后移除,一共 100 次機會,也就是說當(dāng)一個可用代理接下來如果嘗試了 100 次都失敗了,就一直減分直到移除,一旦成功就重新置回 100,嘗試機會越多代表將這個代理拯救回來的機會越多,這樣不容易將曾經(jīng)的一個可用代理丟棄,因為代理不可用的原因可能是網(wǎng)絡(luò)繁忙或者其他人用此代理請求太過頻繁,所以在這里設(shè)置為 100 級。

新獲取的代理分?jǐn)?shù)設(shè)置為 10,檢測如果不可用就減 1,減到 0 就移除,如果可用就置 100。由于我們很多代理是從免費網(wǎng)站獲取的,所以新獲取的代理無效的可能性是非常高的,可能不足 10%,所以在這里我們將其設(shè)置為 10,檢測的機會沒有可用代理 100 次那么多,這也可以適當(dāng)減少開銷。

以上便是代理分?jǐn)?shù)的一個設(shè)置思路,不一定是最優(yōu)思路,但個人實測實用性還是比較強的。

所以我們就需要定義一個類來操作數(shù)據(jù)庫的有序集合,定義一些方法來實現(xiàn)分?jǐn)?shù)的設(shè)置,代理的獲取等等。

實現(xiàn)如下:

MAX_SCORE = 100
MIN_SCORE = 0
INITIAL_SCORE = 10
REDIS_HOST = 'localhost'
REDIS_PORT = 6379
REDIS_PASSWORD = None
REDIS_KEY = 'proxies'
 
import redis
from random import choice
 
class RedisClient(object):
    def __init__(self, host=REDIS_HOST, port=REDIS_PORT, password=REDIS_PASSWORD):
        """
        初始化
        :param host: Redis 地址
        :param port: Redis 端口
        :param password: Redis密碼
        """
        self.db = redis.StrictRedis(host=host, port=port, password=password, decode_responses=True)
 
    def add(self, proxy, score=INITIAL_SCORE):
        """
        添加代理,設(shè)置分?jǐn)?shù)為最高
        :param proxy: 代理
        :param score: 分?jǐn)?shù)
        :return: 添加結(jié)果
        """
        if not self.db.zscore(REDIS_KEY, proxy):
            return self.db.zadd(REDIS_KEY, score, proxy)
 
    def random(self):
        """
        隨機獲取有效代理,首先嘗試獲取最高分?jǐn)?shù)代理,如果不存在,按照排名獲取,否則異常
        :return: 隨機代理
        """
        result = self.db.zrangebyscore(REDIS_KEY, MAX_SCORE, MAX_SCORE)
        if len(result):
            return choice(result)
        else:
            result = self.db.zrevrange(REDIS_KEY, 0, 100)
            if len(result):
                return choice(result)
            else:
                raise PoolEmptyError
 
    def decrease(self, proxy):
        """
        代理值減一分,小于最小值則刪除
        :param proxy: 代理
        :return: 修改后的代理分?jǐn)?shù)
        """
        score = self.db.zscore(REDIS_KEY, proxy)
        if score and score > MIN_SCORE:
            print('代理', proxy, '當(dāng)前分?jǐn)?shù)', score, '減1')
            return self.db.zincrby(REDIS_KEY, proxy, -1)
        else:
            print('代理', proxy, '當(dāng)前分?jǐn)?shù)', score, '移除')
            return self.db.zrem(REDIS_KEY, proxy)
 
    def exists(self, proxy):
        """
        判斷是否存在
        :param proxy: 代理
        :return: 是否存在
        """
        return not self.db.zscore(REDIS_KEY, proxy) == None
 
    def max(self, proxy):
        """
        將代理設(shè)置為MAX_SCORE
        :param proxy: 代理
        :return: 設(shè)置結(jié)果
        """
        print('代理', proxy, '可用,設(shè)置為', MAX_SCORE)
        return self.db.zadd(REDIS_KEY, MAX_SCORE, proxy)
 
    def count(self):
        """
        獲取數(shù)量
        :return: 數(shù)量
        """
        return self.db.zcard(REDIS_KEY)
 
    def all(self):
        """
        獲取全部代理
        :return: 全部代理列表
        """
        return self.db.zrangebyscore(REDIS_KEY, MIN_SCORE, MAX_SCORE)

分享文章:Python3爬蟲如何維護代理池-創(chuàng)新互聯(lián)
分享網(wǎng)址:http://bm7419.com/article2/hddoc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護、關(guān)鍵詞優(yōu)化、Google微信公眾號、網(wǎng)站策劃靜態(tài)網(wǎng)站

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁設(shè)計公司