| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- import time
- from multiprocessing import Process
- import asyncio
- import aiohttp
- from proxypool.db import RedisClient
- from proxypool.error import ResourceDepletionError
- from proxypool.getter import FreeProxyGetter
- from proxypool.setting import *
- class ValidityTester(object):
- """
- 检验器,负责对未知的代理进行异步检测。
- """
- # 用百度的首页来检验
- test_api = TEST_API
- def __init__(self):
- self._raw_proxies = None
- self._usable_proxies = []
- def set_raw_proxies(self, proxies):
- """
- 设置待检测的代理。
- """
- self._raw_proxies = proxies
- self._usable_proxies = []
- async def test_single_proxy(self, proxy):
- """
- 检测单个代理,如果可用,则将其加入_usable_proxies
- """
- async with aiohttp.ClientSession() as session:
- try:
- real_proxy = 'http://' + proxy
- print('Testing', real_proxy)
- async with session.get(self.test_api, proxy=real_proxy, timeout=15) as response:
- await response
- self._usable_proxies.append(proxy)
- print('Valid proxy', proxy)
- except Exception:
- print('Invalid proxy', proxy)
- def test(self):
- """
- 异步检测_raw_proxies中的全部代理。
- """
- print('ValidityTester is working')
- loop = asyncio.get_event_loop()
- tasks = [self.test_single_proxy(proxy) for proxy in self._raw_proxies]
- loop.run_until_complete(asyncio.wait(tasks))
- def get_usable_proxies(self):
- return self._usable_proxies
- class PoolAdder(object):
- """
- 添加器,负责向池中补充代理
- """
- def __init__(self, threshold):
- self._threshold = threshold
- self._conn = RedisClient()
- self._tester = ValidityTester()
- self._crawler = FreeProxyGetter()
- def is_over_threshold(self):
- """
- 判断代理池中的数据量是否达到阈值。
- """
- if self._conn.queue_len >= self._threshold:
- return True
- else:
- return False
- def add_to_queue(self):
- """
- 命令爬虫抓取一定量未检测的代理,然后检测,将通过检测的代理
- 加入到代理池中。
- """
- print('PoolAdder is working')
- proxy_count = 0
- if 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)
- proxy_count += len(raw_proxies)
- if proxy_count == 0:
- raise ResourceDepletionError
- class Schedule(object):
- """
- 总调度器,用于协调各调度器模块
- """
- @staticmethod
- def valid_proxy(cycle=VALID_CHECK_CYCLE):
- """
- 对已经如池的代理进行检测,防止池中的代理因长期
- 不使用而过期。
- 抽出代理池队列中前1/4的代理,检测,合格者压入队列尾。
- """
- conn = RedisClient()
- tester = ValidityTester()
- while True:
- time.sleep(cycle)
- count = int(0.25 * conn.queue_len)
- if count == 0:
- continue
- raw_proxies = conn.get(count)
- tester.set_raw_proxies(raw_proxies)
- tester.test()
- proxies = tester.get_usable_proxies()
- conn.put_many(proxies)
- @staticmethod
- def check_pool(lower_threshold=POOL_LOWER_THRESHOLD,
- upper_threshold=POOL_UPPER_THRESHOLD,
- cycle=POOL_LEN_CHECK_CYCLE):
- """
- 协调添加器,当代理池中可用代理的数量低于下阈值时,触发添加器,启动爬虫
- 补充代理,当代理达到上阈值时,添加器停止工作。
- """
- conn = RedisClient()
- adder = PoolAdder(upper_threshold)
- while True:
- if conn.queue_len < lower_threshold:
- adder.add_to_queue()
- time.sleep(cycle)
- def run(self):
- """
- 运行调度器,创建两个进程,对代理池进行维护。
- """
- valid_process = Process(target=Schedule.valid_proxy)
- check_process = Process(target=Schedule.check_pool)
- valid_process.start()
- check_process.start()
|