swiftshadow 1.2.0__py3-none-any.whl → 2.0.0__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- swiftshadow/__init__.py +15 -10
- swiftshadow/cache.py +22 -5
- swiftshadow/classes.py +168 -100
- swiftshadow/exceptions.py +4 -0
- swiftshadow/helpers.py +18 -3
- swiftshadow/models.py +71 -0
- swiftshadow/providers.py +154 -49
- swiftshadow/types.py +50 -0
- swiftshadow/validator.py +50 -0
- swiftshadow-2.0.0.dist-info/METADATA +95 -0
- swiftshadow-2.0.0.dist-info/RECORD +14 -0
- {swiftshadow-1.2.0.dist-info → swiftshadow-2.0.0.dist-info}/WHEEL +1 -2
- swiftshadow-2.0.0.dist-info/entry_points.txt +2 -0
- swiftshadow/constants.py +0 -250
- swiftshadow-1.2.0.dist-info/METADATA +0 -54
- swiftshadow-1.2.0.dist-info/RECORD +0 -11
- swiftshadow-1.2.0.dist-info/top_level.txt +0 -1
- {swiftshadow-1.2.0.dist-info → swiftshadow-2.0.0.dist-info/licenses}/LICENSE +0 -0
swiftshadow/__init__.py
CHANGED
@@ -1,25 +1,30 @@
|
|
1
|
+
from typing import Literal
|
1
2
|
from swiftshadow.providers import Providers
|
3
|
+
from swiftshadow.models import Proxy
|
4
|
+
from asyncio import run
|
2
5
|
|
3
6
|
|
4
|
-
def QuickProxy(
|
7
|
+
def QuickProxy(
|
8
|
+
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
9
|
+
) -> Proxy | None:
|
5
10
|
"""
|
6
|
-
This function is a faster alternative to `
|
11
|
+
This function is a faster alternative to `ProxyInterface` class.
|
7
12
|
No caching is done.
|
8
13
|
|
9
14
|
Args:
|
10
|
-
|
11
|
-
|
15
|
+
countries: ISO 3166-2 Two letter country codes to filter proxies.
|
16
|
+
protocol: HTTP/HTTPS protocol to filter proxies.
|
12
17
|
|
13
18
|
Returns:
|
14
|
-
|
19
|
+
proxyObject (Proxy): A working proxy object if found or else None.
|
15
20
|
"""
|
16
|
-
for
|
17
|
-
if protocol not in
|
21
|
+
for provider in Providers:
|
22
|
+
if protocol not in provider.protocols:
|
18
23
|
continue
|
19
|
-
if (len(countries) != 0) and (not
|
24
|
+
if (len(countries) != 0) and (not provider.countryFilter):
|
20
25
|
continue
|
21
26
|
try:
|
22
|
-
return
|
23
|
-
except:
|
27
|
+
return run(provider.providerFunction(countries, protocol))[0]
|
28
|
+
except Exception:
|
24
29
|
continue
|
25
30
|
return None
|
swiftshadow/cache.py
CHANGED
@@ -1,16 +1,33 @@
|
|
1
1
|
from datetime import datetime, timezone, timedelta
|
2
2
|
|
3
3
|
|
4
|
-
def getExpiry(
|
4
|
+
def getExpiry(timeToLive: int) -> datetime:
|
5
|
+
"""
|
6
|
+
Fetch a datetime object representing the cache expiry based on TTL.
|
7
|
+
|
8
|
+
Args:
|
9
|
+
timeToLive(int): Time in minutes the cache should expire.
|
10
|
+
|
11
|
+
Returns:
|
12
|
+
expiry(datetime): Datetime object representing the expiry time.
|
13
|
+
"""
|
5
14
|
now = datetime.now(timezone.utc)
|
6
|
-
expiry = now + timedelta(minutes=
|
15
|
+
expiry = now + timedelta(minutes=timeToLive)
|
7
16
|
return expiry
|
8
17
|
|
9
18
|
|
10
|
-
def checkExpiry(
|
19
|
+
def checkExpiry(expiryDate: datetime) -> bool:
|
20
|
+
"""
|
21
|
+
Check if a expiry date object has expired.
|
22
|
+
|
23
|
+
Args:
|
24
|
+
expiryDate(datetime): Expiry date object.
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
expiry(bool): Expire Status.
|
28
|
+
"""
|
11
29
|
now = datetime.now(timezone.utc)
|
12
|
-
|
13
|
-
if (now - expiryDateObject).days < 0:
|
30
|
+
if (now - expiryDate).days < 0:
|
14
31
|
return False
|
15
32
|
else:
|
16
33
|
return True
|
swiftshadow/classes.py
CHANGED
@@ -1,145 +1,213 @@
|
|
1
|
-
from
|
1
|
+
from datetime import datetime
|
2
2
|
from random import choice
|
3
|
-
from
|
4
|
-
from
|
3
|
+
from typing import Literal
|
4
|
+
from pathlib import Path
|
5
|
+
from appdirs import user_cache_dir
|
6
|
+
from logging import FileHandler, getLogger, Formatter, StreamHandler, INFO, DEBUG
|
7
|
+
from sys import stdout
|
8
|
+
from pickle import load, dump
|
9
|
+
from swiftshadow.cache import checkExpiry, getExpiry
|
10
|
+
from swiftshadow.models import CacheData, Proxy as Proxy
|
11
|
+
|
12
|
+
from swiftshadow.exceptions import UnsupportedProxyProtocol
|
5
13
|
from swiftshadow.providers import Providers
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
logFormat = logging.Formatter("%(asctime)s - %(name)s [%(levelname)s]:%(message)s")
|
13
|
-
streamhandler = logging.StreamHandler(stream=sys.stdout)
|
14
|
+
from asyncio import run
|
15
|
+
|
16
|
+
logger = getLogger("swiftshadow")
|
17
|
+
logger.setLevel(INFO)
|
18
|
+
logFormat = Formatter("%(asctime)s - %(name)s [%(levelname)s]:%(message)s")
|
19
|
+
streamhandler = StreamHandler(stream=stdout)
|
14
20
|
streamhandler.setFormatter(logFormat)
|
15
21
|
logger.addHandler(streamhandler)
|
16
22
|
|
17
23
|
|
18
|
-
class
|
24
|
+
class ProxyInterface:
|
25
|
+
"""Manages proxy acquisition, caching, and rotation from various providers.
|
26
|
+
|
27
|
+
This class handles proxy retrieval either through fresh fetching from registered providers
|
28
|
+
or via cached data. It supports protocol filtering, country filtering, cache management,
|
29
|
+
and automatic/manual proxy rotation.
|
30
|
+
|
31
|
+
Attributes:
|
32
|
+
countries (list[str]): List of ISO country codes to filter proxies by (e.g., ["US", "CA"]).
|
33
|
+
protocol (Literal['https', 'http']): Proxy protocol to use. Defaults to 'http'.
|
34
|
+
maxproxies (int): Maximum number of proxies to collect from providers. Defaults to 10.
|
35
|
+
autorotate (bool): Whether to automatically rotate proxy on each get() call. Defaults to False.
|
36
|
+
cachePeriod (int): Number of minutes before cache is considered expired. Defaults to 10.
|
37
|
+
cacheFolderPath (Path): Filesystem path for cache storage. Uses system cache dir by default.
|
38
|
+
proxies (list[Proxy]): List of available proxy objects.
|
39
|
+
current (Proxy | None): Currently active proxy. None if no proxies available.
|
40
|
+
cacheExpiry (datetime | None): Timestamp when cache expires. None if no cache exists.
|
41
|
+
|
42
|
+
Example:
|
43
|
+
```python
|
44
|
+
proxy_manager = ProxyInterface(
|
45
|
+
countries=["US"],
|
46
|
+
protocol="http",
|
47
|
+
autoRotate=True
|
48
|
+
)
|
49
|
+
print(proxy_manager.get())
|
50
|
+
```
|
51
|
+
|
52
|
+
Raises:
|
53
|
+
UnsupportedProxyProtocol: If invalid protocol is specified during initialization.
|
54
|
+
ValueError: If no proxies match filters during update().
|
55
|
+
"""
|
56
|
+
|
19
57
|
def __init__(
|
20
58
|
self,
|
21
|
-
countries: list = [],
|
22
|
-
protocol:
|
59
|
+
countries: list[str] = [],
|
60
|
+
protocol: Literal["https", "http"] = "http",
|
23
61
|
maxProxies: int = 10,
|
24
62
|
autoRotate: bool = False,
|
25
63
|
cachePeriod: int = 10,
|
26
|
-
|
64
|
+
cacheFolderPath: Path | None = None,
|
27
65
|
debug: bool = False,
|
28
66
|
logToFile: bool = False,
|
29
67
|
):
|
68
|
+
"""Initializes ProxyInterface with specified configuration.
|
69
|
+
|
70
|
+
Args:
|
71
|
+
countries: List of ISO country codes to filter proxies. Empty list = no filtering.
|
72
|
+
protocol: Proxy protocol to retrieve. Choose between 'http' or 'https'.
|
73
|
+
maxProxies: Maximum proxies to collect from all providers combined.
|
74
|
+
autoRotate: Enable automatic proxy rotation on every get() call.
|
75
|
+
cachePeriod: Cache validity duration in minutes.
|
76
|
+
cacheFolderPath: Custom path for cache storage. Uses system cache dir if None.
|
77
|
+
debug: Enable debug logging level when True.
|
78
|
+
logToFile: Write logs to swiftshadow.log in cache folder when True.
|
30
79
|
"""
|
31
|
-
The one class for everything.
|
32
80
|
|
33
|
-
|
81
|
+
self.countries: list[str] = [i.upper() for i in countries]
|
34
82
|
|
35
|
-
|
36
|
-
|
37
|
-
protocol
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
83
|
+
if protocol not in ["https", "http"]:
|
84
|
+
raise UnsupportedProxyProtocol(
|
85
|
+
f"Protocol {protocol} is not supported by swiftshadow, please choose between HTTP or HTTPS"
|
86
|
+
)
|
87
|
+
self.protocol: Literal["https", "http"] = protocol
|
88
|
+
|
89
|
+
self.maxproxies: int = maxProxies
|
90
|
+
self.autorotate: bool = autoRotate
|
91
|
+
self.cachePeriod: int = cachePeriod
|
44
92
|
|
45
|
-
Returns:
|
46
|
-
proxyClass (swiftshadow.Proxy): `swiftshadow.Proxy` class instance
|
47
|
-
|
48
|
-
Examples:
|
49
|
-
Simplest way to get a proxy
|
50
|
-
>>> from swiftshadow.swiftshadow import Proxy
|
51
|
-
>>> swift = Proxy()
|
52
|
-
>>> print(swift.proxy())
|
53
|
-
{'http':'192.0.0.1:8080'}
|
54
|
-
Note:
|
55
|
-
Proxies are sourced from **Proxyscrape** and **Scrapingant** websites which are freely available and validated locally.
|
56
|
-
"""
|
57
|
-
self.countries = [i.upper() for i in countries]
|
58
|
-
self.protocol = protocol
|
59
|
-
self.maxProxies = maxProxies
|
60
|
-
self.autoRotate = autoRotate
|
61
|
-
self.cachePeriod = cachePeriod
|
62
|
-
if cacheFolder == "":
|
63
|
-
self.cacheFilePath = ".swiftshadow.json"
|
64
|
-
else:
|
65
|
-
self.cacheFilePath = f"{cacheFolder}/.swiftshadow.json"
|
66
93
|
if debug:
|
67
|
-
logger.setLevel(
|
94
|
+
logger.setLevel(DEBUG)
|
95
|
+
|
96
|
+
if not cacheFolderPath:
|
97
|
+
cacheFolderPath = Path(user_cache_dir(appname="swiftshadow"))
|
98
|
+
cacheFolderPath.mkdir(parents=True, exist_ok=True)
|
99
|
+
logger.debug(f"System Cache folder set at {cacheFolderPath}")
|
100
|
+
self.cacheFolderPath: Path = cacheFolderPath
|
101
|
+
|
68
102
|
if logToFile:
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
103
|
+
logFileHandler = FileHandler(
|
104
|
+
self.cacheFolderPath.joinpath("swiftshadow.log")
|
105
|
+
)
|
106
|
+
logFileHandler.setFormatter(logFormat)
|
107
|
+
logger.addHandler(logFileHandler)
|
108
|
+
self.proxies: list[Proxy] = []
|
109
|
+
self.current: Proxy | None = None
|
110
|
+
self.cacheExpiry: datetime | None = None
|
111
|
+
|
76
112
|
self.update()
|
77
113
|
|
78
114
|
def update(self):
|
115
|
+
"""
|
116
|
+
Updates proxy list from providers or cache.
|
117
|
+
|
118
|
+
First attempts to load valid proxies from cache. If cache is expired/missing,
|
119
|
+
fetches fresh proxies from registered providers that match country and protocol filters.
|
120
|
+
Updates cache file with new proxies if fetched from providers.
|
121
|
+
|
122
|
+
Raises:
|
123
|
+
ValueError: If no proxies found after provider scraping.
|
124
|
+
"""
|
79
125
|
try:
|
80
|
-
with open(
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
126
|
+
with open(
|
127
|
+
self.cacheFolderPath.joinpath("swiftshadow.pickle"), "rb"
|
128
|
+
) as cacheFile:
|
129
|
+
cache: CacheData = load(cacheFile)
|
130
|
+
|
131
|
+
if not checkExpiry(cache.expiryIn):
|
132
|
+
self.proxies = cache.proxies
|
133
|
+
logger.info("Loaded proxies from cache.")
|
134
|
+
logger.debug(
|
135
|
+
f"Cache with {len(cache.proxies)} proxies, expire in {cache.expiryIn}"
|
136
|
+
)
|
137
|
+
self.current = self.proxies[0]
|
138
|
+
self.cacheExpiry = cache.expiryIn
|
139
|
+
return
|
140
|
+
else:
|
141
|
+
logger.info("Cache Expired")
|
96
142
|
except FileNotFoundError:
|
97
|
-
logger.info("No cache found
|
143
|
+
logger.info("No cache found, will be created after update.")
|
98
144
|
|
99
|
-
|
100
|
-
|
101
|
-
if self.protocol not in providerDict["protocols"]:
|
145
|
+
for provider in Providers:
|
146
|
+
if self.protocol not in provider.protocols:
|
102
147
|
continue
|
103
|
-
if (len(self.countries) != 0) and (not
|
148
|
+
if (len(self.countries) != 0) and (not provider.countryFilter):
|
104
149
|
continue
|
105
|
-
|
106
|
-
|
150
|
+
providerProxies: list[Proxy] = run(
|
151
|
+
provider.providerFunction(self.countries, self.protocol)
|
107
152
|
)
|
108
|
-
|
153
|
+
logger.debug(
|
154
|
+
f"{len(providerProxies)} proxies from {provider.providerFunction.__name__}"
|
155
|
+
)
|
156
|
+
self.proxies.extend(providerProxies)
|
157
|
+
|
158
|
+
if len(self.proxies) >= self.maxproxies:
|
109
159
|
break
|
160
|
+
|
110
161
|
if len(self.proxies) == 0:
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
self.
|
115
|
-
|
116
|
-
|
117
|
-
|
162
|
+
raise ValueError("No proxies where found for the current filter settings.")
|
163
|
+
|
164
|
+
with open(
|
165
|
+
self.cacheFolderPath.joinpath("swiftshadow.pickle"), "wb+"
|
166
|
+
) as cacheFile:
|
167
|
+
cacheExpiry = getExpiry(self.cachePeriod)
|
168
|
+
self.cacheExpiry = cacheExpiry
|
169
|
+
cache = CacheData(cacheExpiry, self.proxies)
|
170
|
+
dump(cache, cacheFile)
|
118
171
|
self.current = self.proxies[0]
|
119
172
|
|
120
|
-
def rotate(self):
|
173
|
+
def rotate(self, validate_cache: bool = False):
|
121
174
|
"""
|
122
|
-
|
175
|
+
Rotates to a random proxy from available proxies.
|
123
176
|
|
124
|
-
|
177
|
+
Args:
|
178
|
+
validate_cache: Force cache validation before rotation when True.
|
125
179
|
|
126
180
|
Note:
|
127
|
-
|
181
|
+
Only required for manual rotation when autoRotate=False. Automatic rotation
|
182
|
+
occurs during get() calls when autoRotate=True.
|
183
|
+
|
184
|
+
Raises:
|
185
|
+
ValueError: If validate_cache=True but no cache exists.
|
128
186
|
"""
|
129
|
-
if
|
130
|
-
self.
|
187
|
+
if self.cacheExpiry and not validate_cache:
|
188
|
+
if checkExpiry(self.cacheExpiry):
|
189
|
+
self.update()
|
190
|
+
else:
|
191
|
+
raise ValueError("No cache availabel but validate_cache is true.")
|
131
192
|
self.current = choice(self.proxies)
|
132
193
|
|
133
|
-
def
|
194
|
+
def get(self) -> Proxy:
|
134
195
|
"""
|
135
|
-
|
196
|
+
Retrieves current active proxy.
|
136
197
|
|
137
198
|
Returns:
|
138
|
-
|
199
|
+
Proxy: Current proxy object with connection details.
|
200
|
+
|
201
|
+
Note:
|
202
|
+
Performs automatic rotation if autorotate=True before returning proxy.
|
203
|
+
|
204
|
+
Raises:
|
205
|
+
ValueError: If no proxies are available (current is None).
|
139
206
|
"""
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
else:
|
207
|
+
|
208
|
+
if self.autorotate:
|
209
|
+
self.rotate()
|
210
|
+
if self.current:
|
145
211
|
return self.current
|
212
|
+
else:
|
213
|
+
raise ValueError("No proxy available in current, current is None")
|
swiftshadow/helpers.py
CHANGED
@@ -1,5 +1,8 @@
|
|
1
|
-
from requests import get
|
2
1
|
from datetime import datetime
|
2
|
+
from typing import Literal
|
3
|
+
|
4
|
+
from requests import get
|
5
|
+
from swiftshadow.models import Proxy
|
3
6
|
|
4
7
|
|
5
8
|
def checkProxy(proxy):
|
@@ -11,12 +14,24 @@ def checkProxy(proxy):
|
|
11
14
|
if resp.count(".") == 3:
|
12
15
|
return True
|
13
16
|
return False
|
14
|
-
except Exception
|
17
|
+
except Exception:
|
15
18
|
return False
|
16
19
|
|
17
20
|
|
18
21
|
def log(level, message):
|
19
22
|
level = level.upper()
|
20
23
|
print(
|
21
|
-
f
|
24
|
+
f"{datetime.now().strftime('%d/%m/%Y %H:%M:%S')} - [swiftshadow] - {level} : {message}"
|
22
25
|
)
|
26
|
+
|
27
|
+
|
28
|
+
def plaintextToProxies(text: str, protocol: Literal["http", "https"]) -> list[Proxy]:
|
29
|
+
proxies: list[Proxy] = []
|
30
|
+
for line in text.splitlines():
|
31
|
+
try:
|
32
|
+
ip, port = line.split(":")
|
33
|
+
except ValueError:
|
34
|
+
continue
|
35
|
+
proxy = Proxy(ip=ip, port=int(port), protocol=protocol)
|
36
|
+
proxies.append(proxy)
|
37
|
+
return proxies
|
swiftshadow/models.py
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
from dataclasses import dataclass
|
2
|
+
from datetime import datetime
|
3
|
+
from typing import Any, Callable, Coroutine, Literal
|
4
|
+
|
5
|
+
|
6
|
+
@dataclass
|
7
|
+
class Proxy:
|
8
|
+
"""
|
9
|
+
Class representing a Proxy object.
|
10
|
+
|
11
|
+
Attributes:
|
12
|
+
ip: IP Address of the proxy.
|
13
|
+
port: Port associated with the proxy.
|
14
|
+
protocol: Protocol type of the proxy.
|
15
|
+
|
16
|
+
"""
|
17
|
+
|
18
|
+
ip: str
|
19
|
+
protocol: Literal["http", "https"]
|
20
|
+
port: int
|
21
|
+
|
22
|
+
def as_requests_dict(self) -> dict[Literal["http", "https"], str]:
|
23
|
+
"""
|
24
|
+
Return proxy in requests commpatible dict format.
|
25
|
+
|
26
|
+
Returns:
|
27
|
+
dict: Dict representation of Proxy class.
|
28
|
+
"""
|
29
|
+
return {self.protocol: f"{self.ip}:{self.port}"}
|
30
|
+
|
31
|
+
def as_string(self) -> str:
|
32
|
+
"""
|
33
|
+
Return proxy in a string of format
|
34
|
+
<protocol>://<ip>:<port>
|
35
|
+
|
36
|
+
Returns:
|
37
|
+
string: Proxy in string format.
|
38
|
+
"""
|
39
|
+
return f"{self.protocol}://{self.ip}:{self.port}"
|
40
|
+
|
41
|
+
|
42
|
+
@dataclass
|
43
|
+
class CacheData:
|
44
|
+
"""
|
45
|
+
Class repersenting data structure if the cache in cache file.
|
46
|
+
|
47
|
+
Attributes:
|
48
|
+
expiryIn: Expiry date object.
|
49
|
+
proxies: Proxies to head.
|
50
|
+
"""
|
51
|
+
|
52
|
+
expiryIn: datetime
|
53
|
+
proxies: list[Proxy]
|
54
|
+
|
55
|
+
|
56
|
+
@dataclass
|
57
|
+
class Provider:
|
58
|
+
"""
|
59
|
+
Class repersenting a Provider.
|
60
|
+
|
61
|
+
Attributes:
|
62
|
+
providerFunction: Callable function for this provider.
|
63
|
+
countryFilter: Whether the provider supports country based filters.
|
64
|
+
protocols: Protocols supported by the provider.
|
65
|
+
"""
|
66
|
+
|
67
|
+
providerFunction: Callable[
|
68
|
+
[list[str], Literal["http", "https"]], Coroutine[Any, Any, list[Proxy]]
|
69
|
+
]
|
70
|
+
countryFilter: bool
|
71
|
+
protocols: list[Literal["http", "https"]]
|
swiftshadow/providers.py
CHANGED
@@ -1,57 +1,162 @@
|
|
1
|
+
from typing import Literal
|
2
|
+
|
1
3
|
from requests import get
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
def Thespeedx(max,countries=[],protocol='http'):
|
21
|
-
results = []
|
22
|
-
count =0
|
23
|
-
raw = get('https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/http.txt').text
|
24
|
-
for line in raw.splitlines():
|
25
|
-
if count == max:
|
26
|
-
break
|
27
|
-
proxy = [line,'http']
|
28
|
-
if checkProxy(proxy):
|
29
|
-
results.append(proxy)
|
30
|
-
print(proxy,True)
|
31
|
-
count +=1
|
32
|
-
else:
|
4
|
+
|
5
|
+
from swiftshadow.helpers import plaintextToProxies
|
6
|
+
from swiftshadow.models import Proxy, Provider
|
7
|
+
from swiftshadow.types import MonosansProxyDict
|
8
|
+
from swiftshadow.validator import validate_proxies
|
9
|
+
|
10
|
+
|
11
|
+
async def Monosans(
|
12
|
+
countries: list[str] = [],
|
13
|
+
protocol: Literal["http", "https"] = "http",
|
14
|
+
) -> list[Proxy]:
|
15
|
+
response = get(
|
16
|
+
"https://raw.githubusercontent.com/monosans/proxy-list/main/proxies.json"
|
17
|
+
)
|
18
|
+
proxy_dicts: list[MonosansProxyDict] = response.json()
|
19
|
+
proxies_to_validate: list[Proxy] = []
|
20
|
+
for proxy_dict in proxy_dicts:
|
21
|
+
if proxy_dict["protocol"] != protocol:
|
33
22
|
continue
|
23
|
+
if (
|
24
|
+
len(countries) != 0
|
25
|
+
and proxy_dict["geolocation"]["country"]["iso_code"] not in countries
|
26
|
+
):
|
27
|
+
continue
|
28
|
+
proxy = Proxy(
|
29
|
+
ip=proxy_dict["host"],
|
30
|
+
port=proxy_dict["port"],
|
31
|
+
protocol=proxy_dict["protocol"],
|
32
|
+
)
|
33
|
+
proxies_to_validate.append(proxy)
|
34
|
+
result = await validate_proxies(proxies_to_validate)
|
35
|
+
return result
|
36
|
+
|
37
|
+
|
38
|
+
async def Thespeedx(
|
39
|
+
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
40
|
+
):
|
41
|
+
raw: str = get(
|
42
|
+
"https://raw.githubusercontent.com/TheSpeedX/PROXY-List/master/http.txt"
|
43
|
+
).text
|
44
|
+
proxies: list[Proxy] = plaintextToProxies(raw, protocol="http")
|
45
|
+
results = await validate_proxies(proxies)
|
34
46
|
return results
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
47
|
+
|
48
|
+
|
49
|
+
async def ProxyScrape(
|
50
|
+
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
51
|
+
):
|
52
|
+
baseUrl = "https://api.proxyscrape.com/v3/free-proxy-list/get?request=displayproxies&protocol=http&proxy_format=ipport&format=json"
|
53
|
+
proxies: list[Proxy] = []
|
40
54
|
if len(countries) == 0:
|
41
|
-
apiUrl = baseUrl +
|
55
|
+
apiUrl = baseUrl + "&country=all"
|
42
56
|
else:
|
43
|
-
apiUrl = baseUrl +
|
57
|
+
apiUrl = baseUrl + "&country=" + ",".join([i.upper() for i in countries])
|
44
58
|
raw = get(apiUrl).json()
|
45
|
-
for ipRaw in raw[
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
59
|
+
for ipRaw in raw["proxies"]:
|
60
|
+
proxy = Proxy(protocol="http", ip=ipRaw["ip"], port=ipRaw["port"])
|
61
|
+
proxies.append(proxy)
|
62
|
+
results = await validate_proxies(proxies)
|
63
|
+
return results
|
64
|
+
|
65
|
+
|
66
|
+
async def GoodProxy(
|
67
|
+
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
68
|
+
):
|
69
|
+
baseUrl = "https://raw.githubusercontent.com/yuceltoluyag/GoodProxy/refs/heads/main/GoodProxy.txt"
|
70
|
+
proxies: list[Proxy] = []
|
71
|
+
raw = get(baseUrl).text
|
72
|
+
|
73
|
+
for line in raw.splitlines():
|
74
|
+
if line == "":
|
54
75
|
continue
|
55
|
-
|
76
|
+
line = line.split("|")[0].split(":")
|
77
|
+
proxy = Proxy(ip=line[0], port=int(line[1]), protocol="http")
|
78
|
+
proxies.append(proxy)
|
79
|
+
results = await validate_proxies(proxies)
|
80
|
+
return results
|
81
|
+
|
82
|
+
|
83
|
+
async def OpenProxyList(
|
84
|
+
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
85
|
+
):
|
86
|
+
raw = get("https://api.openproxylist.xyz/http.txt").text
|
87
|
+
proxies: list[Proxy] = plaintextToProxies(raw, protocol="http")
|
88
|
+
results = await validate_proxies(proxies)
|
89
|
+
return results
|
90
|
+
|
91
|
+
|
92
|
+
async def MuRongPIG(
|
93
|
+
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
94
|
+
):
|
95
|
+
raw = get(
|
96
|
+
"https://raw.githubusercontent.com/MuRongPIG/Proxy-Master/refs/heads/main/http_checked.txt"
|
97
|
+
).text
|
98
|
+
proxies: list[Proxy] = plaintextToProxies(raw, protocol="http")
|
99
|
+
results = await validate_proxies(proxies)
|
100
|
+
return results
|
101
|
+
|
102
|
+
|
103
|
+
async def KangProxy(
|
104
|
+
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
105
|
+
):
|
106
|
+
raw = get(
|
107
|
+
f"https://github.com/officialputuid/KangProxy/raw/refs/heads/KangProxy/{protocol}/{protocol}.txt"
|
108
|
+
).text
|
109
|
+
proxies: list[Proxy] = plaintextToProxies(raw, protocol=protocol)
|
110
|
+
results = await validate_proxies(proxies)
|
111
|
+
return results
|
112
|
+
|
113
|
+
|
114
|
+
async def Mmpx12(
|
115
|
+
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
116
|
+
):
|
117
|
+
raw = get(
|
118
|
+
f"https://github.com/mmpx12/proxy-list/raw/refs/heads/master/{protocol}.txt"
|
119
|
+
).text
|
120
|
+
proxies: list[Proxy] = plaintextToProxies(raw, protocol=protocol)
|
121
|
+
results = await validate_proxies(proxies)
|
122
|
+
return results
|
123
|
+
|
124
|
+
|
125
|
+
async def Anonym0usWork1221(
|
126
|
+
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
127
|
+
):
|
128
|
+
raw = get(
|
129
|
+
f"https://github.com/Anonym0usWork1221/Free-Proxies/raw/refs/heads/main/proxy_files/{protocol}_proxies.txt"
|
130
|
+
).text
|
131
|
+
proxies: list[Proxy] = plaintextToProxies(raw, protocol=protocol)
|
132
|
+
results = await validate_proxies(proxies)
|
133
|
+
return results
|
134
|
+
|
135
|
+
|
136
|
+
async def ProxySpace(
|
137
|
+
countries: list[str] = [], protocol: Literal["http", "https"] = "http"
|
138
|
+
):
|
139
|
+
raw = get("https://proxyspace.pro/http.txt").text
|
140
|
+
proxies: list[Proxy] = plaintextToProxies(raw, protocol="http")
|
141
|
+
results = await validate_proxies(proxies)
|
142
|
+
return results
|
143
|
+
|
56
144
|
|
57
|
-
Providers = [
|
145
|
+
Providers: list[Provider] = [
|
146
|
+
Provider(providerFunction=ProxyScrape, countryFilter=True, protocols=["http"]),
|
147
|
+
Provider(providerFunction=Monosans, countryFilter=True, protocols=["http"]),
|
148
|
+
Provider(providerFunction=MuRongPIG, countryFilter=False, protocols=["http"]),
|
149
|
+
Provider(providerFunction=Thespeedx, countryFilter=False, protocols=["http"]),
|
150
|
+
Provider(
|
151
|
+
providerFunction=Anonym0usWork1221,
|
152
|
+
countryFilter=False,
|
153
|
+
protocols=["http", "https"],
|
154
|
+
),
|
155
|
+
Provider(providerFunction=Mmpx12, countryFilter=False, protocols=["http", "https"]),
|
156
|
+
Provider(providerFunction=GoodProxy, countryFilter=False, protocols=["http"]),
|
157
|
+
Provider(
|
158
|
+
providerFunction=KangProxy, countryFilter=False, protocols=["http", "https"]
|
159
|
+
),
|
160
|
+
Provider(providerFunction=ProxySpace, countryFilter=False, protocols=["http"]),
|
161
|
+
Provider(providerFunction=OpenProxyList, countryFilter=False, protocols=["http"]),
|
162
|
+
]
|
swiftshadow/types.py
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
from typing import TypedDict
|
2
|
+
|
3
|
+
|
4
|
+
class MonosansNames(TypedDict):
|
5
|
+
de: str
|
6
|
+
en: str
|
7
|
+
es: str
|
8
|
+
fr: str
|
9
|
+
ja: str
|
10
|
+
pt_BR: str
|
11
|
+
ru: str
|
12
|
+
zh_CN: str
|
13
|
+
|
14
|
+
|
15
|
+
class MonosansContinent(TypedDict):
|
16
|
+
code: str
|
17
|
+
geoname_id: int
|
18
|
+
names: MonosansNames
|
19
|
+
|
20
|
+
|
21
|
+
class MonosansCountry(TypedDict):
|
22
|
+
geoname_id: int
|
23
|
+
is_in_european_union: bool
|
24
|
+
iso_code: str
|
25
|
+
names: MonosansNames
|
26
|
+
|
27
|
+
|
28
|
+
class MonosansLocation(TypedDict):
|
29
|
+
accuracy_radius: int
|
30
|
+
latitude: float
|
31
|
+
longitude: float
|
32
|
+
time_zone: str
|
33
|
+
|
34
|
+
|
35
|
+
class MonosansGeolocation(TypedDict):
|
36
|
+
continent: MonosansContinent
|
37
|
+
country: MonosansCountry
|
38
|
+
location: MonosansLocation
|
39
|
+
registered_country: MonosansCountry
|
40
|
+
|
41
|
+
|
42
|
+
class MonosansProxyDict(TypedDict):
|
43
|
+
protocol: str
|
44
|
+
username: str | None
|
45
|
+
password: str | None
|
46
|
+
host: str
|
47
|
+
port: int
|
48
|
+
exit_ip: str
|
49
|
+
timeout: float
|
50
|
+
geolocation: MonosansGeolocation
|
swiftshadow/validator.py
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
import asyncio
|
2
|
+
|
3
|
+
import aiohttp
|
4
|
+
|
5
|
+
from swiftshadow.models import Proxy
|
6
|
+
|
7
|
+
|
8
|
+
async def check_proxy(async_session: aiohttp.ClientSession, proxy: Proxy) -> str:
|
9
|
+
"""
|
10
|
+
Check one proxy abject.
|
11
|
+
|
12
|
+
Args:
|
13
|
+
async_session: aiohttp client session object
|
14
|
+
proxy: Proxy Object
|
15
|
+
|
16
|
+
Returns:
|
17
|
+
text: API response text
|
18
|
+
"""
|
19
|
+
async with async_session.get(
|
20
|
+
url=f"{proxy.protocol}://checkip.amazonaws.com",
|
21
|
+
proxy=proxy.as_string(),
|
22
|
+
timeout=4,
|
23
|
+
) as response:
|
24
|
+
text = await response.text()
|
25
|
+
return text
|
26
|
+
|
27
|
+
|
28
|
+
async def validate_proxies(proxies: list[Proxy]) -> list[Proxy]:
|
29
|
+
"""
|
30
|
+
Validate all proxies asynchronously.
|
31
|
+
|
32
|
+
Args:
|
33
|
+
proxies: List of Proxy objects
|
34
|
+
|
35
|
+
Returns:
|
36
|
+
working_proxies: List of working Proxies
|
37
|
+
"""
|
38
|
+
working_proxies: list[Proxy] = []
|
39
|
+
async with aiohttp.ClientSession() as async_session:
|
40
|
+
tasks = []
|
41
|
+
for proxy in proxies:
|
42
|
+
task = asyncio.create_task(coro=check_proxy(async_session, proxy))
|
43
|
+
tasks.append(task)
|
44
|
+
results = await asyncio.gather(*tasks, return_exceptions=True)
|
45
|
+
for proxy, result in zip(proxies, results):
|
46
|
+
if type(result) is not str:
|
47
|
+
continue
|
48
|
+
if result.count(".") == 3:
|
49
|
+
working_proxies.append(proxy)
|
50
|
+
return working_proxies
|
@@ -0,0 +1,95 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: swiftshadow
|
3
|
+
Version: 2.0.0
|
4
|
+
Summary: Free IP Proxy rotator for python
|
5
|
+
Author-email: sachin-sankar <mail.sachinsankar@gmail.com>
|
6
|
+
License-File: LICENSE
|
7
|
+
Requires-Python: >=3.12
|
8
|
+
Requires-Dist: aiohttp>=3.11.11
|
9
|
+
Requires-Dist: appdirs>=1.4.4
|
10
|
+
Requires-Dist: requests>=2.32.3
|
11
|
+
Description-Content-Type: text/markdown
|
12
|
+
|
13
|
+
# Swiftshadow
|
14
|
+
|
15
|
+
![PyPI - Downloads](https://img.shields.io/pypi/dm/swiftshadow)
|
16
|
+
![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/sachin-sankar/swiftshadow?include_prereleases&style=flat)
|
17
|
+
|
18
|
+
> [!WARNING]
|
19
|
+
> **Heads up!** If you're using **versions 1.2.1 or below**, please note that **version 2.0.0 and above** includes breaking changes. Before upgrading, read the [documentation](https://sachin-sankar.github.io/swiftshadow/) to understand the changes and ensure compatibility with your code. If you encounter issues, please review the docs before opening a GitHub issue.
|
20
|
+
|
21
|
+
## About
|
22
|
+
|
23
|
+
**Swiftshadow** is a lightweight and efficient Python library designed to simplify IP proxy rotation for web scraping, data mining, and other automated tasks. It helps you bypass common challenges like IP bans, rate limits, and detection mechanisms, ensuring smooth and uninterrupted data collection.
|
24
|
+
|
25
|
+
### Key Features
|
26
|
+
- **Speed**: Optimized for fast proxy retrieval and rotation.
|
27
|
+
- **Reliability**: Automatically switches to working proxies if one fails.
|
28
|
+
- **Customization**: Configure proxy filters, rotation frequency, and caching behavior.
|
29
|
+
- **Low Dependencies**: Only one third-party dependency (`requests`), making it easy to use and maintain.
|
30
|
+
- **Caching**: Built-in caching mechanism to reduce load times and improve performance.
|
31
|
+
|
32
|
+
Whether you're a seasoned developer or a beginner, **Swiftshadow** makes proxy management effortless.
|
33
|
+
|
34
|
+
---
|
35
|
+
|
36
|
+
## Installation
|
37
|
+
|
38
|
+
Install the library using pip:
|
39
|
+
|
40
|
+
```bash
|
41
|
+
pip install swiftshadow
|
42
|
+
```
|
43
|
+
|
44
|
+
---
|
45
|
+
|
46
|
+
## Quick Start
|
47
|
+
|
48
|
+
### Get a Proxy in 2 Lines
|
49
|
+
Fetch a random proxy with just two lines of code:
|
50
|
+
|
51
|
+
```python
|
52
|
+
from swiftshadow import QuickProxy
|
53
|
+
|
54
|
+
print(QuickProxy()) # Output: http://<ip>:<port>
|
55
|
+
```
|
56
|
+
|
57
|
+
### Advanced Usage
|
58
|
+
For more control, use the `ProxyInterface` class:
|
59
|
+
|
60
|
+
```python
|
61
|
+
from swiftshadow.classes import ProxyInterface
|
62
|
+
|
63
|
+
# Fetch HTTPS proxies from the US
|
64
|
+
swift = ProxyInterface(countries=["US"], protocol="https")
|
65
|
+
print(swift.get().as_string()) # Output: https://<ip>:<port>
|
66
|
+
```
|
67
|
+
|
68
|
+
---
|
69
|
+
|
70
|
+
## Documentation
|
71
|
+
|
72
|
+
Explore the full documentation to learn more about **Swiftshadow**'s features and advanced usage:
|
73
|
+
|
74
|
+
📚 [Documentation](https://sachin-sankar.github.io/swiftshadow/)
|
75
|
+
|
76
|
+
---
|
77
|
+
|
78
|
+
## Why Swiftshadow?
|
79
|
+
|
80
|
+
- **Lightweight**: Minimal dependencies and easy to integrate.
|
81
|
+
- **Flexible**: Supports filtering by country and protocol.
|
82
|
+
- **Scalable**: Ideal for both small scripts and large-scale scraping projects.
|
83
|
+
- **Open Source**: Free to use, modify, and contribute to under the MIT License.
|
84
|
+
|
85
|
+
---
|
86
|
+
|
87
|
+
## Contributing
|
88
|
+
|
89
|
+
Contributions are welcome! If you'd like to improve **Swiftshadow**, feel free to open an issue or submit a pull request on [GitHub](https://github.com/sachin-sankar/swiftshadow).
|
90
|
+
|
91
|
+
---
|
92
|
+
|
93
|
+
## License
|
94
|
+
|
95
|
+
**Swiftshadow** is licensed under the MIT License. See the [LICENSE](https://github.com/sachin-sankar/swiftshadow/blob/main/LICENSE) file for details.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
swiftshadow/__init__.py,sha256=DCxCxaMrluQDVJLyK5K61NxSaadD1d-nyTrFKsjfNDI,921
|
2
|
+
swiftshadow/cache.py,sha256=eA_AWa8EsPdB6xD__ButvQdqETC4i89qEgxmHQV2XWU,800
|
3
|
+
swiftshadow/classes.py,sha256=4hr0h2aOb-CXYPrf_ESf05RSEdRVLmYtvx09npnUVhQ,8242
|
4
|
+
swiftshadow/exceptions.py,sha256=qu4eXyrkWD9qd4HCIR-8vRfVcqLlTupo4sD72alCdug,129
|
5
|
+
swiftshadow/helpers.py,sha256=hHJ_JjRx2UFC5Ircl75LeYKBNDYTY_xMy2iWCk-UPqo,959
|
6
|
+
swiftshadow/models.py,sha256=YyfZV98tPdLnF1O3WmTNUNoK4t0GuchfEftzjiM03ck,1678
|
7
|
+
swiftshadow/providers.py,sha256=myJ6t-WD20wrjc7qDhxCpX1-oi7ipQutp34XKM2tjeI,5660
|
8
|
+
swiftshadow/types.py,sha256=Alyw3n54OESX1vSR-0kTvpYTlJ8LKfy5J9WZbtglHpE,894
|
9
|
+
swiftshadow/validator.py,sha256=dBcb6Lev6ojsk9f45IjyEUHZXsCcylyn6RoZA1WPDNQ,1345
|
10
|
+
swiftshadow-2.0.0.dist-info/METADATA,sha256=MSM2WB68lsN__C1JiNwMH2sPMah2GrPUoCwyNbPoF9U,3261
|
11
|
+
swiftshadow-2.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
12
|
+
swiftshadow-2.0.0.dist-info/entry_points.txt,sha256=yMj0uEagcmXK2dmMmNXWebTpTT9j5K03oaRrd2wkyLA,49
|
13
|
+
swiftshadow-2.0.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
14
|
+
swiftshadow-2.0.0.dist-info/RECORD,,
|
swiftshadow/constants.py
DELETED
@@ -1,250 +0,0 @@
|
|
1
|
-
CountryCodes = {
|
2
|
-
"Afghanistan": "AF",
|
3
|
-
"Åland Islands": "AX",
|
4
|
-
"Albania": "AL",
|
5
|
-
"Algeria": "DZ",
|
6
|
-
"American Samoa": "AS",
|
7
|
-
"Andorra": "AD",
|
8
|
-
"Angola": "AO",
|
9
|
-
"Anguilla": "AI",
|
10
|
-
"Antarctica": "AQ",
|
11
|
-
"Antigua and Barbuda": "AG",
|
12
|
-
"Argentina": "AR",
|
13
|
-
"Armenia": "AM",
|
14
|
-
"Aruba": "AW",
|
15
|
-
"Australia": "AU",
|
16
|
-
"Austria": "AT",
|
17
|
-
"Azerbaijan": "AZ",
|
18
|
-
"Bahamas": "BS",
|
19
|
-
"Bahrain": "BH",
|
20
|
-
"Bangladesh": "BD",
|
21
|
-
"Barbados": "BB",
|
22
|
-
"Belarus": "BY",
|
23
|
-
"Belgium": "BE",
|
24
|
-
"Belize": "BZ",
|
25
|
-
"Benin": "BJ",
|
26
|
-
"Bermuda": "BM",
|
27
|
-
"Bhutan": "BT",
|
28
|
-
"Bolivia (Plurinational State of)": "BO",
|
29
|
-
'"Bonaire': ' Sint Eustatius and Saba"',
|
30
|
-
"Bosnia and Herzegovina": "BA",
|
31
|
-
"Botswana": "BW",
|
32
|
-
"Bouvet Island": "BV",
|
33
|
-
"Brazil": "BR",
|
34
|
-
"British Indian Ocean Territory": "IO",
|
35
|
-
"Brunei Darussalam": "BN",
|
36
|
-
"Bulgaria": "BG",
|
37
|
-
"Burkina Faso": "BF",
|
38
|
-
"Burundi": "BI",
|
39
|
-
"Cabo Verde": "CV",
|
40
|
-
"Cambodia": "KH",
|
41
|
-
"Cameroon": "CM",
|
42
|
-
"Canada": "CA",
|
43
|
-
"Cayman Islands": "KY",
|
44
|
-
"Central African Republic": "CF",
|
45
|
-
"Chad": "TD",
|
46
|
-
"Chile": "CL",
|
47
|
-
"China": "CN",
|
48
|
-
"Christmas Island": "CX",
|
49
|
-
"Cocos (Keeling) Islands": "CC",
|
50
|
-
"Colombia": "CO",
|
51
|
-
"Comoros": "KM",
|
52
|
-
"Congo": "CG",
|
53
|
-
'"Congo': ' Democratic Republic of the"',
|
54
|
-
"Cook Islands": "CK",
|
55
|
-
"Costa Rica": "CR",
|
56
|
-
"Côte d'Ivoire": "CI",
|
57
|
-
"Croatia": "HR",
|
58
|
-
"Cuba": "CU",
|
59
|
-
"Curaçao": "CW",
|
60
|
-
"Cyprus": "CY",
|
61
|
-
"Czechia": "CZ",
|
62
|
-
"Denmark": "DK",
|
63
|
-
"Djibouti": "DJ",
|
64
|
-
"Dominica": "DM",
|
65
|
-
"Dominican Republic": "DO",
|
66
|
-
"Ecuador": "EC",
|
67
|
-
"Egypt": "EG",
|
68
|
-
"El Salvador": "SV",
|
69
|
-
"Equatorial Guinea": "GQ",
|
70
|
-
"Eritrea": "ER",
|
71
|
-
"Estonia": "EE",
|
72
|
-
"Eswatini": "SZ",
|
73
|
-
"Ethiopia": "ET",
|
74
|
-
"Falkland Islands (Malvinas)": "FK",
|
75
|
-
"Faroe Islands": "FO",
|
76
|
-
"Fiji": "FJ",
|
77
|
-
"Finland": "FI",
|
78
|
-
"France": "FR",
|
79
|
-
"French Guiana": "GF",
|
80
|
-
"French Polynesia": "PF",
|
81
|
-
"French Southern Territories": "TF",
|
82
|
-
"Gabon": "GA",
|
83
|
-
"Gambia": "GM",
|
84
|
-
"Georgia": "GE",
|
85
|
-
"Germany": "DE",
|
86
|
-
"Ghana": "GH",
|
87
|
-
"Gibraltar": "GI",
|
88
|
-
"Greece": "GR",
|
89
|
-
"Greenland": "GL",
|
90
|
-
"Grenada": "GD",
|
91
|
-
"Guadeloupe": "GP",
|
92
|
-
"Guam": "GU",
|
93
|
-
"Guatemala": "GT",
|
94
|
-
"Guernsey": "GG",
|
95
|
-
"Guinea": "GN",
|
96
|
-
"Guinea-Bissau": "GW",
|
97
|
-
"Guyana": "GY",
|
98
|
-
"Haiti": "HT",
|
99
|
-
"Heard Island and McDonald Islands": "HM",
|
100
|
-
"Holy See": "VA",
|
101
|
-
"Honduras": "HN",
|
102
|
-
"Hong Kong": "HK",
|
103
|
-
"Hungary": "HU",
|
104
|
-
"Iceland": "IS",
|
105
|
-
"India": "IN",
|
106
|
-
"Indonesia": "ID",
|
107
|
-
"Iran (Islamic Republic of)": "IR",
|
108
|
-
"Iraq": "IQ",
|
109
|
-
"Ireland": "IE",
|
110
|
-
"Isle of Man": "IM",
|
111
|
-
"Israel": "IL",
|
112
|
-
"Italy": "IT",
|
113
|
-
"Jamaica": "JM",
|
114
|
-
"Japan": "JP",
|
115
|
-
"Jersey": "JE",
|
116
|
-
"Jordan": "JO",
|
117
|
-
"Kazakhstan": "KZ",
|
118
|
-
"Kenya": "KE",
|
119
|
-
"Kiribati": "KI",
|
120
|
-
"Korea (Democratic People's Republic of)": "KP",
|
121
|
-
'"Korea': ' Republic of"',
|
122
|
-
"Kuwait": "KW",
|
123
|
-
"Kyrgyzstan": "KG",
|
124
|
-
"Lao People's Democratic Republic": "LA",
|
125
|
-
"Latvia": "LV",
|
126
|
-
"Lebanon": "LB",
|
127
|
-
"Lesotho": "LS",
|
128
|
-
"Liberia": "LR",
|
129
|
-
"Libya": "LY",
|
130
|
-
"Liechtenstein": "LI",
|
131
|
-
"Lithuania": "LT",
|
132
|
-
"Luxembourg": "LU",
|
133
|
-
"Macao": "MO",
|
134
|
-
"Madagascar": "MG",
|
135
|
-
"Malawi": "MW",
|
136
|
-
"Malaysia": "MY",
|
137
|
-
"Maldives": "MV",
|
138
|
-
"Mali": "ML",
|
139
|
-
"Malta": "MT",
|
140
|
-
"Marshall Islands": "MH",
|
141
|
-
"Martinique": "MQ",
|
142
|
-
"Mauritania": "MR",
|
143
|
-
"Mauritius": "MU",
|
144
|
-
"Mayotte": "YT",
|
145
|
-
"Mexico": "MX",
|
146
|
-
"Micronesia (Federated States of)": "FM",
|
147
|
-
'"Moldova': ' Republic of"',
|
148
|
-
"Monaco": "MC",
|
149
|
-
"Mongolia": "MN",
|
150
|
-
"Montenegro": "ME",
|
151
|
-
"Montserrat": "MS",
|
152
|
-
"Morocco": "MA",
|
153
|
-
"Mozambique": "MZ",
|
154
|
-
"Myanmar": "MM",
|
155
|
-
"Namibia": "NA",
|
156
|
-
"Nauru": "NR",
|
157
|
-
"Nepal": "NP",
|
158
|
-
"Netherlands": "NL",
|
159
|
-
"New Caledonia": "NC",
|
160
|
-
"New Zealand": "NZ",
|
161
|
-
"Nicaragua": "NI",
|
162
|
-
"Niger": "NE",
|
163
|
-
"Nigeria": "NG",
|
164
|
-
"Niue": "NU",
|
165
|
-
"Norfolk Island": "NF",
|
166
|
-
"North Macedonia": "MK",
|
167
|
-
"Northern Mariana Islands": "MP",
|
168
|
-
"Norway": "NO",
|
169
|
-
"Oman": "OM",
|
170
|
-
"Pakistan": "PK",
|
171
|
-
"Palau": "PW",
|
172
|
-
'"Palestine': ' State of"',
|
173
|
-
"Panama": "PA",
|
174
|
-
"Papua New Guinea": "PG",
|
175
|
-
"Paraguay": "PY",
|
176
|
-
"Peru": "PE",
|
177
|
-
"Philippines": "PH",
|
178
|
-
"Pitcairn": "PN",
|
179
|
-
"Poland": "PL",
|
180
|
-
"Portugal": "PT",
|
181
|
-
"Puerto Rico": "PR",
|
182
|
-
"Qatar": "QA",
|
183
|
-
"Réunion": "RE",
|
184
|
-
"Romania": "RO",
|
185
|
-
"Russian Federation": "RU",
|
186
|
-
"Rwanda": "RW",
|
187
|
-
"Saint Barthélemy": "BL",
|
188
|
-
'"Saint Helena': ' Ascension and Tristan da Cunha"',
|
189
|
-
"Saint Kitts and Nevis": "KN",
|
190
|
-
"Saint Lucia": "LC",
|
191
|
-
"Saint Martin (French part)": "MF",
|
192
|
-
"Saint Pierre and Miquelon": "PM",
|
193
|
-
"Saint Vincent and the Grenadines": "VC",
|
194
|
-
"Samoa": "WS",
|
195
|
-
"San Marino": "SM",
|
196
|
-
"Sao Tome and Principe": "ST",
|
197
|
-
"Saudi Arabia": "SA",
|
198
|
-
"Senegal": "SN",
|
199
|
-
"Serbia": "RS",
|
200
|
-
"Seychelles": "SC",
|
201
|
-
"Sierra Leone": "SL",
|
202
|
-
"Singapore": "SG",
|
203
|
-
"Sint Maarten (Dutch part)": "SX",
|
204
|
-
"Slovakia": "SK",
|
205
|
-
"Slovenia": "SI",
|
206
|
-
"Solomon Islands": "SB",
|
207
|
-
"Somalia": "SO",
|
208
|
-
"South Africa": "ZA",
|
209
|
-
"South Georgia and the South Sandwich Islands": "GS",
|
210
|
-
"South Sudan": "SS",
|
211
|
-
"Spain": "ES",
|
212
|
-
"Sri Lanka": "LK",
|
213
|
-
"Sudan": "SD",
|
214
|
-
"Suriname": "SR",
|
215
|
-
"Svalbard and Jan Mayen": "SJ",
|
216
|
-
"Sweden": "SE",
|
217
|
-
"Switzerland": "CH",
|
218
|
-
"Syrian Arab Republic": "SY",
|
219
|
-
'"Taiwan': ' Province of China"',
|
220
|
-
"Tajikistan": "TJ",
|
221
|
-
'"Tanzania': ' United Republic of"',
|
222
|
-
"Thailand": "TH",
|
223
|
-
"Timor-Leste": "TL",
|
224
|
-
"Togo": "TG",
|
225
|
-
"Tokelau": "TK",
|
226
|
-
"Tonga": "TO",
|
227
|
-
"Trinidad and Tobago": "TT",
|
228
|
-
"Tunisia": "TN",
|
229
|
-
"Turkey": "TR",
|
230
|
-
"Turkmenistan": "TM",
|
231
|
-
"Turks and Caicos Islands": "TC",
|
232
|
-
"Tuvalu": "TV",
|
233
|
-
"Uganda": "UG",
|
234
|
-
"Ukraine": "UA",
|
235
|
-
"United Arab Emirates": "AE",
|
236
|
-
"United Kingdom of Great Britain and Northern Ireland": "GB",
|
237
|
-
"United States of America": "US",
|
238
|
-
"United States Minor Outlying Islands": "UM",
|
239
|
-
"Uruguay": "UY",
|
240
|
-
"Uzbekistan": "UZ",
|
241
|
-
"Vanuatu": "VU",
|
242
|
-
"Venezuela (Bolivarian Republic of)": "VE",
|
243
|
-
"Viet Nam": "VN",
|
244
|
-
"Virgin Islands (British)": "VG",
|
245
|
-
"Virgin Islands (U.S.)": "VI",
|
246
|
-
"Wallis and Futuna": "WF",
|
247
|
-
"Western Sahara": "EH",
|
248
|
-
"Yemen": "YE",
|
249
|
-
"Zambia": "ZM",
|
250
|
-
}
|
@@ -1,54 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.1
|
2
|
-
Name: swiftshadow
|
3
|
-
Version: 1.2.0
|
4
|
-
Summary: Free IP Proxy rotator for python
|
5
|
-
Home-page: https://github.com/sachin-sankar/swiftshadow
|
6
|
-
Author: Sachin Sankar
|
7
|
-
Author-email: mail.sachinsankar@gmail.com
|
8
|
-
Classifier: Development Status :: 5 - Production/Stable
|
9
|
-
Description-Content-Type: text/markdown
|
10
|
-
License-File: LICENSE
|
11
|
-
Requires-Dist: requests
|
12
|
-
|
13
|
-
# Swiftshadow
|
14
|
-
|
15
|
-
![PyPI - Downloads](https://img.shields.io/pypi/dm/swiftshadow) ![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/sachin-sankar/swiftshadow?include_prereleases&style=flat)
|
16
|
-
|
17
|
-
> [!TIP]
|
18
|
-
> I'm refactoring the library for better speed and maintainability. Future updates might have breaking changes, but I'll keep you posted!
|
19
|
-
|
20
|
-
## About
|
21
|
-
|
22
|
-
Swiftshadow is a powerful Python library designed to simplify the process of rotating IP proxies for web scraping, data mining, and other automated tasks. With its advanced features, Swiftshadow can help you overcome many of the challenges associated with web scraping, including blocked IP addresses and other forms of detection.
|
23
|
-
|
24
|
-
One of the key benefits of Swiftshadow is its speed. The library is designed to operate quickly and efficiently, which means you can scrape data at a faster rate than with other tools. Additionally, Swiftshadow includes a built-in caching mechanism that helps to reduce the load time and improve performance.
|
25
|
-
|
26
|
-
Another important feature of Swiftshadow is its reliability. The library is designed to be robust and resilient, which means that even if one of your proxies fails or is blocked, the system will automatically switch to another proxy to ensure continuity of your scraping process. This feature helps to ensure that your scraping efforts are not interrupted by technical issues or other problems.
|
27
|
-
|
28
|
-
Swiftshadow is also highly customizable. You can easily configure the library to suit your specific needs, including specifying the number of proxies to use, the frequency of rotation, and other parameters. This level of flexibility makes Swiftshadow a versatile tool that can be adapted to a wide range of use cases.
|
29
|
-
|
30
|
-
Finally, Swiftshadow has a low dependency on third-party libraries (only one), which makes it easier to use and maintain. Whether you are a seasoned developer or a novice, you can quickly get started with Swiftshadow and start scraping data with ease.
|
31
|
-
|
32
|
-
## Installation
|
33
|
-
|
34
|
-
To get started install the library using pip.
|
35
|
-
|
36
|
-
``` py
|
37
|
-
pip install swiftshadow
|
38
|
-
```
|
39
|
-
|
40
|
-
## One class rules all
|
41
|
-
|
42
|
-
Everything in swiftshadow is under one class for ease of use and minimal code.
|
43
|
-
|
44
|
-
Get a proxy using just 2 lines of code!
|
45
|
-
|
46
|
-
``` py
|
47
|
-
from swiftshadow.swiftshadow import QuickProxy
|
48
|
-
|
49
|
-
print(QuickProxy())
|
50
|
-
```
|
51
|
-
|
52
|
-
That was easy.
|
53
|
-
|
54
|
-
Head to [Documentation](https://sachin-sankar.github.io/swiftshadow/) to get started.
|
@@ -1,11 +0,0 @@
|
|
1
|
-
swiftshadow/__init__.py,sha256=UGscPyIFECuTgLjcMxp9_QNyfxd6b-msRAtubenBAL0,764
|
2
|
-
swiftshadow/cache.py,sha256=tNj07m0Ii_r0wLu9NKTYxOyS8uYeC7BbgFdMnuLqK7Y,411
|
3
|
-
swiftshadow/classes.py,sha256=YlXuV5QobEwvIMQDt2sjT173Q-EQbGk6bz5nfyn0Cds,5249
|
4
|
-
swiftshadow/constants.py,sha256=FRhoYg8WNaLy8RLDD4BsANlXlY2tctBCdy7sCnkaVY0,6303
|
5
|
-
swiftshadow/helpers.py,sha256=RGC-Tq9vWqiddu_KEKYWc_URO-ISm3PXuMBqB_cl7XQ,533
|
6
|
-
swiftshadow/providers.py,sha256=qUYUxUuSifwuWWs3KxW2al_T5ee9Lr7MRaTddIR9lyw,2060
|
7
|
-
swiftshadow-1.2.0.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
8
|
-
swiftshadow-1.2.0.dist-info/METADATA,sha256=RRq0DPKJlgD1gboURK0gtCJ_Fq04P08hinNvz988BjY,2793
|
9
|
-
swiftshadow-1.2.0.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
|
10
|
-
swiftshadow-1.2.0.dist-info/top_level.txt,sha256=GClzVDF5vWSzqHOwgG2ycQAAJXRxd-QOdP1h3YrHOuM,12
|
11
|
-
swiftshadow-1.2.0.dist-info/RECORD,,
|
@@ -1 +0,0 @@
|
|
1
|
-
swiftshadow
|
File without changes
|