55from proxypool .storages .redis import RedisClient
66from proxypool .setting import TEST_TIMEOUT , TEST_BATCH , TEST_URL , TEST_VALID_STATUS , TEST_ANONYMOUS , \
77 TEST_DONT_SET_MAX_SCORE
8- from aiohttp import ClientProxyConnectionError , ServerDisconnectedError , ClientOSError , ClientHttpProxyError
8+ from aiohttp import ClientProxyConnectionError , ServerDisconnectedError , ClientOSError , ClientHttpProxyError , \
9+ ClientResponseError , ContentTypeError
910from asyncio import TimeoutError
1011from proxypool .testers import __all__ as testers_cls
1112
1617 ServerDisconnectedError ,
1718 ClientOSError ,
1819 ClientHttpProxyError ,
20+ ClientResponseError ,
21+ ContentTypeError ,
1922 AssertionError
2023)
2124
@@ -30,83 +33,102 @@ def __init__(self):
3033 init redis
3134 """
3235 self .redis = RedisClient ()
33- self .loop = asyncio .get_event_loop ()
3436 self .testers_cls = testers_cls
3537 self .testers = [tester_cls () for tester_cls in self .testers_cls ]
3638
37- async def test (self , proxy : Proxy ):
39+ async def test (self , proxy : Proxy , session : aiohttp . ClientSession ):
3840 """
3941 test single proxy
4042 :param proxy: Proxy object
43+ :param session: shared aiohttp session
4144 :return:
4245 """
43- async with aiohttp .ClientSession (connector = aiohttp .TCPConnector (ssl = False )) as session :
44- try :
45- logger .debug (f'testing { proxy .string ()} ' )
46- # if TEST_ANONYMOUS is True, make sure that
47- # the proxy has the effect of hiding the real IP
48- # logger.debug(f'TEST_ANONYMOUS {TEST_ANONYMOUS}')
49- if TEST_ANONYMOUS :
50- url = 'https://httpbin.org/ip'
51- async with session .get (url , timeout = TEST_TIMEOUT ) as response :
52- resp_json = await response .json ()
53- origin_ip = resp_json ['origin' ]
54- # logger.debug(f'origin ip is {origin_ip}')
55- async with session .get (url , proxy = f'http://{ proxy .string ()} ' , timeout = TEST_TIMEOUT ) as response :
56- resp_json = await response .json ()
57- anonymous_ip = resp_json ['origin' ]
58- logger .debug (f'anonymous ip is { anonymous_ip } ' )
59- assert origin_ip != anonymous_ip
60- assert proxy .host == anonymous_ip
61- async with session .get (TEST_URL , proxy = f'http://{ proxy .string ()} ' , timeout = TEST_TIMEOUT ,
62- allow_redirects = False ) as response :
63- if response .status in TEST_VALID_STATUS :
64- if TEST_DONT_SET_MAX_SCORE :
65- logger .debug (
66- f'proxy { proxy .string ()} is valid, remain current score' )
67- else :
68- self .redis .max (proxy )
69- logger .debug (
70- f'proxy { proxy .string ()} is valid, set max score' )
46+ try :
47+ logger .debug (f'testing { proxy .string ()} ' )
48+ # if TEST_ANONYMOUS is True, make sure that
49+ # the proxy has the effect of hiding the real IP
50+ # logger.debug(f'TEST_ANONYMOUS {TEST_ANONYMOUS}')
51+ if TEST_ANONYMOUS :
52+ url = 'https://httpbin.org/ip'
53+ async with session .get (url , timeout = TEST_TIMEOUT ) as response :
54+ resp_json = await response .json ()
55+ origin_ip = resp_json ['origin' ]
56+ # logger.debug(f'origin ip is {origin_ip}')
57+ async with session .get (url , proxy = f'http://{ proxy .string ()} ' , timeout = TEST_TIMEOUT ) as response :
58+ resp_json = await response .json ()
59+ anonymous_ip = resp_json ['origin' ]
60+ logger .debug (f'anonymous ip is { anonymous_ip } ' )
61+ assert origin_ip != anonymous_ip
62+ assert proxy .host == anonymous_ip
63+ async with session .get (TEST_URL , proxy = f'http://{ proxy .string ()} ' , timeout = TEST_TIMEOUT ,
64+ allow_redirects = False ) as response :
65+ if response .status in TEST_VALID_STATUS :
66+ if TEST_DONT_SET_MAX_SCORE :
67+ logger .debug (
68+ f'proxy { proxy .string ()} is valid, remain current score' )
7169 else :
72- self .redis .decrease (proxy )
70+ self .redis .max (proxy )
7371 logger .debug (
74- f'proxy { proxy .string ()} is invalid, decrease score' )
75- # if independent tester class found, create new set of storage and do the extra test
76- for tester in self .testers :
77- key = tester .key
78- if self .redis .exists (proxy , key ):
79- test_url = tester .test_url
80- headers = tester .headers ()
81- cookies = tester .cookies ()
82- async with session .get (test_url , proxy = f'http://{ proxy .string ()} ' ,
83- timeout = TEST_TIMEOUT ,
84- headers = headers ,
85- cookies = cookies ,
86- allow_redirects = False ) as response :
87- resp_text = await response .text ()
88- is_valid = await tester .parse (resp_text , test_url , proxy .string ())
89- if is_valid :
90- if tester .test_dont_set_max_score :
91- logger .info (
92- f'key[{ key } ] proxy { proxy .string ()} is valid, remain current score' )
93- else :
94- self .redis .max (
95- proxy , key , tester .proxy_score_max )
96- logger .info (
97- f'key[{ key } ] proxy { proxy .string ()} is valid, set max score' )
72+ f'proxy { proxy .string ()} is valid, set max score' )
73+ else :
74+ self .redis .decrease (proxy )
75+ logger .debug (
76+ f'proxy { proxy .string ()} is invalid, decrease score' )
77+ # if independent tester class found, create new set of storage and do the extra test
78+ for tester in self .testers :
79+ key = tester .key
80+ if self .redis .exists (proxy , key ):
81+ test_url = tester .test_url
82+ headers = tester .headers ()
83+ cookies = tester .cookies ()
84+ async with session .get (test_url , proxy = f'http://{ proxy .string ()} ' ,
85+ timeout = TEST_TIMEOUT ,
86+ headers = headers ,
87+ cookies = cookies ,
88+ allow_redirects = False ) as response :
89+ resp_text = await response .text ()
90+ is_valid = await tester .parse (resp_text , test_url , proxy .string ())
91+ if is_valid :
92+ if tester .test_dont_set_max_score :
93+ logger .info (
94+ f'key[{ key } ] proxy { proxy .string ()} is valid, remain current score' )
9895 else :
99- self .redis .decrease (
100- proxy , tester . key , tester .proxy_score_min )
96+ self .redis .max (
97+ proxy , key , tester .proxy_score_max )
10198 logger .info (
102- f'key[{ key } ] proxy { proxy .string ()} is invalid, decrease score' )
99+ f'key[{ key } ] proxy { proxy .string ()} is valid, set max score' )
100+ else :
101+ self .redis .decrease (
102+ proxy , tester .key , tester .proxy_score_min )
103+ logger .info (
104+ f'key[{ key } ] proxy { proxy .string ()} is invalid, decrease score' )
103105
104- except EXCEPTIONS :
105- self .redis .decrease (proxy )
106- [self .redis .decrease (proxy , tester .key , tester .proxy_score_min )
107- for tester in self .testers ]
106+ except EXCEPTIONS :
107+ self .redis .decrease (proxy )
108+ [self .redis .decrease (proxy , tester .key , tester .proxy_score_min )
109+ for tester in self .testers ]
110+ logger .debug (
111+ f'proxy { proxy .string ()} is invalid, decrease score' )
112+
113+ async def run_tests (self ):
114+ """
115+ test all proxies in batches, reusing a single aiohttp session
116+ :return:
117+ """
118+ count = self .redis .count ()
119+ logger .debug (f'{ count } proxies to test' )
120+ cursor = 0
121+ connector = aiohttp .TCPConnector (ssl = False , limit = TEST_BATCH )
122+ async with aiohttp .ClientSession (connector = connector ) as session :
123+ while True :
108124 logger .debug (
109- f'proxy { proxy .string ()} is invalid, decrease score' )
125+ f'testing proxies use cursor { cursor } , count { TEST_BATCH } ' )
126+ cursor , proxies = self .redis .batch (cursor , count = TEST_BATCH )
127+ if proxies :
128+ tasks = [self .test (proxy , session ) for proxy in proxies ]
129+ await asyncio .gather (* tasks , return_exceptions = True )
130+ if not cursor :
131+ break
110132
111133 @logger .catch
112134 def run (self ):
@@ -116,26 +138,29 @@ def run(self):
116138 """
117139 # event loop of aiohttp
118140 logger .info ('stating tester...' )
119- count = self .redis .count ()
120- logger .debug (f'{ count } proxies to test' )
121- cursor = 0
122- while True :
123- logger .debug (
124- f'testing proxies use cursor { cursor } , count { TEST_BATCH } ' )
125- cursor , proxies = self .redis .batch (cursor , count = TEST_BATCH )
126- if proxies :
127- tasks = [self .loop .create_task (
128- self .test (proxy )) for proxy in proxies ]
129- self .loop .run_until_complete (asyncio .wait (tasks ))
130- if not cursor :
131- break
141+ loop = asyncio .new_event_loop ()
142+ asyncio .set_event_loop (loop )
143+ try :
144+ loop .run_until_complete (self .run_tests ())
145+ finally :
146+ loop .close ()
132147
133148
134149def run_tester ():
135150 host = '96.113.165.182'
136151 port = '3128'
137- tasks = [tester .test (Proxy (host = host , port = port ))]
138- tester .loop .run_until_complete (asyncio .wait (tasks ))
152+ tester = Tester ()
153+
154+ async def _test ():
155+ async with aiohttp .ClientSession (connector = aiohttp .TCPConnector (ssl = False )) as session :
156+ await tester .test (Proxy (host = host , port = port ), session )
157+
158+ loop = asyncio .new_event_loop ()
159+ asyncio .set_event_loop (loop )
160+ try :
161+ loop .run_until_complete (_test ())
162+ finally :
163+ loop .close ()
139164
140165
141166if __name__ == '__main__' :
0 commit comments