proxy-reader 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of proxy-reader might be problematic. Click here for more details.

proxy_reader/logger.py ADDED
@@ -0,0 +1,21 @@
1
+
2
+
3
+ import logging
4
+ from logging.handlers import RotatingFileHandler
5
+
6
+ filename = "proxy_reader.log"
7
+ logging_format = logging.Formatter(
8
+ "%(levelname)s:[%(filename)s:%(lineno)s]:%(asctime)s: %(message)s")
9
+ logger = logging.getLogger(__name__)
10
+ console_handler = logging.StreamHandler()
11
+ console_handler.setFormatter(logging_format)
12
+ file_handler = RotatingFileHandler(filename, mode='a', maxBytes=5 * 1024 * 1024,
13
+ backupCount=2, encoding="utf-8", delay=False)
14
+ file_handler.setFormatter(logging_format)
15
+
16
+ logger.setLevel(logging.DEBUG)
17
+ file_handler.setLevel(logging.DEBUG)
18
+ console_handler.setLevel(logging.DEBUG)
19
+
20
+ logger.addHandler(console_handler)
21
+ logger.addHandler(file_handler)
File without changes
@@ -0,0 +1,106 @@
1
+ from typing import List, Optional, Dict, Any, Protocol
2
+ from .._types import ProxiesList
3
+ from ..proxy import Proxy
4
+
5
+
6
+ class ProxiesReaderProtocol(Protocol):
7
+ @property
8
+ def total(self) -> int:
9
+ pass
10
+
11
+ @property
12
+ def total_working(self) -> int:
13
+ pass
14
+
15
+ @property
16
+ def total_bad(self) -> int:
17
+ pass
18
+
19
+ @property
20
+ def proxies(self) -> ProxiesList:
21
+ pass
22
+
23
+ @property
24
+ def bad_proxies(self) -> ProxiesList:
25
+ pass
26
+
27
+ @property
28
+ def working_proxies(self) -> ProxiesList:
29
+ pass
30
+
31
+ @working_proxies.setter
32
+ def working_proxies(self, working_proxies: List[Proxy]) -> None:
33
+ pass
34
+
35
+ def read_raw(self) -> List[str]:
36
+ pass
37
+
38
+ def random_url(self) -> str:
39
+ pass
40
+
41
+ def read_with_auth(self) -> None:
42
+ pass
43
+
44
+ def read_authless(self) -> None:
45
+ pass
46
+
47
+ async def _check_proxy(
48
+ self, proxy: Proxy, response_time: Optional[int] = None
49
+ ) -> bool:
50
+ pass
51
+
52
+ async def check_all_proxies(self, max_resp_time: int = 30) -> None:
53
+ pass
54
+
55
+ async def _check_proxy_socks(
56
+ self, proxy: Proxy, response_time: Optional[int] = None
57
+ ) -> bool:
58
+ pass
59
+
60
+ async def check_all_proxies_socks5(self, max_resp_time: int = 5) -> None:
61
+ pass
62
+
63
+ def get_working_proxies_list_http(self) -> List[str]:
64
+ pass
65
+
66
+ def write_working_proxies(self, filename: str) -> None:
67
+ pass
68
+
69
+ def get_random_http(self) -> Optional[str]:
70
+ pass
71
+
72
+ def get_random_socks5(self) -> Optional[str]:
73
+ pass
74
+
75
+ def get_random_socks5_telegram(self) -> Optional[Dict[str, Any]]:
76
+ pass
77
+
78
+ def next_http_from_list(self) -> Optional[str]:
79
+ pass
80
+
81
+ def next_http_from_cycle(self) -> str:
82
+ pass
83
+
84
+ def next_socks5_from_list(self) -> str:
85
+ pass
86
+
87
+ def next_socks5_from_cycle(self) -> str:
88
+ pass
89
+
90
+ def next_http_telegram_from_list(self) -> Dict[str, Any]:
91
+ pass
92
+
93
+ def next_http_telegram_from_cycle(self) -> Dict[str, Any]:
94
+ pass
95
+
96
+ def next_socks5_telegram_from_cycle(self) -> Dict[str, Any]:
97
+ pass
98
+
99
+ def next_socks5_telegram_from_list(self) -> Dict[str, Any]:
100
+ pass
101
+
102
+ def next_https_from_list(self) -> str:
103
+ pass
104
+
105
+ def next_https_from_cycle(self) -> str:
106
+ pass
proxy_reader/proxy.py ADDED
@@ -0,0 +1,78 @@
1
+ from typing import Optional, Dict, Any
2
+
3
+
4
+ class Proxy:
5
+ def __init__(self, ip: str, port: str, username: Optional[str] = None, password: Optional[str] = None) -> None:
6
+ self._ip = ip
7
+ self._port = port
8
+ self._username = username
9
+ self._password = password
10
+
11
+ @property
12
+ def ip(self) -> str:
13
+ return self._ip
14
+
15
+ @property
16
+ def port(self) -> str:
17
+ return self._port
18
+
19
+ @property
20
+ def username(self) -> Optional[str]:
21
+ return self._username
22
+
23
+ @property
24
+ def password(self) -> Optional[str]:
25
+ return self._password
26
+
27
+ @property
28
+ def http(self) -> str:
29
+ if self.username and self.password:
30
+ return f"http://{self._username}:{self._password}@{self._ip}:{self._port}"
31
+ return f"http://{self._ip}:{self._port}"
32
+
33
+ @property
34
+ def https(self) -> str:
35
+ if self.username and self.password:
36
+ return f"https://{self._username}:{self._password}@{self._ip}:{self._port}"
37
+ return f"https://{self._ip}:{self._port}"
38
+
39
+ @property
40
+ def telegram_http(self) -> Dict[str, Any]:
41
+ p = {"proxy_type": 3, "addr": self._ip, "port": int(self._port)}
42
+ if self.username and self.password:
43
+ p.update({"username": self.username, "password": self.password})
44
+ return p
45
+
46
+ @property
47
+ def telegram_socks5(self) -> Dict[str, Any]:
48
+ p = {"proxy_type": 2, "addr": self._ip, "port": int(self._port)}
49
+ if self.username and self.password:
50
+ p.update({"username": self.username, "password": self.password})
51
+ return p
52
+
53
+ @property
54
+ def telegram_socks4(self) -> Dict[str, Any]:
55
+ p = {"proxy_type": 1, "addr": self._ip, "port": int(self._port)}
56
+ if self.username and self.password:
57
+ p.update({"username": self.username, "password": self.password})
58
+ return p
59
+
60
+ @property
61
+ def socks5(self) -> str:
62
+ if self._username is not None and self._password is not None:
63
+ return f"socks5://{self._username}:{self._password}@{self.ip}:{self.port}"
64
+ return f"socks5://{self.ip}:{self.port}"
65
+
66
+ @property
67
+ def socks4(self) -> str:
68
+ if self._username is not None and self._password is not None:
69
+ return f"socks4://{self._username}:{self._password}@{self.ip}:{self.port}"
70
+ return f"socks4://{self.ip}:{self.port}"
71
+
72
+ def __str__(self) -> str:
73
+ if self._username is not None and self._password is not None:
74
+ return f"{self._ip}:{self._port}:{self._username}:{self._password}"
75
+ return f"{self._ip}:{self._port}"
76
+
77
+ def __repr__(self) -> str:
78
+ return self.__str__()
proxy_reader/py.typed ADDED
File without changes
proxy_reader/reader.py ADDED
@@ -0,0 +1,361 @@
1
+ import random
2
+ import itertools
3
+ from .proxy import Proxy
4
+ import aiohttp
5
+ import asyncio
6
+ from .logger import logger, console_handler, file_handler
7
+ import os
8
+ from aiohttp_socks import ProxyConnector
9
+ import sys
10
+ from typing import Optional, List, Dict, Any
11
+ from ._types import ProxiesList, ProxyiesGen
12
+ from .protocols.reader import ProxiesReaderProtocol
13
+
14
+
15
+ class ProxiesReader(ProxiesReaderProtocol):
16
+ def __init__(
17
+ self,
18
+ file_path: str = "proxies.txt",
19
+ shuffle: bool = False,
20
+ debug: bool = False,
21
+ extra_debug: bool = False,
22
+ ) -> None:
23
+ self._file_path = file_path
24
+ self._debug = debug
25
+ self._extra_debug = extra_debug
26
+
27
+ self._shuffle = shuffle
28
+ self._proxies: ProxiesList = []
29
+ self._has_auth = False
30
+ self._bad_proxies: ProxiesList = []
31
+ self._working_proxies: ProxiesList = []
32
+ self._proxies_checked = False
33
+ self._proxy_iterator: Optional[ProxyiesGen] = None
34
+ self._proxy_iterator_cycle: Optional[ProxyiesGen] = None
35
+ self._thread_control: asyncio.Semaphore = asyncio.Semaphore(500)
36
+ self._max_response_time = 60
37
+ self._timeout_count = 0
38
+
39
+ self._check_urls = [
40
+ # New
41
+ "http://checkip.amazonaws.com",
42
+ "http://ipinfo.io/ip",
43
+ "http://icanhazip.com",
44
+ "http://api.ipify.org",
45
+ "http://ifconfig.co/ip",
46
+ # "http://ipapi.co/ip",
47
+ "http://ident.me",
48
+ "http://api64.ipify.org?format=json",
49
+ "http://ifconfig.me/ip",
50
+ "http://www.trackip.net/ip",
51
+ # "http://api.adviceslip.com/advice",
52
+ # "http://api.thecatapi.com/v1/images/search",
53
+ # "http://dog.ceo/api/breeds/image/random",
54
+ ]
55
+
56
+ if not self._debug:
57
+ logger.removeHandler(file_handler)
58
+ logger.removeHandler(console_handler)
59
+ try:
60
+ os.remove(file_handler.baseFilename)
61
+ except Exception:
62
+ pass
63
+
64
+ @property
65
+ def total(self) -> int:
66
+ return len(self._proxies)
67
+
68
+ @property
69
+ def total_working(self) -> int:
70
+ return len(self._working_proxies)
71
+
72
+ @property
73
+ def total_bad(self) -> int:
74
+ return len(self._bad_proxies)
75
+
76
+ @property
77
+ def proxies(self) -> ProxiesList:
78
+ return self._proxies
79
+
80
+ @property
81
+ def bad_proxies(self) -> ProxiesList:
82
+ return self._bad_proxies
83
+
84
+ @property
85
+ def working_proxies(self) -> ProxiesList:
86
+ return self._working_proxies
87
+
88
+ @working_proxies.setter
89
+ def working_proxies(self, working_proxies: list[Proxy]) -> None:
90
+ self._working_proxies = working_proxies
91
+
92
+ def __str__(self) -> str:
93
+ return str(self._proxies)
94
+
95
+ def __repr__(self) -> str:
96
+ return self.__str__()
97
+
98
+ def read_raw(self) -> List[str]:
99
+ lines = open(self._file_path).readlines()
100
+ return [line.strip().replace("\n", "") for line in lines]
101
+
102
+ def random_url(self) -> str:
103
+ return random.choice(self._check_urls)
104
+
105
+ def read_with_auth(self) -> None:
106
+ """Format: IP:PORT:USERNAME:PASSWORD"""
107
+ raw_proxies = self.read_raw()
108
+ for proxy in raw_proxies:
109
+ sp_proxy = proxy.split(":")
110
+ ip = sp_proxy[0]
111
+ port = sp_proxy[1]
112
+ username = sp_proxy[2]
113
+ password = sp_proxy[3]
114
+ self._proxies.append(Proxy(ip, port, username, password))
115
+
116
+ self._has_auth = True
117
+ if self._shuffle:
118
+ random.shuffle(self._proxies)
119
+
120
+ def read_authless(self) -> None:
121
+ """Format: IP:PORT"""
122
+ raw_proxies = self.read_raw()
123
+ for proxy in raw_proxies:
124
+ sp_proxy = proxy.split(":")
125
+ ip = sp_proxy[0]
126
+ port = sp_proxy[1]
127
+ self._proxies.append(Proxy(ip, port))
128
+ logger.debug(
129
+ f"Loaded total {len(self._proxies)} proxies from {self._file_path}"
130
+ )
131
+ if self._shuffle:
132
+ random.shuffle(self._proxies)
133
+
134
+ async def _check_proxy(
135
+ self, proxy: Proxy, response_time: Optional[int] = None
136
+ ) -> bool:
137
+ connectins_limit = 60 if "win" in sys.platform else 100
138
+ connector = aiohttp.TCPConnector(limit=connectins_limit)
139
+ session = aiohttp.ClientSession(connector=connector)
140
+ url = self.random_url()
141
+ p = proxy.http
142
+
143
+ async with self._thread_control:
144
+ logger.debug(f"Checking proxy {p} ..")
145
+ try:
146
+ # resp = await asyncio.wait_for(session.get(url, proxy=p), timeout=self._max_response_time)
147
+ resp = await session.get(
148
+ url,
149
+ timeout=aiohttp.ClientTimeout(self._max_response_time),
150
+ proxy=p,
151
+ ssl=False,
152
+ )
153
+ # await resp.read()
154
+
155
+ except asyncio.TimeoutError as e:
156
+ self._timeout_count += 1
157
+ logger.debug(f"{p} : TIMEOUT {e}. {url}")
158
+ self._bad_proxies.append(proxy)
159
+ await session.close()
160
+ return False
161
+
162
+ except Exception as e:
163
+ logger.debug(f"Bad proxy raised. {e}", exc_info=self._extra_debug)
164
+ await session.close()
165
+ return False
166
+
167
+ if resp.status == 200:
168
+ logger.debug(f"{p}: Working")
169
+ self._working_proxies.append(proxy)
170
+
171
+ else:
172
+ logger.debug(f"{p}: Not Working. Response code: {resp.status}")
173
+ self._bad_proxies.append(proxy)
174
+
175
+ return True
176
+
177
+ async def check_all_proxies(self, max_resp_time: int = 30) -> None:
178
+ """Run this to check all proxies at once."""
179
+ tasks: List[asyncio.Task[bool]] = []
180
+ for proxy in self._proxies:
181
+ tasks.append(asyncio.create_task(self._check_proxy(proxy, max_resp_time)))
182
+ await asyncio.gather(*tasks)
183
+ self._proxies_checked = True
184
+ logger.debug("All proxies checked.")
185
+
186
+ async def _check_proxy_socks(
187
+ self, proxy: Proxy, response_time: Optional[int] = None
188
+ ) -> bool:
189
+ url = self.random_url()
190
+ socks_connector = ProxyConnector.from_url(proxy.socks5) # type: ignore
191
+ session = aiohttp.ClientSession(connector=socks_connector)
192
+ logger.debug(f"Checking proxy {proxy} ..")
193
+ try:
194
+ resp = await asyncio.wait_for(session.get(url), timeout=response_time)
195
+
196
+ except asyncio.TimeoutError:
197
+ logger.debug(f"{proxy} : TIMEOUT: Not working.")
198
+ self._bad_proxies.append(proxy)
199
+ await session.close()
200
+ return False
201
+
202
+ except Exception as e:
203
+ logger.debug(f"Bad proxy raised. {e}", exc_info=self._extra_debug)
204
+ await session.close()
205
+ return False
206
+
207
+ await resp.read()
208
+ await session.close()
209
+ if resp.status == 200:
210
+ logger.debug(f"{proxy}: Working")
211
+ self._working_proxies.append(proxy)
212
+ else:
213
+ logger.debug(f"{proxy}: Not Working")
214
+ self._bad_proxies.append(proxy)
215
+
216
+ return True
217
+
218
+ async def check_all_proxies_socks5(self, max_resp_time: int = 5) -> None:
219
+ """Run the check on all proxies at once."""
220
+ tasks: List[asyncio.Task[bool]] = []
221
+ for proxy in self._proxies:
222
+ tasks.append(
223
+ asyncio.create_task(self._check_proxy_socks(proxy, max_resp_time))
224
+ )
225
+ await asyncio.gather(*tasks)
226
+ self._proxies_checked = True
227
+ logger.debug("All proxies checked.")
228
+
229
+ def get_working_proxies_list_http(self) -> List[str]:
230
+ working_list: List[str] = []
231
+ for proxy in self._working_proxies:
232
+ working_list.append(proxy.http)
233
+ return working_list
234
+
235
+ def write_working_proxies(self, filename: str) -> None:
236
+ working_list = self.get_working_proxies_list_http()
237
+ logger.debug(working_list)
238
+ with open(filename, "w") as f:
239
+ f.write("\n".join([proxy.strip() for proxy in working_list]))
240
+ logger.debug(f"Proxies written to: {filename}")
241
+
242
+ def get_random_http(self) -> Optional[str]:
243
+ _p = None
244
+ if len(self._working_proxies) > 0:
245
+ proxy = random.choice(self._working_proxies)
246
+ _p = proxy.http
247
+ return _p
248
+
249
+ def get_random_socks5(self) -> Optional[str]:
250
+ _p = None
251
+ if len(self._working_proxies) > 0:
252
+ proxy = random.choice(self._working_proxies)
253
+ _p = proxy.socks5
254
+ return _p
255
+
256
+ def get_random_socks5_telegram(self) -> Optional[Dict[str, Any]]:
257
+ _p = None
258
+ if len(self._working_proxies) > 0:
259
+ proxy = random.choice(self._working_proxies)
260
+ _p = proxy.telegram_socks5
261
+ return _p
262
+
263
+ def next_http_from_list(self) -> Optional[str]:
264
+ """Get next proxy from proxies list"""
265
+
266
+ def __iter() -> ProxyiesGen:
267
+ for proxy in self._working_proxies:
268
+ yield proxy
269
+
270
+ if self._proxy_iterator is None:
271
+ self._proxy_iterator = __iter()
272
+
273
+ return str(next(self._proxy_iterator).http)
274
+
275
+ def next_http_from_cycle(self) -> str:
276
+ """Get next proxy from proxies cycle"""
277
+
278
+ def __iter() -> ProxyiesGen:
279
+ for proxy in itertools.cycle(self._working_proxies):
280
+ yield proxy
281
+
282
+ if self._proxy_iterator_cycle is None:
283
+ self._proxy_iterator_cycle = __iter()
284
+
285
+ return str(next(self._proxy_iterator_cycle).http)
286
+
287
+ def next_socks5_from_list(self) -> str:
288
+ """Get next proxy from proxies list"""
289
+
290
+ if self._proxy_iterator is None:
291
+ self._proxy_iterator = self.__proxies_gen(self._working_proxies)
292
+ return str(next(self._proxy_iterator).socks5)
293
+
294
+ def next_socks5_from_cycle(self) -> str:
295
+ """Get next proxy from proxies cycle"""
296
+
297
+ if self._proxy_iterator_cycle is None:
298
+ self._proxy_iterator_cycle = self.__proxies_gen(
299
+ self._working_proxies, cycle_proxies=True
300
+ )
301
+ return str(next(self._proxy_iterator_cycle).socks5)
302
+
303
+ def next_http_telegram_from_list(self) -> Dict[str, Any]:
304
+ """Get next proxy from proxies list"""
305
+
306
+ if self._proxy_iterator is None:
307
+ self._proxy_iterator = self.__proxies_gen(self._working_proxies)
308
+ return dict(next(self._proxy_iterator).telegram_http)
309
+
310
+ def next_http_telegram_from_cycle(self) -> Dict[str, Any]:
311
+ """Get next proxy from proxies cycle"""
312
+
313
+ if self._proxy_iterator is None:
314
+ self._proxy_iterator = self.__proxies_gen(
315
+ self._working_proxies, cycle_proxies=True
316
+ )
317
+ return dict(next(self._proxy_iterator).telegram_http)
318
+
319
+ def next_socks5_telegram_from_cycle(self) -> Dict[str, Any]:
320
+ """Get next proxy from proxies cycle"""
321
+ if self._proxy_iterator_cycle is None:
322
+ self._proxy_iterator_cycle = self.__proxies_gen(
323
+ self._working_proxies, cycle_proxies=True
324
+ )
325
+ return dict(next(self._proxy_iterator_cycle).telegram_socks5)
326
+
327
+ def next_socks5_telegram_from_list(self) -> Dict[str, Any]:
328
+ """Get next proxy from proxies cycle"""
329
+
330
+ if self._proxy_iterator_cycle is None:
331
+ self._proxy_iterator_cycle = self.__proxies_gen(self._working_proxies)
332
+ return dict(next(self._proxy_iterator_cycle).telegram_socks5)
333
+
334
+ def next_https_from_list(self) -> str:
335
+ """Get next proxy from proxies list"""
336
+
337
+ if self._proxy_iterator is None:
338
+ self._proxy_iterator = self.__proxies_gen(self._working_proxies)
339
+
340
+ return str(next(self._proxy_iterator).https)
341
+
342
+ def next_https_from_cycle(self) -> str:
343
+ """Get next proxy from proxies cycle"""
344
+
345
+ if not self._proxy_iterator_cycle:
346
+ self._proxy_iterator_cycle = self.__proxies_gen(
347
+ self._working_proxies, cycle_proxies=True
348
+ )
349
+
350
+ return str(next(self._proxy_iterator_cycle).https)
351
+
352
+ def __proxies_gen(
353
+ self, proxies_list: List[Proxy], cycle_proxies: bool = False
354
+ ) -> ProxyiesGen:
355
+ if cycle_proxies:
356
+ for proxy in itertools.cycle(self._working_proxies):
357
+ yield proxy
358
+
359
+ else:
360
+ for proxy in proxies_list:
361
+ yield proxy
@@ -0,0 +1,8 @@
1
+ The MIT License (MIT)
2
+ Copyright © 2024 Rune Tech
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5
+
6
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7
+
8
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,33 @@
1
+ Metadata-Version: 2.1
2
+ Name: proxy-reader
3
+ Version: 0.1.0
4
+ Summary: Read and check bulk proxies effectively
5
+ Author-email: Rune Tech <runetech2024@gmail.com>
6
+ License: The MIT License (MIT)
7
+ Copyright © 2024 Rune Tech
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
14
+ Project-URL: Homepage, https://github.com/runetech0/proxy-reader
15
+ Project-URL: github, https://github.com/runetech0/proxy-reader
16
+ Keywords: proxies,proxy,reader,checker,bulk
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Requires-Dist: aiohttp >=3.10.10
21
+ Requires-Dist: aiohttp-socks >=0.9.0
22
+
23
+
24
+
25
+
26
+ # proxy_reader - A simple but useful bulk proxies reader and checker.
27
+
28
+ This is useful when you are working with multiple proxies and want to bulk check
29
+ these proxies before using them.
30
+ It has iterators to iterate the proxies for easy reading.
31
+
32
+
33
+ ## Changelogs
@@ -0,0 +1,14 @@
1
+ proxy_reader/__init__.py,sha256=8_HgszorTyU_0OJmvxgimP9S21y07s9R1n_U-wHMwTs,46
2
+ proxy_reader/_types.py,sha256=OWAYiN91E_IWgs1myPy1Q9l-8XkVVq8uDzjLOTB_Eww,317
3
+ proxy_reader/domains.py,sha256=d4FUb2zw3Kg9bAjtaggEcxZA293WvVcRTgMKKPmYr1A,135662
4
+ proxy_reader/logger.py,sha256=BxaHptwZlPPGdx5mbS8vi77u0N-W6cKhcR-5lG2x93c,710
5
+ proxy_reader/proxy.py,sha256=vkI2vonxlm0x0u3Tojq6xKaw5_7fvSbmICW8b_M4lzY,2645
6
+ proxy_reader/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ proxy_reader/reader.py,sha256=KeaAPhxMI6moYaLmzYj7ZGcn8REXWs-1xBMkXuK2Ff0,12373
8
+ proxy_reader/protocols/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ proxy_reader/protocols/reader.py,sha256=WscEXPpKmJuMF2R7EBqDZTheRh8BIUilukojcPRFyRg,2303
10
+ proxy_reader-0.1.0.dist-info/LICENSE,sha256=8DyHi9RsZXeM8s1DpaXubZSSG44PkzV2oskJE3E09F4,1081
11
+ proxy_reader-0.1.0.dist-info/METADATA,sha256=hsWGBfcZrYHMTZWKY_oQEkWBgYzisQ66sWJkt0AM5JI,1892
12
+ proxy_reader-0.1.0.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
13
+ proxy_reader-0.1.0.dist-info/top_level.txt,sha256=NIrKvLf5DF2_oEnj0yg84roFna2-MaJ7zE1jY2CIU0I,13
14
+ proxy_reader-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.2.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ proxy_reader