├── .gitignore ├── LICENSE.md ├── README.md ├── proxy_checker ├── __init__.py └── proxy_checker.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | cover/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | db.sqlite3-journal 64 | 65 | # Flask stuff: 66 | instance/ 67 | .webassets-cache 68 | 69 | # Scrapy stuff: 70 | .scrapy 71 | 72 | # Sphinx documentation 73 | docs/_build/ 74 | 75 | # PyBuilder 76 | .pybuilder/ 77 | target/ 78 | 79 | # Jupyter Notebook 80 | .ipynb_checkpoints 81 | 82 | # IPython 83 | profile_default/ 84 | ipython_config.py 85 | 86 | # pyenv 87 | # For a library or package, you might want to ignore these files since the code is 88 | # intended to run in multiple environments; otherwise, check them in: 89 | # .python-version 90 | 91 | # pipenv 92 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 93 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 94 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 95 | # install all needed dependencies. 96 | #Pipfile.lock 97 | 98 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 99 | __pypackages__/ 100 | 101 | # Celery stuff 102 | celerybeat-schedule 103 | celerybeat.pid 104 | 105 | # SageMath parsed files 106 | *.sage.py 107 | 108 | # Environments 109 | .env 110 | .venv 111 | env/ 112 | venv/ 113 | ENV/ 114 | env.bak/ 115 | venv.bak/ 116 | 117 | # Spyder project settings 118 | .spyderproject 119 | .spyproject 120 | 121 | # Rope project settings 122 | .ropeproject 123 | 124 | # mkdocs documentation 125 | /site 126 | 127 | # mypy 128 | .mypy_cache/ 129 | .dmypy.json 130 | dmypy.json 131 | 132 | # Pyre type checker 133 | .pyre/ 134 | 135 | # pytype static type analyzer 136 | .pytype/ 137 | 138 | # Cython debug symbols 139 | cython_debug/ 140 | 141 | .pypirc -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ricerati 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Proxy Checker (Python) 2 | 3 | [![Downloads](https://pepy.tech/badge/proxy-checker)](https://pepy.tech/project/proxy-checker) 4 | 5 | A proxy checker in Python using PycURL, a Python interface to libcurl. 6 | 7 | ## Description 8 | 9 | The proxy checker takes a proxy as input and uses it to send a request to a proxy judge (a website that outputs the information that was sent to it). If the request succeeds, the proxy checker will use the information it receives from the proxy judge to determine the proxy's: 10 | 11 | - Country 12 | - Protocol 13 | - Anonymity 14 | - Speed 15 | 16 | ## Installation 17 | 18 | ```console 19 | pip install proxy-checker 20 | ``` 21 | 22 | ## Usage 23 | 24 | ```python3 25 | from proxy_checker import ProxyChecker 26 | 27 | checker = ProxyChecker() 28 | checker.check_proxy(':') 29 | ``` 30 | 31 | ```json 32 | { 33 | "country": "United States", 34 | "country_code": "US", 35 | "protocols": ["socks4", "socks5"], 36 | "anonymity": "Elite", 37 | "timeout": 1649 38 | } 39 | ``` 40 | 41 | ## Parameters 42 | 43 | | Name | Type | Default | Description | 44 | | ------------- | ---- | ------- | ---------------------------------------------------- | 45 | | proxy | str | | The proxy to test | 46 | | check_country | bool | True | If `true`, the proxy's country will be looked up | 47 | | check_address | bool | False | If `true`, the proxy's remote address will looked up | 48 | | user | str | None | The proxy's username | 49 | | password | str | None | The proxy's password | 50 | 51 | ## Requirements 52 | 53 | - Python 3.\* 54 | - [PycURL](http://pycurl.io/) - A Python interface to libcurl \* 55 | 56 | ###### \* If you have trouble installing PycURL on Windows, try to use Christoph Gohlke's collection of [Python Extension Package for Windows](https://www.lfd.uci.edu/~gohlke/pythonlibs/#pycurl). 57 | 58 | ## Contributing 59 | 60 | Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. 61 | 62 | Please make sure to update tests as appropriate. 63 | 64 | ## License 65 | 66 | [MIT](LICENSE.md) 67 | -------------------------------------------------------------------------------- /proxy_checker/__init__.py: -------------------------------------------------------------------------------- 1 | from .proxy_checker import ProxyChecker 2 | -------------------------------------------------------------------------------- /proxy_checker/proxy_checker.py: -------------------------------------------------------------------------------- 1 | import pycurl 2 | from io import BytesIO 3 | import re 4 | import random 5 | import json 6 | 7 | 8 | class ProxyChecker: 9 | def __init__(self): 10 | self.ip = self.get_ip() 11 | self.proxy_judges = [ 12 | 'http://proxyjudge.us/azenv.php', 13 | 'http://mojeip.net.pl/asdfa/azenv.php' 14 | ] 15 | 16 | def get_ip(self): 17 | r = self.send_query(url='https://api.ipify.org/') 18 | 19 | if not r: 20 | return "" 21 | 22 | return r['response'] 23 | 24 | def send_query(self, proxy=False, url=None, user=None, password=None): 25 | response = BytesIO() 26 | c = pycurl.Curl() 27 | 28 | c.setopt(c.URL, url or random.choice(self.proxy_judges)) 29 | c.setopt(c.WRITEDATA, response) 30 | c.setopt(c.TIMEOUT, 5) 31 | 32 | if user is not None and password is not None: 33 | c.setopt(c.PROXYUSERPWD, f"{user}:{password}") 34 | 35 | c.setopt(c.SSL_VERIFYHOST, 0) 36 | c.setopt(c.SSL_VERIFYPEER, 0) 37 | 38 | if proxy: 39 | c.setopt(c.PROXY, proxy) 40 | 41 | # Perform request 42 | try: 43 | c.perform() 44 | except Exception as e: 45 | # print(e) 46 | return False 47 | 48 | # Return False if the status is not 200 49 | if c.getinfo(c.HTTP_CODE) != 200: 50 | return False 51 | 52 | # Calculate the request timeout in milliseconds 53 | timeout = round(c.getinfo(c.CONNECT_TIME) * 1000) 54 | 55 | # Decode the response content 56 | response = response.getvalue().decode('iso-8859-1') 57 | 58 | return { 59 | 'timeout': timeout, 60 | 'response': response 61 | } 62 | 63 | def parse_anonymity(self, r): 64 | if self.ip in r: 65 | return 'Transparent' 66 | 67 | privacy_headers = [ 68 | 'VIA', 69 | 'X-FORWARDED-FOR', 70 | 'X-FORWARDED', 71 | 'FORWARDED-FOR', 72 | 'FORWARDED-FOR-IP', 73 | 'FORWARDED', 74 | 'CLIENT-IP', 75 | 'PROXY-CONNECTION' 76 | ] 77 | 78 | if any([header in r for header in privacy_headers]): 79 | return 'Anonymous' 80 | 81 | return 'Elite' 82 | 83 | def get_country(self, ip): 84 | r = self.send_query(url='https://ip2c.org/' + ip) 85 | 86 | if r and r['response'][0] == '1': 87 | r = r['response'].split(';') 88 | return [r[3], r[1]] 89 | 90 | return ['-', '-'] 91 | 92 | def check_proxy(self, proxy, check_country=True, check_address=False, user=None, password=None): 93 | protocols = {} 94 | timeout = 0 95 | 96 | # Test the proxy for each protocol 97 | for protocol in ['http', 'socks4', 'socks5']: 98 | r = self.send_query(proxy=protocol + '://' + proxy, user=user, password=password) 99 | 100 | # Check if the request failed 101 | if not r: 102 | continue 103 | 104 | protocols[protocol] = r 105 | timeout += r['timeout'] 106 | 107 | # Check if the proxy failed all tests 108 | if (len(protocols) == 0): 109 | return False 110 | 111 | r = protocols[random.choice(list(protocols.keys()))]['response'] 112 | 113 | # Get country 114 | if check_country: 115 | country = self.get_country(proxy.split(':')[0]) 116 | 117 | # Check anonymity 118 | anonymity = self.parse_anonymity(r) 119 | 120 | # Check timeout 121 | timeout = timeout // len(protocols) 122 | 123 | # Check remote address 124 | if check_address: 125 | remote_regex = r'REMOTE_ADDR = (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' 126 | remote_addr = re.search(remote_regex, r) 127 | if remote_addr: 128 | remote_addr = remote_addr.group(1) 129 | 130 | results = { 131 | 'protocols': list(protocols.keys()), 132 | 'anonymity': anonymity, 133 | 'timeout': timeout 134 | } 135 | 136 | if check_country: 137 | results['country'] = country[0] 138 | results['country_code'] = country[1] 139 | 140 | if check_address: 141 | results['remote_address'] = remote_addr 142 | 143 | return results 144 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open('README.md', 'r') as f: 4 | long_description = f.read() 5 | 6 | setuptools.setup( 7 | name='proxy_checker', 8 | version='0.6', 9 | packages=['proxy_checker'], 10 | install_requires=['pycurl'], 11 | author='ricerati', 12 | description='Proxy checker in Python', 13 | long_description=long_description, 14 | long_description_content_type='text/markdown', 15 | keywords='proxy checker', 16 | project_urls={ 17 | 'Source Code': 'https://github.com/ricerati/proxy-checker-python' 18 | }, 19 | classifiers=[ 20 | 'License :: OSI Approved :: MIT License' 21 | ] 22 | ) 23 | --------------------------------------------------------------------------------