proxy-reader 0.1.0__tar.gz → 2.0.0__tar.gz

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.

Files changed (25) hide show
  1. {proxy_reader-0.1.0 → proxy_reader-2.0.0}/LICENSE +0 -0
  2. {proxy_reader-0.1.0 → proxy_reader-2.0.0}/MANIFEST.in +0 -0
  3. {proxy_reader-0.1.0/proxy_reader.egg-info → proxy_reader-2.0.0}/PKG-INFO +24 -3
  4. proxy_reader-2.0.0/README.md +32 -0
  5. {proxy_reader-0.1.0 → proxy_reader-2.0.0}/proxy_reader/__init__.py +1 -1
  6. {proxy_reader-0.1.0 → proxy_reader-2.0.0}/proxy_reader/_types.py +10 -1
  7. proxy_reader-2.0.0/proxy_reader/logs_config.py +20 -0
  8. {proxy_reader-0.1.0 → proxy_reader-2.0.0}/proxy_reader/protocols/__init__.py +0 -0
  9. proxy_reader-2.0.0/proxy_reader/protocols/reader.py +74 -0
  10. proxy_reader-2.0.0/proxy_reader/proxy.py +83 -0
  11. {proxy_reader-0.1.0 → proxy_reader-2.0.0}/proxy_reader/reader.py +89 -50
  12. proxy_reader-2.0.0/proxy_reader/utils.py +35 -0
  13. {proxy_reader-0.1.0 → proxy_reader-2.0.0/proxy_reader.egg-info}/PKG-INFO +24 -3
  14. {proxy_reader-0.1.0 → proxy_reader-2.0.0}/proxy_reader.egg-info/SOURCES.txt +2 -1
  15. {proxy_reader-0.1.0 → proxy_reader-2.0.0}/pyproject.toml +2 -2
  16. proxy_reader-0.1.0/README.md +0 -11
  17. proxy_reader-0.1.0/proxy_reader/logger.py +0 -21
  18. proxy_reader-0.1.0/proxy_reader/protocols/reader.py +0 -106
  19. proxy_reader-0.1.0/proxy_reader/proxy.py +0 -78
  20. {proxy_reader-0.1.0 → proxy_reader-2.0.0}/proxy_reader/domains.py +0 -0
  21. {proxy_reader-0.1.0 → proxy_reader-2.0.0}/proxy_reader/py.typed +0 -0
  22. {proxy_reader-0.1.0 → proxy_reader-2.0.0}/proxy_reader.egg-info/dependency_links.txt +0 -0
  23. {proxy_reader-0.1.0 → proxy_reader-2.0.0}/proxy_reader.egg-info/requires.txt +0 -0
  24. {proxy_reader-0.1.0 → proxy_reader-2.0.0}/proxy_reader.egg-info/top_level.txt +0 -0
  25. {proxy_reader-0.1.0 → proxy_reader-2.0.0}/setup.cfg +0 -0
File without changes
File without changes
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: proxy-reader
3
- Version: 0.1.0
3
+ Version: 2.0.0
4
4
  Summary: Read and check bulk proxies effectively
5
5
  Author-email: Rune Tech <runetech2024@gmail.com>
6
6
  License: The MIT License (MIT)
@@ -23,11 +23,32 @@ Requires-Dist: aiohttp_socks>=0.9.0
23
23
 
24
24
 
25
25
 
26
- # proxy_reader - A simple but useful bulk proxies reader and checker.
26
+ # proxy-reader - A simple but useful bulk proxies reader and checker.
27
27
 
28
28
  This is useful when you are working with multiple proxies and want to bulk check
29
29
  these proxies before using them.
30
30
  It has iterators to iterate the proxies for easy reading.
31
31
 
32
32
 
33
+ ## Installation
34
+
35
+ ```
36
+ pip install proxy-reader
37
+ ```
38
+
33
39
  ## Changelogs
