class Scaner(object): def __init__(self): self.db = Database(_DB_SETTINGS) self.db.table = _TABLE['standby'] self.rator = Rator(self.db) self.standby_data = [] def run(self): logger.info('Running Scanner.') self.rator.begin() loop = asyncio.get_event_loop() while 1: try: if self.standby_data: pen = len(self.standby_data) logger.info( 'Start the validation of the local "standby" database,length : %d ' % pen) pop_len = pen if pen <= LOCAL_AMOUNT else LOCAL_AMOUNT stanby_proxies = [ self.standby_data.pop() for x in range(pop_len) ] semaphore = asyncio.Semaphore(COROUTINE_MAX) logger.info( 'Start to verify the standby proxy data,amount: %d ' % pop_len) tasks = [ asyncio.ensure_future(self.validate(i, semaphore)) for i in stanby_proxies if i ] loop.run_until_complete(asyncio.gather(*tasks)) logger.info( 'Local validation finished.Left standby proxies:%d' % len(self.standby_data)) time.sleep(VALIDATE_LOCAL) else: self.standby_data = self.db.all() except Exception as e: logger.error('Error class : %s , msg : %s ' % (e.__class__, e)) self.rator.end() loop.close() logger.info('Scanner shuts down.') return async def validate(self, proxy, semaphore): ip = proxy['ip'] port = proxy['port'] # 可设置响应超时对API服务器请求代理,没写 async with semaphore: async with aiohttp.ClientSession() as session: try: async with session.get(proxy_validate_url.format(ip, port), headers=headers, timeout=15) as response: data = await response.text(encoding='utf-8') data = json.loads(data) except Exception as e: logger.error('Error class : %s , msg : %s ' % (e.__class__, e)) return else: res = data['msg'][0] if 'anony' in res and 'time' in res: proxy['anony_type'] = res['anony'] proxy['resp_time'] = res['time'] self.rator.mark_update(proxy, collected=False) else: self.rator.mark_fail(proxy)
class Scaner(object): """ 本地扫描器,对本地standby有效代理数据库中的数据进行周期验证 保证其以后调用数据的实时验证,通过内置打分器进行打分存储 """ def __init__(self): self.db = Database(_DB_SETTINGS) self.db.table = _TABLE['standby'] self.rator = Rator(self.db) self.standby_data = [] def check_allot(self, proxies): """ 将扫描器一次取出的要验证的本地standby数据库有效代理数据进行分组 分成几组则有多少个异步协程来验证IP代理数据,一组中有多少个代理IP 则一个协程一次验证的代理IP就有多少个。建议一次验证的IP数不要太多, 防止目标验证网站封掉本机IP,如果你已经爬取到一定数量的IP代理并存储 到standby或stable数据库中,则可以将数值设置大一点,最大不能超过100 如果是刚刚开始建立FooProxy数据库,则建议将offset设置为2,慢慢爬取建立 稳定数据库后,再设置大一点的数值。此处设置为20是因为我的本地数据库已经很大。 Q:为甚要有这个函数? A:前期因为使用单个IP代理对应一个异步协程验证,一次取出500个代理进行验证,经常被 目标验证网站http://www.moguproxy.com封掉IP或者断开连接,此时使用查询分组可以 减少一次性访问的异步协程的数量,但是如果offset值设置过大会引起目标验证网站的多线程 验证压力增大,被封IP的几率大大增加,所以设置一个合适的offset比较好。 Q:那究竟要多大啊这个offset? A:前期刚刚开始使用FooProxy项目来建立代理池的话,建议设为2,即是最小值了,此时不会增加目标网站 的多线程验证压力,不会引起注意,但是也要设置好一次取出的待验证IP代理数据的量,在config中设置 的LOCAL_AMOUNT,默认500,可以自己设置100或者更小,看自己需求,offse和LOCAL_AMOUNT这两个值 越大被封IP的几率越大,建议前期offset为2,后续代理池稳定下来可以设置更大的值。 Q:这么麻烦那我自己验证代理有效性不就行了? A:这是可以的。由于我比较懒,所以使用了验证网站的接口,也可以自己去访问一些验证服务器来判断返回的 头部内容,根据response headers中的内容确定匿名程度,以及响应时间。比如访问:http://httpbin.org/get?show_env=1 但是如果用这种办法,验证用的validate异步协程函数就要重写。 :param proxies:扫描器一次取出来的待验证本地standby有效数据库的代理IP列表,格式[{},{},..] :return:返回分组结果,格式 {'查询参数字符串':[{},{},..],'查询参数字符串':[{},{},..],..} 查询参数字符串对应的值为分组后的一组代理IP数据,dict类型 """ p_len = len(proxies) offset = 20 params_dict = {} if p_len <= offset: return { '&'.join([ 'ip_ports%5B%5D={}%3A{}'.format(i['ip'], i['port']) for i in proxies ]): proxies } else: base = math.ceil(p_len / offset) p_groups = [ proxies[i * offset:(i + 1) * offset] for i in range(base) ] for group in p_groups: url_str = '&'.join([ 'ip_ports%5B%5D={}%3A{}'.format(i['ip'], i['port']) for i in group ]) params_dict[url_str] = group return params_dict def run(self): """ 运行本地扫描器 """ logger.info('Running Scanner.') self.rator.begin() loop = asyncio.get_event_loop() while 1: try: if self.standby_data: pen = len(self.standby_data) logger.info( 'Start the validation of the local "standby" database,length : %d ' % pen) pop_len = pen if pen <= LOCAL_AMOUNT else LOCAL_AMOUNT stanby_proxies = [ self.standby_data.pop() for x in range(pop_len) ] prams_dict = self.check_allot(stanby_proxies) semaphore = asyncio.Semaphore(COROUTINE_MAX) logger.info( 'Start to verify the standby proxy data,amount: %d ' % pop_len) tasks = [ asyncio.ensure_future( self.validate(i, prams_dict[i], semaphore)) for i in prams_dict ] loop.run_until_complete(asyncio.gather(*tasks)) logger.info( 'Local validation finished.Left standby proxies:%d' % len(self.standby_data)) time.sleep(VALIDATE_LOCAL) else: self.standby_data = self.db.all() except Exception as e: logger.error('Error class : %s , msg : %s ' % (e.__class__, e)) self.rator.end() loop.close() logger.info('Scanner shuts down.') return async def validate(self, url_str, proxies, semaphore): """ 异步验证协程,对本地standby中的代理数据进行异步验证 :param url_str: IP代理分组中一个组的验证查询参数字符串 :param proxies: 查询参数字符串对应的IP代理组 :param semaphore: 协程最大并发量信号 """ _proxy = None async with semaphore: async with aiohttp.ClientSession() as session: while 1: try: async with session.get(mul_validate_url + url_str, headers=v_headers, proxy=_proxy) as response: data = await response.text(encoding='utf-8') data = json.loads(data) except Exception as e: _proxy = get_proxy(format=False) if not _proxy: logger.error( 'No available proxy to retry the request for validation.' ) return continue else: for res in data['msg']: proxy = find_proxy(res['ip'], res['port'], proxies) try: if 'anony' in res and 'time' in res: proxy['anony_type'] = res['anony'] proxy['resp_time'] = res['time'] self.rator.mark_update(proxy, collected=False) else: self.rator.mark_fail(proxy) except KeyError as e: logger.error('Error class : %s , msg : %s ' % (e.__class__, e)) continue return