swiftshadow 1.0.2__py3-none-any.whl → 1.2.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 +11 -5
- swiftshadow/cache.py +0 -1
- swiftshadow/classes.py +37 -57
- swiftshadow/helpers.py +4 -16
- swiftshadow/providers.py +47 -42
- {swiftshadow-1.0.2.dist-info → swiftshadow-1.2.0.dist-info}/METADATA +5 -2
- swiftshadow-1.2.0.dist-info/RECORD +11 -0
- {swiftshadow-1.0.2.dist-info → swiftshadow-1.2.0.dist-info}/WHEEL +1 -1
- swiftshadow-1.0.2.dist-info/RECORD +0 -11
- {swiftshadow-1.0.2.dist-info → swiftshadow-1.2.0.dist-info}/LICENSE +0 -0
- {swiftshadow-1.0.2.dist-info → swiftshadow-1.2.0.dist-info}/top_level.txt +0 -0
swiftshadow/__init__.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from swiftshadow.providers import
|
1
|
+
from swiftshadow.providers import Providers
|
2
2
|
|
3
3
|
|
4
4
|
def QuickProxy(countries: list = [], protocol: str = "http"):
|
@@ -13,7 +13,13 @@ def QuickProxy(countries: list = [], protocol: str = "http"):
|
|
13
13
|
Returns:
|
14
14
|
proxyObject (dict): A working proxy object.
|
15
15
|
"""
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
for providerDict in Providers:
|
17
|
+
if protocol not in providerDict["protocols"]:
|
18
|
+
continue
|
19
|
+
if (len(countries) != 0) and (not providerDict["countryFilter"]):
|
20
|
+
continue
|
21
|
+
try:
|
22
|
+
return providerDict["provider"](1, countries, protocol)[0]
|
23
|
+
except:
|
24
|
+
continue
|
25
|
+
return None
|
swiftshadow/cache.py
CHANGED
swiftshadow/classes.py
CHANGED
@@ -2,9 +2,17 @@ from requests import get
|
|
2
2
|
from random import choice
|
3
3
|
from json import dump, load
|
4
4
|
from swiftshadow.helpers import log
|
5
|
-
from swiftshadow.providers import
|
5
|
+
from swiftshadow.providers import Providers
|
6
6
|
import swiftshadow.cache as cache
|
7
|
-
import
|
7
|
+
import logging
|
8
|
+
import sys
|
9
|
+
|
10
|
+
logger = logging.getLogger("swiftshadow")
|
11
|
+
logger.setLevel(logging.INFO)
|
12
|
+
logFormat = logging.Formatter("%(asctime)s - %(name)s [%(levelname)s]:%(message)s")
|
13
|
+
streamhandler = logging.StreamHandler(stream=sys.stdout)
|
14
|
+
streamhandler.setFormatter(logFormat)
|
15
|
+
logger.addHandler(streamhandler)
|
8
16
|
|
9
17
|
|
10
18
|
class Proxy:
|
@@ -16,6 +24,8 @@ class Proxy:
|
|
16
24
|
autoRotate: bool = False,
|
17
25
|
cachePeriod: int = 10,
|
18
26
|
cacheFolder: str = "",
|
27
|
+
debug: bool = False,
|
28
|
+
logToFile: bool = False,
|
19
29
|
):
|
20
30
|
"""
|
21
31
|
The one class for everything.
|
@@ -29,6 +39,8 @@ class Proxy:
|
|
29
39
|
autoRotate: Rotates proxy when `Proxy.proxy()` function is called.
|
30
40
|
cachePeriod: Time to cache proxies in minutes.
|
31
41
|
cacheFolder: Folder to store cache file.
|
42
|
+
debug: Sets Log Level to Debug.
|
43
|
+
logToFile: Whether to pipe log to a log file. If cacheFolder is set log file is saved there.
|
32
44
|
|
33
45
|
Returns:
|
34
46
|
proxyClass (swiftshadow.Proxy): `swiftshadow.Proxy` class instance
|
@@ -51,22 +63,17 @@ class Proxy:
|
|
51
63
|
self.cacheFilePath = ".swiftshadow.json"
|
52
64
|
else:
|
53
65
|
self.cacheFilePath = f"{cacheFolder}/.swiftshadow.json"
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
proxy = {ip[2]: ip[0]}
|
60
|
-
try:
|
61
|
-
oip = get(f"{protocol}://ipinfo.io/ip", proxies=proxy).text
|
62
|
-
except:
|
63
|
-
return False
|
64
|
-
if oip.count(".") == 3 and oip != self.mip:
|
65
|
-
return True
|
66
|
+
if debug:
|
67
|
+
logger.setLevel(logging.DEBUG)
|
68
|
+
if logToFile:
|
69
|
+
if cacheFolder == "":
|
70
|
+
logFilePath = "swiftshadow.log"
|
66
71
|
else:
|
67
|
-
|
68
|
-
|
69
|
-
|
72
|
+
logFilePath = f"{cacheFolder}/swiftshadow.log"
|
73
|
+
fileHandler = logging.FileHandler(logFilePath)
|
74
|
+
fileHandler.setFormatter(logFormat)
|
75
|
+
logger.addHandler(fileHandler)
|
76
|
+
self.update()
|
70
77
|
|
71
78
|
def update(self):
|
72
79
|
try:
|
@@ -75,8 +82,7 @@ class Proxy:
|
|
75
82
|
self.expiry = data[0]
|
76
83
|
expired = cache.checkExpiry(self.expiry)
|
77
84
|
if not expired:
|
78
|
-
|
79
|
-
"info",
|
85
|
+
logger.info(
|
80
86
|
"Loaded proxies from cache",
|
81
87
|
)
|
82
88
|
self.proxies = data[1]
|
@@ -84,22 +90,25 @@ class Proxy:
|
|
84
90
|
self.current = self.proxies[0]
|
85
91
|
return
|
86
92
|
else:
|
87
|
-
|
88
|
-
"
|
89
|
-
"Cache expired. Updating cache...",
|
93
|
+
logger.info(
|
94
|
+
"Cache expired. Updating cache.",
|
90
95
|
)
|
91
96
|
except FileNotFoundError:
|
92
|
-
|
97
|
+
logger.info("No cache found. Cache will be created after update")
|
93
98
|
|
94
99
|
self.proxies = []
|
95
|
-
|
96
|
-
|
100
|
+
for providerDict in Providers:
|
101
|
+
if self.protocol not in providerDict["protocols"]:
|
102
|
+
continue
|
103
|
+
if (len(self.countries) != 0) and (not providerDict["countryFilter"]):
|
104
|
+
continue
|
97
105
|
self.proxies.extend(
|
98
|
-
|
106
|
+
providerDict["provider"](self.maxProxies, self.countries, self.protocol)
|
99
107
|
)
|
108
|
+
if len(self.proxies) >= self.maxProxies:
|
109
|
+
break
|
100
110
|
if len(self.proxies) == 0:
|
101
|
-
|
102
|
-
"warning",
|
111
|
+
logger.warning(
|
103
112
|
"No proxies found for current settings. To prevent runtime error updating the proxy list again.",
|
104
113
|
)
|
105
114
|
self.update()
|
@@ -134,32 +143,3 @@ class Proxy:
|
|
134
143
|
return choice(self.proxies)
|
135
144
|
else:
|
136
145
|
return self.current
|
137
|
-
|
138
|
-
|
139
|
-
class ProxyChains:
|
140
|
-
def __init__(
|
141
|
-
self, countries: list = [], protocol: str = "http", maxProxies: int = 10
|
142
|
-
):
|
143
|
-
self.countries = [i.upper() for i in countries]
|
144
|
-
self.protocol = protocol
|
145
|
-
self.maxProxies = maxProxies
|
146
|
-
self.update()
|
147
|
-
|
148
|
-
def update(self):
|
149
|
-
proxies = []
|
150
|
-
for provider in Providers:
|
151
|
-
print(len(proxies))
|
152
|
-
if len(proxies) == self.maxProxies:
|
153
|
-
break
|
154
|
-
log("INFO", f"{provider}")
|
155
|
-
for proxyDict in provider(self.maxProxies, self.countries, self.protocol):
|
156
|
-
proxyRaw = list(proxyDict.items())[0]
|
157
|
-
proxy = f'{proxyRaw[0]} {proxyRaw[1].replace(":"," ")}'
|
158
|
-
proxies.append(proxy)
|
159
|
-
proxies = "\n".join(proxies)
|
160
|
-
configFileName = "swiftshadow-proxychains.conf"
|
161
|
-
config = f"random_chain\nchain_len=1\nproxy_dns\n[ProxyList]\n{proxies}"
|
162
|
-
with open(configFileName, "w") as file:
|
163
|
-
file.write(config)
|
164
|
-
cmd = f"proxychains -f {os.path.abspath(configFileName)}"
|
165
|
-
os.system(cmd)
|
swiftshadow/helpers.py
CHANGED
@@ -1,29 +1,17 @@
|
|
1
|
-
from swiftshadow.constants import CountryCodes
|
2
1
|
from requests import get
|
3
2
|
from datetime import datetime
|
4
3
|
|
5
4
|
|
6
|
-
def
|
7
|
-
try:
|
8
|
-
return CountryCodes[countryName]
|
9
|
-
except KeyError:
|
10
|
-
for name in list(CountryCodes.keys()):
|
11
|
-
if countryName in name:
|
12
|
-
return CountryCodes[name]
|
13
|
-
|
14
|
-
|
15
|
-
def checkProxy(proxy, countries):
|
16
|
-
if countries != []:
|
17
|
-
if proxy[-1].upper() not in countries:
|
18
|
-
return False
|
5
|
+
def checkProxy(proxy):
|
19
6
|
proxyDict = {proxy[1]: proxy[0]}
|
20
7
|
try:
|
21
|
-
resp = get(
|
8
|
+
resp = get(
|
9
|
+
f"{proxy[1]}://checkip.amazonaws.com", proxies=proxyDict, timeout=2
|
10
|
+
).text
|
22
11
|
if resp.count(".") == 3:
|
23
12
|
return True
|
24
13
|
return False
|
25
14
|
except Exception as e:
|
26
|
-
# log('error',str(e))
|
27
15
|
return False
|
28
16
|
|
29
17
|
|
swiftshadow/providers.py
CHANGED
@@ -1,52 +1,57 @@
|
|
1
1
|
from requests import get
|
2
|
-
from swiftshadow.helpers import
|
2
|
+
from swiftshadow.helpers import checkProxy
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
def Monosans(max, countries=[],protocol="http"):
|
5
|
+
raw = get('https://raw.githubusercontent.com/monosans/proxy-list/main/proxies.json').json()
|
6
|
+
results = []
|
7
7
|
count = 0
|
8
|
-
|
9
|
-
rows = [i.split("<td>") for i in raw.split("<tr>")]
|
10
|
-
|
11
|
-
def clean(text):
|
12
|
-
return text[: text.find("<")].strip()
|
13
|
-
|
14
|
-
for row in rows[2:]:
|
8
|
+
for proxy in raw:
|
15
9
|
if count == max:
|
16
|
-
return
|
17
|
-
|
18
|
-
|
10
|
+
return results
|
11
|
+
if proxy['protocol'] == protocol:
|
12
|
+
if len(countries) != 0 and proxy['geolocation']['country']['iso_code'] not in countries:
|
13
|
+
continue
|
14
|
+
proxy = [f'{proxy['host']}:{proxy['port']}',proxy['protocol']]
|
15
|
+
if checkProxy(proxy):
|
16
|
+
results.append(proxy)
|
17
|
+
count += 1
|
18
|
+
return results
|
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:
|
19
33
|
continue
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
if checkProxy(cleaned, countries):
|
26
|
-
result.append({cleaned[1]: cleaned[0]})
|
27
|
-
count += 1
|
28
|
-
return result
|
29
|
-
|
30
|
-
|
31
|
-
def Proxyscrape(max, countries=[], protocol="http"):
|
32
|
-
result = []
|
34
|
+
return results
|
35
|
+
|
36
|
+
def ProxyScrape(max,countries=[],protocol='http'):
|
37
|
+
baseUrl = 'https://api.proxyscrape.com/v3/free-proxy-list/get?request=displayproxies&protocol=http&proxy_format=ipport&format=json'
|
38
|
+
results = []
|
33
39
|
count = 0
|
34
|
-
|
35
|
-
|
36
|
-
query += "&country=all"
|
40
|
+
if len(countries) == 0:
|
41
|
+
apiUrl = baseUrl + '&country=all'
|
37
42
|
else:
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
ips = get(query).text
|
42
|
-
for ip in ips.split("\n"):
|
43
|
+
apiUrl = baseUrl + '&country=' + ','.join([i.upper() for i in countries])
|
44
|
+
raw = get(apiUrl).json()
|
45
|
+
for ipRaw in raw['proxies']:
|
43
46
|
if count == max:
|
44
|
-
|
45
|
-
proxy = [
|
46
|
-
if checkProxy(proxy
|
47
|
-
|
47
|
+
break
|
48
|
+
proxy = [ipRaw['proxy'],'http']
|
49
|
+
if checkProxy(proxy):
|
50
|
+
results.append(proxy)
|
48
51
|
count += 1
|
49
|
-
|
50
|
-
|
52
|
+
else:
|
53
|
+
print(proxy,False)
|
54
|
+
continue
|
55
|
+
return results
|
51
56
|
|
52
|
-
Providers = [
|
57
|
+
Providers = [{'provider':Monosans,'countryFilter':True,'protocols':['http']},{'provider':Thespeedx,'countryFilter':False,'protocols':['http']},{'provider':ProxyScrape,'countryFilter':True,'protocols':['http']}]
|
@@ -1,11 +1,11 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: swiftshadow
|
3
|
-
Version: 1.0
|
3
|
+
Version: 1.2.0
|
4
4
|
Summary: Free IP Proxy rotator for python
|
5
5
|
Home-page: https://github.com/sachin-sankar/swiftshadow
|
6
6
|
Author: Sachin Sankar
|
7
7
|
Author-email: mail.sachinsankar@gmail.com
|
8
|
-
Classifier: Development Status ::
|
8
|
+
Classifier: Development Status :: 5 - Production/Stable
|
9
9
|
Description-Content-Type: text/markdown
|
10
10
|
License-File: LICENSE
|
11
11
|
Requires-Dist: requests
|
@@ -14,6 +14,9 @@ Requires-Dist: requests
|
|
14
14
|
|
15
15
|
 
|
16
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
|
+
|
17
20
|
## About
|
18
21
|
|
19
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.
|
@@ -0,0 +1,11 @@
|
|
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,11 +0,0 @@
|
|
1
|
-
swiftshadow/__init__.py,sha256=cybIN6hvkK06k9aeun0YhhuUSZiEcIr6jdOne2WFWlA,604
|
2
|
-
swiftshadow/cache.py,sha256=2bQo7WqeyAMJkfLj4wRX5fPatZPaiaLVcn2gm_pzBFg,434
|
3
|
-
swiftshadow/classes.py,sha256=WSSZFwfRWuF2r0X0fb-J4IigmZkxox5EOr8uQQr0SWM,5773
|
4
|
-
swiftshadow/constants.py,sha256=FRhoYg8WNaLy8RLDD4BsANlXlY2tctBCdy7sCnkaVY0,6303
|
5
|
-
swiftshadow/helpers.py,sha256=C3iekcwN3ni4pFx0rV7EPYPqDglHCHMTtbWMPNNnOX8,917
|
6
|
-
swiftshadow/providers.py,sha256=GaVKg5J5hH2HSfdGDPuFivcCu6QB5HFjlVFvrrtNdhw,1490
|
7
|
-
swiftshadow-1.0.2.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
8
|
-
swiftshadow-1.0.2.dist-info/METADATA,sha256=zSImGEjSvlwxYj_h11atv5iHNaaZ25Eog50ft4ClcNo,2635
|
9
|
-
swiftshadow-1.0.2.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
10
|
-
swiftshadow-1.0.2.dist-info/top_level.txt,sha256=GClzVDF5vWSzqHOwgG2ycQAAJXRxd-QOdP1h3YrHOuM,12
|
11
|
-
swiftshadow-1.0.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|