40
+
41
+ ### [v0.3.0]
42
+ * Add load_list class method to load proxies from list
43
+ * MAJOR: auto detect the proxies format
44
+ * Use new logging config to disable logs and prevent proxy_reader.log from creating
45
+ * Logs can be enabled from user-side
46
+ * Add option to disable proxies checking from __init__
47
+
48
+
49
+ ### [v0.2.0] - 2024-10-21
50
+
51
+ * Previous unrecorded changes
52
+
53
+
54
+ For more info/queries Telegram: [@runetech](https://t.me/runetech)
@@ -0,0 +1,32 @@
1
+
2
+
3
+
4
+ # proxy-reader - A simple but useful bulk proxies reader and checker.
5
+
6
+ This is useful when you are working with multiple proxies and want to bulk check
7
+ these proxies before using them.
8
+ It has iterators to iterate the proxies for easy reading.
9
+
10
+
11
+ ## Installation
12
+
13
+ ```
14
+ pip install proxy-reader
15
+ ```
16
+
17
+ ## Changelogs
18
+
19
+ ### [v0.3.0]
20
+ * Add load_list class method to load proxies from list
21
+ * MAJOR: auto detect the proxies format
22
+ * Use new logging config to disable logs and prevent proxy_reader.log from creating
23
+ * Logs can be enabled from user-side
24
+ * Add option to disable proxies checking from __init__
25
+
26
+
27
+ ### [v0.2.0] - 2024-10-21
28
+
29
+ * Previous unrecorded changes
30
+
31
+
32
+ For more info/queries Telegram: [@runetech](https://t.me/runetech)
@@ -1,4 +1,4 @@
1
1
  from .reader import *
2
2
 
3
3
 
4
- __version__ = "0.1.0"
4
+ __version__ = "2.0.0"
@@ -1,4 +1,4 @@
1
- from typing import TypedDict, NotRequired, List, Iterator, TypeAlias
1
+ from typing import TypedDict, NotRequired, List, Iterator, TypeAlias, Any, Optional
2
2
  from .proxy import Proxy
3
3
 
4
4
 
@@ -10,5 +10,14 @@ class TelegramHTTP(TypedDict):
10
10
  password: NotRequired[str]
11
11
 
12
12
 
13
+ GeneralDict: TypeAlias = dict[str, Any]
14
+
13
15
  ProxiesList: TypeAlias = List[Proxy]
14
16
  ProxyiesGen: TypeAlias = Iterator[Proxy]
17
+
18
+
19
+ class ProxyDictT(TypedDict):
20
+ host: str
21
+ port: str
22
+ username: Optional[str]
23
+ password: Optional[str]
@@ -0,0 +1,20 @@
1
+ import logging
2
+
3
+ # Create the package-wide logger
4
+ package_name = "proxy_reader"
5
+ logger = logging.getLogger(package_name)
6
+ logger.addHandler(logging.NullHandler())
7
+ logger.setLevel(logging.WARNING) # Default: Show only warnings/errors
8
+
9
+
10
+ def enable_debug_logs() -> None:
11
+ logger = logging.getLogger(package_name)
12
+ logger.setLevel(logging.DEBUG) # Set log level
13
+
14
+ # 🔥 Make sure a handler is added (VERY IMPORTANT)
15
+ ch = logging.StreamHandler() # Console handler
16
+ ch.setLevel(logging.DEBUG) # Match the logger's level
17
+ formatter = logging.Formatter("%(name)s - %(levelname)s - %(message)s")
18
+ ch.setFormatter(formatter)
19
+ logger.addHandler(ch) # Attach the handler
20
+ logger.debug(f"Debugging enabled on {package_name!r}")
@@ -0,0 +1,74 @@
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
+
10
+ @property
11
+ def total_working(self) -> int: ...
12
+
13
+ @property
14
+ def total_bad(self) -> int: ...
15
+
16
+ @property
17
+ def proxies(self) -> ProxiesList: ...
18
+
19
+ @property
20
+ def bad_proxies(self) -> ProxiesList: ...
21
+
22
+ @property
23
+ def working_proxies(self) -> ProxiesList: ...
24
+
25
+ @working_proxies.setter
26
+ def working_proxies(self, working_proxies: List[Proxy]) -> None: ...
27
+
28
+ def _random_proxy_check_url(self) -> str: ...
29
+
30
+ def read_with_auth(self) -> None: ...
31
+
32
+ def read_authless(self) -> None: ...
33
+
34
+ async def _check_proxy(
35
+ self, proxy: Proxy, response_time: Optional[int] = None
36
+ ) -> bool: ...
37
+
38
+ async def check_all_proxies(self, max_resp_time: int = 30) -> None: ...
39
+
40
+ async def _check_proxy_socks(
41
+ self, proxy: Proxy, response_time: Optional[int] = None
42
+ ) -> bool: ...
43
+
44
+ async def check_all_proxies_socks5(self, max_resp_time: int = 5) -> None: ...
45
+
46
+ def get_working_proxies_list_http(self) -> List[str]: ...
47
+
48
+ def write_working_proxies(self, filename: str) -> None: ...
49
+
50
+ def get_random_http(self) -> Optional[str]: ...
51
+
52
+ def get_random_socks5(self) -> Optional[str]: ...
53
+
54
+ def get_random_socks5_telegram(self) -> Optional[Dict[str, Any]]: ...
55
+
56
+ def next_http_from_list(self) -> Optional[str]: ...
57
+
58
+ def next_http_from_cycle(self) -> str: ...
59
+
60
+ def next_socks5_from_list(self) -> str: ...
61
+
62
+ def next_socks5_from_cycle(self) -> str: ...
63
+
64
+ def next_http_telegram_from_list(self) -> Dict[str, Any]: ...
65
+
66
+ def next_http_telegram_from_cycle(self) -> Dict[str, Any]: ...
67
+
68
+ def next_socks5_telegram_from_cycle(self) -> Dict[str, Any]: ...
69
+
70
+ def next_socks5_telegram_from_list(self) -> Dict[str, Any]: ...
71
+
72
+ def next_https_from_list(self) -> str: ...
73
+
74
+ def next_https_from_cycle(self) -> str: ...
@@ -0,0 +1,83 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING, Optional, Dict, Any
3
+
4
+
5
+ if TYPE_CHECKING:
6
+ from ._types import GeneralDict, ProxyDictT
7
+
8
+
9
+ class Proxy:
10
+ def __init__(
11
+ self,
12
+ proxy: ProxyDictT,
13
+ ) -> None:
14
+ self._proxy = proxy
15
+
16
+ @property
17
+ def ip(self) -> str:
18
+ return self._proxy["host"]
19
+
20
+ @property
21
+ def port(self) -> str:
22
+ return self._proxy["port"]
23
+
24
+ @property
25
+ def username(self) -> Optional[str]:
26
+ return self._proxy["username"]
27
+
28
+ @property
29
+ def password(self) -> Optional[str]:
30
+ return self._proxy["password"]
31
+
32
+ @property
33
+ def http(self) -> str:
34
+ if self.username and self.password:
35
+ return f"http://{self.username}:{self.password}@{self.ip}:{self.port}"
36
+ return f"http://{self.ip}:{self.port}"
37
+
38
+ @property
39
+ def https(self) -> str:
40
+ if self.username and self.password:
41
+ return f"https://{self.username}:{self.password}@{self.ip}:{self.port}"
42
+ return f"https://{self.ip}:{self.port}"
43
+
44
+ @property
45
+ def telegram_http(self) -> Dict[str, Any]:
46
+ p: GeneralDict = {"proxy_type": 3, "addr": self.ip, "port": int(self.port)}
47
+ if self.username and self.password:
48
+ p.update({"username": self.username, "password": self.password})
49
+ return p
50
+
51
+ @property
52
+ def telegram_socks5(self) -> Dict[str, Any]:
53
+ p: GeneralDict = {"proxy_type": 2, "addr": self.ip, "port": int(self.port)}
54
+ if self.username and self.password:
55
+ p.update({"username": self.username, "password": self.password})
56
+ return p
57
+
58
+ @property
59
+ def telegram_socks4(self) -> Dict[str, Any]:
60
+ p: GeneralDict = {"proxy_type": 1, "addr": self.ip, "port": int(self.port)}
61
+ if self.username and self.password:
62
+ p.update({"username": self.username, "password": self.password})
63
+ return p
64
+
65
+ @property
66
+ def socks5(self) -> str:
67
+ if self.username is not None and self.password is not None:
68
+ return f"socks5://{self.username}:{self.password}@{self.ip}:{self.port}"
69
+ return f"socks5://{self.ip}:{self.port}"
70
+
71
+ @property
72
+ def socks4(self) -> str:
73
+ if self.username is not None and self.password is not None:
74
+ return f"socks4://{self.username}:{self.password}@{self.ip}:{self.port}"
75
+ return f"socks4://{self.ip}:{self.port}"
76
+
77
+ def __str__(self) -> str:
78
+ if self.username is not None and self.password is not None:
79
+ return f"{self.ip}:{self.port}:{self.username}:{self.password}"
80
+ return f"{self.ip}:{self.port}"
81
+
82
+ def __repr__(self) -> str:
83
+ return self.__str__()
@@ -1,40 +1,52 @@
1
+ import os
1
2
  import random
2
3
  import itertools
4
+ import tempfile
5
+ import warnings
6
+ from .utils import parse_proxy_line
3
7
  from .proxy import Proxy
4
8
  import aiohttp
5
9
  import asyncio
6
- from .logger import logger, console_handler, file_handler
7
- import os
10
+ from .logs_config import logger
8
11
  from aiohttp_socks import ProxyConnector
9
12
  import sys
10
13
  from typing import Optional, List, Dict, Any
11
- from ._types import ProxiesList, ProxyiesGen
14
+ from ._types import ProxiesList, ProxyDictT, ProxyiesGen
12
15
  from .protocols.reader import ProxiesReaderProtocol
13
16
 
14
17
 
15
18
  class ProxiesReader(ProxiesReaderProtocol):
16
19
  def __init__(
17
20
  self,
18
- file_path: str = "proxies.txt",
21
+ proxies_file: str,
22
+ check_proxies: bool = False,
23
+ proxy_checking_threads: int = 50,
24
+ max_response_time: int = 60,
19
25
  shuffle: bool = False,
20
- debug: bool = False,
21
- extra_debug: bool = False,
22
26
  ) -> None:
23
- self._file_path = file_path
24
- self._debug = debug
25
- self._extra_debug = extra_debug
27
+ self._raw_proxies = open(proxies_file, encoding="utf-8", mode="r").readlines()
26
28
 
29
+ self._check_proxies = check_proxies
27
30
  self._shuffle = shuffle
28
- self._proxies: ProxiesList = []
29
- self._has_auth = False
31
+ self._proxies_dict_list: list[ProxyDictT] = [
32
+ parse_proxy_line(p) for p in self._raw_proxies
33
+ ]
34
+ self._all_proxies: ProxiesList = [Proxy(p) for p in self._proxies_dict_list]
35
+
30
36
  self._bad_proxies: ProxiesList = []
31
- self._working_proxies: ProxiesList = []
32
- self._proxies_checked = False
37
+
38
+ self._working_proxies: ProxiesList = (
39
+ [] if self._check_proxies else self._all_proxies
40
+ )
41
+
33
42
  self._proxy_iterator: Optional[ProxyiesGen] = None
34
43
  self._proxy_iterator_cycle: Optional[ProxyiesGen] = None
35
- self._thread_control: asyncio.Semaphore = asyncio.Semaphore(500)
36
- self._max_response_time = 60
44
+ self._thread_control: asyncio.Semaphore = asyncio.Semaphore(
45
+ proxy_checking_threads
46
+ )
47
+ self._max_response_time = max_response_time
37
48
  self._timeout_count = 0
49
+ self._proxies_checked = False
38
50
 
39
51
  self._check_urls = [
40
52
  # New
@@ -53,17 +65,39 @@ class ProxiesReader(ProxiesReaderProtocol):
53
65
  # "http://dog.ceo/api/breeds/image/random",
54
66
  ]
55
67
 
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
68
+ @classmethod
69
+ def load_list(
70
+ cls,
71
+ proxies: list[str],
72
+ check_proxies: bool = False,
73
+ proxy_checking_threads: int = 50,
74
+ max_response_time: int = 60,
75
+ shuffle: bool = False,
76
+ ) -> "ProxiesReader":
77
+ """Load proxies from a list"""
78
+ proxies_file = tempfile.NamedTemporaryFile(
79
+ delete=False, suffix=".txt", mode="w+"
80
+ )
81
+ try:
82
+ proxies_file.write("\n".join(proxies))
83
+ proxies_file.flush()
84
+ new = cls(
85
+ proxies_file.name,
86
+ check_proxies,
87
+ proxy_checking_threads,
88
+ max_response_time,
89
+ shuffle,
90
+ )
91
+
92
+ finally:
93
+ proxies_file.close()
94
+ os.unlink(proxies_file.name)
95
+
96
+ return new
63
97
 
64
98
  @property
65
99
  def total(self) -> int:
66
- return len(self._proxies)
100
+ return len(self._all_proxies)
67
101
 
68
102
  @property
69
103
  def total_working(self) -> int:
@@ -75,7 +109,7 @@ class ProxiesReader(ProxiesReaderProtocol):
75
109
 
76
110
  @property
77
111
  def proxies(self) -> ProxiesList:
78
- return self._proxies
112
+ return self._all_proxies
79
113
 
80
114
  @property
81
115
  def bad_proxies(self) -> ProxiesList:
@@ -90,46 +124,48 @@ class ProxiesReader(ProxiesReaderProtocol):
90
124
  self._working_proxies = working_proxies
91
125
 
92
126
  def __str__(self) -> str:
93
- return str(self._proxies)
127
+ return str(self._all_proxies)
94
128
 
95
129
  def __repr__(self) -> str:
96
130
  return self.__str__()
97
131
 
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:
132
+ def _random_proxy_check_url(self) -> str:
103
133
  return random.choice(self._check_urls)
104
134
 
105
135
  def read_with_auth(self) -> None:
106
136
  """Format: IP:PORT:USERNAME:PASSWORD"""
107
- raw_proxies = self.read_raw()
137
+ return warnings.warn(
138
+ "read_with_auth is deprecated. Please don't use it. It's not working ...",
139
+ )
140
+ raw_proxies = self._read_raw()
108
141
  for proxy in raw_proxies:
109
142
  sp_proxy = proxy.split(":")
110
143
  ip = sp_proxy[0]
111
144
  port = sp_proxy[1]
112
145
  username = sp_proxy[2]
113
146
  password = sp_proxy[3]
114
- self._proxies.append(Proxy(ip, port, username, password))
147
+ self._all_proxies.append(Proxy(ip, port, username, password))
115
148
 
116
149
  self._has_auth = True
117
150
  if self._shuffle:
118
- random.shuffle(self._proxies)
151
+ random.shuffle(self._all_proxies)
119
152
 
120
153
  def read_authless(self) -> None:
121
154
  """Format: IP:PORT"""
122
- raw_proxies = self.read_raw()
155
+ return warnings.warn(
156
+ "read_authless is deprecated. Please don't use it. It's not working ..."
157
+ )
158
+ raw_proxies = self._read_raw()
123
159
  for proxy in raw_proxies:
124
160
  sp_proxy = proxy.split(":")
125
161
  ip = sp_proxy[0]
126
162
  port = sp_proxy[1]
127
- self._proxies.append(Proxy(ip, port))
163
+ self._all_proxies.append(Proxy(ip, port))
128
164
  logger.debug(
129
- f"Loaded total {len(self._proxies)} proxies from {self._file_path}"
165
+ f"Loaded total {len(self._all_proxies)} proxies from {self._file_path}"
130
166
  )
131
167
  if self._shuffle:
132
- random.shuffle(self._proxies)
168
+ random.shuffle(self._all_proxies)
133
169
 
134
170
  async def _check_proxy(
135
171
  self, proxy: Proxy, response_time: Optional[int] = None
@@ -137,7 +173,7 @@ class ProxiesReader(ProxiesReaderProtocol):
137
173
  connectins_limit = 60 if "win" in sys.platform else 100
138
174
  connector = aiohttp.TCPConnector(limit=connectins_limit)
139
175
  session = aiohttp.ClientSession(connector=connector)
140
- url = self.random_url()
176
+ url = self._random_proxy_check_url()
141
177
  p = proxy.http
142
178
 
143
179
  async with self._thread_control:
@@ -156,14 +192,17 @@ class ProxiesReader(ProxiesReaderProtocol):
156
192
  self._timeout_count += 1
157
193
  logger.debug(f"{p} : TIMEOUT {e}. {url}")
158
194
  self._bad_proxies.append(proxy)
195
+ await connector.close()
159
196
  await session.close()
160
197
  return False
161
198
 
162
199
  except Exception as e:
163
- logger.debug(f"Bad proxy raised. {e}", exc_info=self._extra_debug)
164
- await session.close()
200
+ logger.debug(f"Bad proxy raised. {e}", exc_info=True)
165
201
  return False
166
202
 
203
+ finally:
204
+ await session.close()
205
+
167
206
  if resp.status == 200:
168
207
  logger.debug(f"{p}: Working")
169
208
  self._working_proxies.append(proxy)
@@ -176,19 +215,19 @@ class ProxiesReader(ProxiesReaderProtocol):
176
215
 
177
216
  async def check_all_proxies(self, max_resp_time: int = 30) -> None:
178
217
  """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.")
218
+ if self._check_proxies:
219
+ async with asyncio.TaskGroup() as gp:
220
+ for proxy in self._all_proxies:
221
+ gp.create_task(self._check_proxy(proxy, max_resp_time))
222
+ self._proxies_checked = True
223
+ logger.debug("All proxies checked.")
185
224
 
186
225
  async def _check_proxy_socks(
187
226
  self, proxy: Proxy, response_time: Optional[int] = None
188
227
  ) -> bool:
189
- url = self.random_url()
228
+ url = self._random_proxy_check_url()
190
229
  socks_connector = ProxyConnector.from_url(proxy.socks5) # type: ignore
191
- session = aiohttp.ClientSession(connector=socks_connector)
230
+ session = aiohttp.ClientSession(connector=socks_connector) # type: ignore
192
231
  logger.debug(f"Checking proxy {proxy} ..")
193
232
  try:
194
233
  resp = await asyncio.wait_for(session.get(url), timeout=response_time)
@@ -200,7 +239,7 @@ class ProxiesReader(ProxiesReaderProtocol):
200
239
  return False
201
240
 
202
241
  except Exception as e:
203
- logger.debug(f"Bad proxy raised. {e}", exc_info=self._extra_debug)
242
+ logger.debug(f"Bad proxy raised. {e}", exc_info=True)
204
243
  await session.close()
205
244
  return False
206
245
 
@@ -218,7 +257,7 @@ class ProxiesReader(ProxiesReaderProtocol):
218
257
  async def check_all_proxies_socks5(self, max_resp_time: int = 5) -> None:
219
258
  """Run the check on all proxies at once."""
220
259
  tasks: List[asyncio.Task[bool]] = []
221
- for proxy in self._proxies:
260
+ for proxy in self._all_proxies:
222
261
  tasks.append(
223
262
  asyncio.create_task(self._check_proxy_socks(proxy, max_resp_time))
224
263
  )
@@ -0,0 +1,35 @@
1
+ from ._types import ProxyDictT
2
+ import re
3
+ from typing import cast
4
+ from .logs_config import logger
5
+
6
+
7
+ def parse_proxy_line(proxy: str) -> ProxyDictT:
8
+ """
9
+ Detects the format of the proxy string and extracts the components.
10
+
11
+ Returns a dictionary with 'ip_or_host', 'port', 'username', and 'password'.
12
+ """
13
+ logger.info("Reading the proxy format ...")
14
+ patterns: list[str] = [
15
+ # Format 1: IP/Hostname:PORT:USERNAME:PASSWORD
16
+ r"^(?P<host>[\w\.-]+):(?P<port>\d+):(?P<username>[^:]+):(?P<password>.+)$",
17
+ # Format 2: USERNAME:PASSWORD:IP/Hostname:PORT
18
+ r"^(?P<username>[^:]+):(?P<password>[^:]+):(?P<host>[\w\.-]+):(?P<port>\d+)$",
19
+ # Format 3: http://USERNAME:PASSWORD@IP/Hostname:PORT
20
+ r"^http:\/\/(?P<username>[^:]+):(?P<password>[^@]+)@(?P<host>[\w\.-]+):(?P<port>\d+)$",
21
+ # Format 4: USERNAME:PASSWORD@IP/Hostname:PORT
22
+ r"^(?P<username>[^:]+):(?P<password>[^@]+)@(?P<host>[\w\.-]+):(?P<port>\d+)$",
23
+ # Format 5: IP/Hostname:PORT (No Username/Password)
24
+ r"^(?P<ip_or_host>[\w\.-]+):(?P<port>\d+)$",
25
+ ]
26
+
27
+ for pattern in patterns:
28
+ match = re.match(pattern, proxy.strip())
29
+ if match:
30
+ data = match.groupdict()
31
+ data.setdefault("username", None) # Ensure username exists
32
+ data.setdefault("password", None) # Ensure password exists
33
+ return cast(ProxyDictT, data)
34
+
35
+ raise ValueError(f"Invalid format: {proxy}")
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: proxy-reader
3
- Version: 0.1.0
3
+ Version: 2.0.0
4
4
  Summary: Read and check bulk proxies effectively
5
5
  Author-email: Rune Tech <runetech2024@gmail.com>
6
6
  License: The MIT License (MIT)
@@ -23,11 +23,32 @@ Requires-Dist: aiohttp_socks>=0.9.0
23
23
 
24
24
 
25
25
 
26
- # proxy_reader - A simple but useful bulk proxies reader and checker.
26
+ # proxy-reader - A simple but useful bulk proxies reader and checker.
27
27
 
28
28
  This is useful when you are working with multiple proxies and want to bulk check
29
29
  these proxies before using them.
30
30
  It has iterators to iterate the proxies for easy reading.
31
31
 
32
32
 
33
+ ## Installation
34
+
35
+ ```
36
+ pip install proxy-reader
37
+ ```
38
+
33
39
  ## Changelogs
40
+
41
+ ### [v0.3.0]
42
+ * Add load_list class method to load proxies from list
43
+ * MAJOR: auto detect the proxies format
44
+ * Use new logging config to disable logs and prevent proxy_reader.log from creating
45
+ * Logs can be enabled from user-side
46
+ * Add option to disable proxies checking from __init__
47
+
48
+
49
+ ### [v0.2.0] - 2024-10-21
50
+
51
+ * Previous unrecorded changes
52
+
53
+
54
+ For more info/queries Telegram: [@runetech](https://t.me/runetech)
@@ -5,10 +5,11 @@ pyproject.toml
5
5
  proxy_reader/__init__.py
6
6
  proxy_reader/_types.py
7
7
  proxy_reader/domains.py
8
- proxy_reader/logger.py
8
+ proxy_reader/logs_config.py
9
9
  proxy_reader/proxy.py
10
10
  proxy_reader/py.typed
11
11
  proxy_reader/reader.py
12
+ proxy_reader/utils.py
12
13
  proxy_reader.egg-info/PKG-INFO
13
14
  proxy_reader.egg-info/SOURCES.txt
14
15
  proxy_reader.egg-info/dependency_links.txt
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
9
9
  [project]
10
10
 
11
11
  name = "proxy-reader"
12
- version = "0.1.0"
12
+ version = "2.0.0"
13
13
  description = "Read and check bulk proxies effectively"
14
14
  authors = [
15
15
  {name = "Rune Tech", email = "runetech2024@gmail.com"}
@@ -33,7 +33,7 @@ github = "https://github.com/runetech0/proxy-reader"
33
33
 
34
34
  [tool.bumpver]
35
35
 
36
- current_version = "0.1.0"
36
+ current_version = "2.0.0"
37
37
  version_pattern = "MAJOR.MINOR.PATCH"
38
38
  commit_message = "bump version {old_version} -> {new_version}"
39
39
  tag_message = "{new_version}"
@@ -1,11 +0,0 @@
1
-
2
-
3
-
4
- # proxy_reader - A simple but useful bulk proxies reader and checker.
5
-
6
- This is useful when you are working with multiple proxies and want to bulk check
7
- these proxies before using them.
8
- It has iterators to iterate the proxies for easy reading.
9
-
10
-
11
- ## Changelogs
@@ -1,21 +0,0 @@
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)
@@ -1,106 +0,0 @@
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
@@ -1,78 +0,0 @@
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__()
File without changes