爬蟲基礎 -- 用Flask+Redis維護代理池

因爲在爬蟲的時候經常經常會遇到封IP 的情況,那麼使用代理就可以解決這個問題。

池子裏面放一些代理,而且需要定期的檢查。


互聯網上公開了大量的免費代理,而且互聯網上也有付費的代理。


代理池的要求:

1.多站抓取,異步檢測

2.定時篩選,持續更新

3.提供接口,易於提取


代理池的架構



開始搭建代理池。

主要是借鑑 github上Germey的代理池的實現

https://github.com/germey/proxypool


下面看看介紹一下源碼。其實我也是看作者的視頻學習他的代碼的。


def main():

    s = Schedule()
    s.run()
    app.run()


代碼在 run.py 中首先實例化了一個 調度器。 並且執行了run()方法。。


s.run() 是運行調度器,和檢驗,添加,刪去代理相關。

app.run() 是啓動起來flask框架。提供api接口相關的。實例化一個redisclient對象。並且可以調用redis的相關方法。

先說一下 redis的處理函數:

get()   從隊列左側拿出一個代理

put()   從隊列右側放進去一個代理

pop()   從右側彈出一個代理

queue_len()  獲得隊列長度

flush()  清空隊列


講解一下Schedule調度器的實現。


下面的代碼是 Schedule調度器的代碼:

class Schedule(object):
    @staticmethod
    def valid_proxy(cycle=VALID_CHECK_CYCLE):
        """
        Get half of proxies which in redis
        """
        conn = RedisClient()
        tester = ValidityTester()
        while True:
            print('Refreshing ip')
            count = int(0.5 * conn.queue_len)
            if count == 0:
                print('Waiting for adding')
                time.sleep(cycle)
                continue
            raw_proxies = conn.get(count)
            tester.set_raw_proxies(raw_proxies)
            tester.test()
            time.sleep(cycle)

    @staticmethod
    def check_pool(lower_threshold=POOL_LOWER_THRESHOLD,
                   upper_threshold=POOL_UPPER_THRESHOLD,
                   cycle=POOL_LEN_CHECK_CYCLE):
        """
        If the number of proxies less than lower_threshold, add proxy
        """
        conn = RedisClient()
        adder = PoolAdder(upper_threshold)
        while True:
            if conn.queue_len < lower_threshold:
                adder.add_to_queue()
            time.sleep(cycle)

    def run(self):
        print('Ip processing running')
        valid_process = Process(target=Schedule.valid_proxy)
        check_process = Process(target=Schedule.check_pool)
        valid_process.start()
        check_process.start()


執行了run方法之後,開啓了兩個進程。

一個是定時檢測 代理池中的 ip是否有效,另一個是檢測池子中的ip個數是否滿足要求。



第一個 方法: 定時檢測代理池中的ip是否有效 。

def valid_proxy(cycle=VALID_CHECK_CYCLE):  是定時檢測方法。其中的VALID_CHECK_CYCLE 是循環檢測的週期間隔。

valid_proxy 方法在實例化連接redis之後,又實例化了一個檢測是否有效的一個類。每次取出一半隊列長度的代理。


具體的檢測過程是在以下代碼實現的。(這是一個異步檢測。py3.6  )

async def test_single_proxy(self, proxy):
        """
        text one proxy, if valid, put them to usable_proxies.
        """
        try:
            async with aiohttp.ClientSession() as session:
                try:
                    if isinstance(proxy, bytes):
                        proxy = proxy.decode('utf-8')
                    real_proxy = 'http://' + proxy
                    print('Testing', proxy)
                    async with session.get(self.test_api, proxy=real_proxy, timeout=get_proxy_timeout) as response:
                        if response.status == 200:
                            self._conn.put(proxy)
                            print('Valid proxy', proxy)
                except (ProxyConnectionError, TimeoutError, ValueError):
                    print('Invalid proxy', proxy)
        except (ServerDisconnectedError, ClientResponseError,ClientConnectorError) as s:
            print(s)
            pass


第二個 方法 : 檢測代理池中的代理ip是否夠用。不夠的話,就向一些代理網站上取一些代理ip。並且檢驗有效之後就添加進到代理池。

    def add_to_queue(self):
        print('PoolAdder is working')
        proxy_count = 0
        while not self.is_over_threshold():
            for callback_label in range(self._crawler.__CrawlFuncCount__):
                callback = self._crawler.__CrawlFunc__[callback_label]
                raw_proxies = self._crawler.get_raw_proxies(callback)
                # test crawled proxies
                self._tester.set_raw_proxies(raw_proxies)
                self._tester.test()
                proxy_count += len(raw_proxies)
                if self.is_over_threshold():
                    print('IP is enough, waiting to be used')
                    break
            if proxy_count == 0:
                raise ResourceDepletionError

這裏的 for callback_label in range(self._crawler.__CrawlFuncCount__): 是一個很厲害的實現。


他將getter.py裏的關於得到代理ip的網站的函數放到列表裏。然後挨個執行一遍。具體實現如下

    """
        元類,在FreeProxyGetter類中加入
        __CrawlFunc__和__CrawlFuncCount__
        兩個參數,分別表示爬蟲函數,和爬蟲函數的數量。
    """
    def __new__(cls, name, bases, attrs):
        count = 0
        attrs['__CrawlFunc__'] = []
        for k, v in attrs.items():
            if 'crawl_' in k:
                attrs['__CrawlFunc__'].append(k)
                count += 1
        attrs['__CrawlFuncCount__'] = count
        return type.__new__(cls, name, bases, attrs)

如果還想添加一個網站的抓取。


只要再添加一個crawl_開頭的一個方法就好了。






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