proxy-scraper-cli 1.8.1__tar.gz → 1.10.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.
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/PKG-INFO +110 -12
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/README.md +108 -11
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxy_scraper_cli.egg-info/PKG-INFO +110 -12
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxy_scraper_cli.egg-info/SOURCES.txt +9 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxy_scraper_cli.egg-info/requires.txt +1 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/__init__.py +1 -1
- proxy_scraper_cli-1.10.0/proxyscraper/action.py +96 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/cli.py +20 -5
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/completion.py +61 -3
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/exporters.py +43 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/pages.py +7 -4
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/parsing.py +13 -8
- proxy_scraper_cli-1.10.0/proxyscraper/proxypages.py +241 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/publish.py +15 -1
- proxy_scraper_cli-1.10.0/proxyscraper/report.py +266 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/server/core.py +23 -11
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/site/index.html +163 -17
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/sites.py +45 -6
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/sources.py +3 -1
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/pyproject.toml +1 -1
- proxy_scraper_cli-1.10.0/tests/test_action.py +69 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_completion.py +35 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_exporters.py +22 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_mine_sources.py +8 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_parsing.py +7 -5
- proxy_scraper_cli-1.10.0/tests/test_parsing_fuzz.py +83 -0
- proxy_scraper_cli-1.10.0/tests/test_proxy_pages.py +93 -0
- proxy_scraper_cli-1.10.0/tests/test_report.py +119 -0
- proxy_scraper_cli-1.10.0/tests/test_server_closed_writer.py +72 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_sites.py +31 -1
- proxy_scraper_cli-1.10.0/tests/test_sources_json.py +36 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_uptime.py +12 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/LICENSE +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxy_scraper_cli.egg-info/dependency_links.txt +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxy_scraper_cli.egg-info/entry_points.txt +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxy_scraper_cli.egg-info/top_level.txt +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/__main__.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/agent.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/api.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/app.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/asndb.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/blocklist.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/charts.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/checker.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/compat.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/fetchcache.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/geo.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/geodb.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/handshake.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/history.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/judges.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/mcp_entry.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/mcp_server.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/netio.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/options.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/output.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/paths.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/pipeline.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/preferences.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/server/__init__.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/server/http.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/server/pool.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/server/socks.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/server/status.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/server/upstream.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/site/apple-touch-icon.png +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/site/googleaac1161b7853c5b5.html +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/site/logo.png +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/site/og.png +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/sources.json +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/targets.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/ui/__init__.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/ui/dashboard.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/ui/keys.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/ui/report.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/ui/serve.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/ui/widgets.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/proxyscraper/ui/wizard.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/setup.cfg +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_agent.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_api.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_app.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_asndb.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_auth.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_blocklist.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_charts.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_checker.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_compat.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_discovery_growth.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_fetchcache.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_geodb.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_judges.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_learning.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_live_api.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_mcp_server.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_options.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_output_stdout.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_packaging.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_pages.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_paths.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_pipeline.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_proxy_sources.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_publish.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_robustness.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_serve_password.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_serve_refill.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_serve_v2.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_server.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_server_fixes.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_tamper.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_targets.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_ui.py +0 -0
- {proxy_scraper_cli-1.8.1 → proxy_scraper_cli-1.10.0}/tests/test_wizard.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: proxy-scraper-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10.0
|
|
4
4
|
Summary: Finds free HTTP, SOCKS4 and SOCKS5 proxies that actually work: 700+ sources, real checks, honeypot filtering and a rotating local proxy server.
|
|
5
5
|
Author: Maximilian Feix
|
|
6
6
|
License-Expression: MIT
|
|
@@ -35,6 +35,7 @@ Provides-Extra: mcp
|
|
|
35
35
|
Requires-Dist: mcp<3,>=2.2; python_version >= "3.10" and extra == "mcp"
|
|
36
36
|
Provides-Extra: dev
|
|
37
37
|
Requires-Dist: pytest; extra == "dev"
|
|
38
|
+
Requires-Dist: hypothesis; extra == "dev"
|
|
38
39
|
Requires-Dist: ruff==0.16.8; extra == "dev"
|
|
39
40
|
Dynamic: license-file
|
|
40
41
|
|
|
@@ -138,11 +139,12 @@ python3 proxy_scraper.py
|
|
|
138
139
|
|
|
139
140
|
Every [release](https://github.com/maximilianfeix/proxy-scraper/releases/latest) also ships a wheel you can install with `pip install <file>.whl`, and a multi-arch image (amd64/arm64) on `ghcr.io`. In the container the wizard never shows up, it runs straight away. For the proxy server use `--serve --serve-host 0.0.0.0` with `-p 127.0.0.1:8899:8899`, so the port is only open on your own machine.
|
|
140
141
|
|
|
141
|
-
Tab completion for bash, zsh and
|
|
142
|
+
Tab completion for bash, zsh, fish and PowerShell:
|
|
142
143
|
|
|
143
144
|
```bash
|
|
144
145
|
eval "$(proxy-scraper --completion zsh)" # in ~/.zshrc (after compinit), same for bash in ~/.bashrc
|
|
145
146
|
proxy-scraper --completion fish > ~/.config/fish/completions/proxy-scraper.fish
|
|
147
|
+
proxy-scraper --completion powershell | Out-String | Invoke-Expression # in $PROFILE
|
|
146
148
|
```
|
|
147
149
|
|
|
148
150
|
Installed, the learned state lives in your user data folder (`~/Library/Application Support/proxy-scraper`, `%LOCALAPPDATA%\proxy-scraper` or `~/.local/share/proxy-scraper`; override with `PROXY_SCRAPER_HOME`) and results go to `./results`. Run from a clone, both stay inside the project.
|
|
@@ -578,14 +580,92 @@ for p in proxies:
|
|
|
578
580
|
continue # free proxies come and go – just take the next one
|
|
579
581
|
```
|
|
580
582
|
|
|
581
|
-
**
|
|
583
|
+
**httpx** (`pip install "httpx[socks]"`) – straight from the hourly list, no scan
|
|
584
|
+
|
|
585
|
+
```python
|
|
586
|
+
import httpx
|
|
587
|
+
from proxyscraper import live_proxies
|
|
588
|
+
|
|
589
|
+
for p in live_proxies(types=["http", "socks5"], https=True, min_uptime=90, limit=10): # httpx can't do SOCKS4
|
|
590
|
+
try:
|
|
591
|
+
with httpx.Client(proxy=p.url, timeout=10) as client:
|
|
592
|
+
print(p.url, "→", client.get("https://api.ipify.org").text)
|
|
593
|
+
break
|
|
594
|
+
except httpx.HTTPError:
|
|
595
|
+
continue # next one
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
**aiohttp** (`pip install aiohttp aiohttp-socks` – aiohttp alone can't do SOCKS)
|
|
599
|
+
|
|
600
|
+
```python
|
|
601
|
+
import asyncio
|
|
602
|
+
|
|
603
|
+
import aiohttp
|
|
604
|
+
from aiohttp_socks import ProxyConnector, ProxyError
|
|
605
|
+
from proxyscraper import live_proxies_async
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
async def main():
|
|
609
|
+
for p in await live_proxies_async(https=True, min_uptime=90, limit=10):
|
|
610
|
+
try:
|
|
611
|
+
async with aiohttp.ClientSession(connector=ProxyConnector.from_url(p.url)) as session:
|
|
612
|
+
async with session.get("https://api.ipify.org", timeout=aiohttp.ClientTimeout(total=10)) as r:
|
|
613
|
+
print(p.url, "→", await r.text())
|
|
614
|
+
return
|
|
615
|
+
except (aiohttp.ClientError, ProxyError, asyncio.TimeoutError, OSError):
|
|
616
|
+
continue # free proxies come and go – just take the next one
|
|
617
|
+
|
|
618
|
+
asyncio.run(main())
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
**Scrapy** – a downloader middleware that sends every request, retries included, through the next proxy. Scrapy only speaks HTTP proxies, `https=True` picks the ones that can tunnel `https://` pages
|
|
622
|
+
|
|
623
|
+
```python
|
|
624
|
+
import itertools
|
|
625
|
+
|
|
626
|
+
import scrapy
|
|
627
|
+
from scrapy.crawler import CrawlerProcess
|
|
628
|
+
from proxyscraper import live_proxies
|
|
629
|
+
|
|
630
|
+
PROXIES = [p.url for p in live_proxies(types="http", https=True, min_uptime=50)]
|
|
631
|
+
if not PROXIES:
|
|
632
|
+
raise SystemExit("No proxy matches right now – loosen the filters (e.g. min_uptime)")
|
|
633
|
+
POOL = itertools.cycle(PROXIES)
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
class RotatingProxy:
|
|
637
|
+
def process_request(self, request, spider=None): # newer Scrapy leaves out spider
|
|
638
|
+
request.meta["proxy"] = next(POOL)
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
class IpSpider(scrapy.Spider):
|
|
642
|
+
name = "ip"
|
|
643
|
+
start_urls = [f"https://api.ipify.org/?n={i}" for i in range(3)]
|
|
644
|
+
custom_settings = {
|
|
645
|
+
"DOWNLOADER_MIDDLEWARES": {f"{__name__}.RotatingProxy": 350},
|
|
646
|
+
"RETRY_TIMES": 5, "DOWNLOAD_TIMEOUT": 15,
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
def parse(self, response):
|
|
650
|
+
print(response.meta["proxy"], "→", response.text)
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
if __name__ == "__main__":
|
|
654
|
+
process = CrawlerProcess()
|
|
655
|
+
process.crawl(IpSpider)
|
|
656
|
+
process.start()
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
In a Scrapy project, put `RotatingProxy` in `middlewares.py` and add it to `DOWNLOADER_MIDDLEWARES` in `settings.py`. For long crawls, reload the pool now and then – the list changes every hour.
|
|
660
|
+
|
|
661
|
+
**proxychains, Clash / Mihomo, sing-box** – ready-made configs with `--export`
|
|
582
662
|
|
|
583
663
|
```bash
|
|
584
|
-
proxy-scraper --want 30 -y --export proxychains,clash
|
|
664
|
+
proxy-scraper --want 30 -y --export proxychains,clash,singbox
|
|
585
665
|
proxychains4 -f results/latest/proxychains.conf curl https://api.ipify.org
|
|
586
666
|
```
|
|
587
667
|
|
|
588
|
-
`clash.yaml` has all HTTP and SOCKS5 proxies plus a `url-test` group that always picks the fastest.
|
|
668
|
+
`clash.yaml` has all HTTP and SOCKS5 proxies plus a `url-test` group that always picks the fastest. `singbox.json` does the same for sing-box, SOCKS4 included, and opens a local proxy: `sing-box run -c results/latest/singbox.json`, then use `127.0.0.1:2080` as HTTP or SOCKS5 proxy. All three leave out HTTP proxies that can't tunnel (`CONNECT`), because these tools tunnel everything.
|
|
589
669
|
|
|
590
670
|
**In a pipe** – `-o -` prints the hits to stdout, the interface moves to stderr
|
|
591
671
|
|
|
@@ -601,6 +681,22 @@ export HTTPS_PROXY=http://127.0.0.1:8899 HTTP_PROXY=http://127.0.0.1:8899
|
|
|
601
681
|
pip download requests # git, pip, npm & co. now go through the pool
|
|
602
682
|
```
|
|
603
683
|
|
|
684
|
+
**In a GitHub workflow** – the action picks working proxies for the next steps
|
|
685
|
+
|
|
686
|
+
```yaml
|
|
687
|
+
- id: proxies
|
|
688
|
+
uses: maximilianfeix/proxy-scraper@v1
|
|
689
|
+
with:
|
|
690
|
+
types: socks5
|
|
691
|
+
https: true
|
|
692
|
+
min-uptime: 90 # on the list for 90 %+ of the week
|
|
693
|
+
works-on: google # optional: google, reddit, amazon
|
|
694
|
+
recheck: true # optional: check them again from the runner
|
|
695
|
+
- run: curl -x "${{ steps.proxies.outputs.proxy }}" https://api.ipify.org
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
`proxy` is the fastest one, `file` a text file with all of them (up to `limit`, default 20), `count` how many. Without a match the step fails, unless `fail-if-empty: false`.
|
|
699
|
+
|
|
604
700
|
**Without installing anything** – straight from the live list
|
|
605
701
|
|
|
606
702
|
```bash
|
|
@@ -644,16 +740,16 @@ curl.exe -x (Get-Content "$run\all.txt" -TotalCount 1) http://api.ipify.org
|
|
|
644
740
|
| `-t`, `--timeout S` | timeout per proxy (default: 8 s) |
|
|
645
741
|
| `--discover` | search GitHub for new sources right now |
|
|
646
742
|
| `--no-cache` | download every list again (unchanged ones are normally skipped via ETag) |
|
|
647
|
-
| `--list-sources [N]` | show the source ranking |
|
|
743
|
+
| `--list-sources [N]` | show the source ranking (add `--json` for scripts: url, status, hit rate, checks, last change) |
|
|
648
744
|
| `--serve-host ADDR` | where the proxy server listens (default `127.0.0.1`; `0.0.0.0` for Docker, with a warning) |
|
|
649
745
|
| `--serve-password SECRET` | clients must send this password in the proxy login; better set `PROXY_SCRAPER_SERVE_PASSWORD` |
|
|
650
746
|
| `--rotate STRATEGY` · `--sticky SEC` | how the proxy server picks proxies, see [above](#proxy-server) |
|
|
651
747
|
| `--serve-refill HOURS` | while serving, check fresh proxies every HOURS and add the hits to the pool |
|
|
652
748
|
| `--serve [PORT]` | afterwards serve as a rotating proxy on `127.0.0.1:PORT` (default: 8899) |
|
|
653
749
|
| `-o FILE` | also write all hits to this file; `-o -` prints them to stdout |
|
|
654
|
-
| `--export FORMATS` | extra files for other tools: `proxychains`, `clash`, `curl` or `all` |
|
|
750
|
+
| `--export FORMATS` | extra files for other tools: `proxychains`, `clash`, `singbox`, `curl` or `all` |
|
|
655
751
|
| `-V`, `--version` | print the version |
|
|
656
|
-
| `--completion SHELL` | print the tab completion script for bash, zsh or
|
|
752
|
+
| `--completion SHELL` | print the tab completion script for bash, zsh, fish or PowerShell |
|
|
657
753
|
|
|
658
754
|
Everything else: `proxy-scraper --help`
|
|
659
755
|
|
|
@@ -735,10 +831,12 @@ Only for things that don't matter. Public proxies are run by strangers who can r
|
|
|
735
831
|
|
|
736
832
|
## Roadmap
|
|
737
833
|
|
|
738
|
-
What's next is
|
|
834
|
+
What's next is in the [open issues](../../issues) – ideas and wishes are welcome as an [issue](../../issues/new/choose). During Hacktoberfest there are [beginner-friendly issues](../../issues?q=is%3Aopen+label%3Ahacktoberfest) with pointers on where to start.
|
|
835
|
+
|
|
836
|
+
- [ ] [Measure throughput, not just latency](../../issues/140)
|
|
837
|
+
- [ ] [Daily snapshots as a dataset](../../issues/143)
|
|
739
838
|
|
|
740
|
-
|
|
741
|
-
- [ ] [sing-box export](../../issues/113), [PowerShell completion](../../issues/114), [shareable filters on the website](../../issues/116)
|
|
839
|
+
Shipped in v1.8 and v1.9: uptime per proxy and `stable.txt`, which proxies get through to Google, Reddit and Amazon, `live_proxies()` in Python, a page per proxy with its week of checks, a weekly report, live charts in this README, shareable filters on the website, sources mined from other scrapers' lists, untyped lists tried as HTTP and SOCKS5, `--export singbox`, PowerShell completion and recipes for httpx, aiohttp and Scrapy.
|
|
742
840
|
|
|
743
841
|
Shipped in [v1.7](../../milestone/7): an MCP server so AI agents get working proxies and can load pages through them, 28 new sources and a GitHub search that runs daily and keeps what it found, and a cleaner website.
|
|
744
842
|
|
|
@@ -783,7 +881,7 @@ proxyscraper/
|
|
|
783
881
|
├── geodb.py DB-IP country database (monthly, binary search)
|
|
784
882
|
├── targets.py target sites for --target
|
|
785
883
|
├── output.py result files
|
|
786
|
-
├── exporters.py proxychains, Clash and curl formats (--export)
|
|
884
|
+
├── exporters.py proxychains, Clash, sing-box and curl formats (--export)
|
|
787
885
|
├── server/ rotating proxy server (--serve): pool · http · upstream · socks · status · core
|
|
788
886
|
├── api.py find_proxies() / check_proxies() for Python
|
|
789
887
|
├── agent.py MCP tools without the SDK: live list, filters, fetch through proxies
|
|
@@ -98,11 +98,12 @@ python3 proxy_scraper.py
|
|
|
98
98
|
|
|
99
99
|
Every [release](https://github.com/maximilianfeix/proxy-scraper/releases/latest) also ships a wheel you can install with `pip install <file>.whl`, and a multi-arch image (amd64/arm64) on `ghcr.io`. In the container the wizard never shows up, it runs straight away. For the proxy server use `--serve --serve-host 0.0.0.0` with `-p 127.0.0.1:8899:8899`, so the port is only open on your own machine.
|
|
100
100
|
|
|
101
|
-
Tab completion for bash, zsh and
|
|
101
|
+
Tab completion for bash, zsh, fish and PowerShell:
|
|
102
102
|
|
|
103
103
|
```bash
|
|
104
104
|
eval "$(proxy-scraper --completion zsh)" # in ~/.zshrc (after compinit), same for bash in ~/.bashrc
|
|
105
105
|
proxy-scraper --completion fish > ~/.config/fish/completions/proxy-scraper.fish
|
|
106
|
+
proxy-scraper --completion powershell | Out-String | Invoke-Expression # in $PROFILE
|
|
106
107
|
```
|
|
107
108
|
|
|
108
109
|
Installed, the learned state lives in your user data folder (`~/Library/Application Support/proxy-scraper`, `%LOCALAPPDATA%\proxy-scraper` or `~/.local/share/proxy-scraper`; override with `PROXY_SCRAPER_HOME`) and results go to `./results`. Run from a clone, both stay inside the project.
|
|
@@ -538,14 +539,92 @@ for p in proxies:
|
|
|
538
539
|
continue # free proxies come and go – just take the next one
|
|
539
540
|
```
|
|
540
541
|
|
|
541
|
-
**
|
|
542
|
+
**httpx** (`pip install "httpx[socks]"`) – straight from the hourly list, no scan
|
|
543
|
+
|
|
544
|
+
```python
|
|
545
|
+
import httpx
|
|
546
|
+
from proxyscraper import live_proxies
|
|
547
|
+
|
|
548
|
+
for p in live_proxies(types=["http", "socks5"], https=True, min_uptime=90, limit=10): # httpx can't do SOCKS4
|
|
549
|
+
try:
|
|
550
|
+
with httpx.Client(proxy=p.url, timeout=10) as client:
|
|
551
|
+
print(p.url, "→", client.get("https://api.ipify.org").text)
|
|
552
|
+
break
|
|
553
|
+
except httpx.HTTPError:
|
|
554
|
+
continue # next one
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
**aiohttp** (`pip install aiohttp aiohttp-socks` – aiohttp alone can't do SOCKS)
|
|
558
|
+
|
|
559
|
+
```python
|
|
560
|
+
import asyncio
|
|
561
|
+
|
|
562
|
+
import aiohttp
|
|
563
|
+
from aiohttp_socks import ProxyConnector, ProxyError
|
|
564
|
+
from proxyscraper import live_proxies_async
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
async def main():
|
|
568
|
+
for p in await live_proxies_async(https=True, min_uptime=90, limit=10):
|
|
569
|
+
try:
|
|
570
|
+
async with aiohttp.ClientSession(connector=ProxyConnector.from_url(p.url)) as session:
|
|
571
|
+
async with session.get("https://api.ipify.org", timeout=aiohttp.ClientTimeout(total=10)) as r:
|
|
572
|
+
print(p.url, "→", await r.text())
|
|
573
|
+
return
|
|
574
|
+
except (aiohttp.ClientError, ProxyError, asyncio.TimeoutError, OSError):
|
|
575
|
+
continue # free proxies come and go – just take the next one
|
|
576
|
+
|
|
577
|
+
asyncio.run(main())
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**Scrapy** – a downloader middleware that sends every request, retries included, through the next proxy. Scrapy only speaks HTTP proxies, `https=True` picks the ones that can tunnel `https://` pages
|
|
581
|
+
|
|
582
|
+
```python
|
|
583
|
+
import itertools
|
|
584
|
+
|
|
585
|
+
import scrapy
|
|
586
|
+
from scrapy.crawler import CrawlerProcess
|
|
587
|
+
from proxyscraper import live_proxies
|
|
588
|
+
|
|
589
|
+
PROXIES = [p.url for p in live_proxies(types="http", https=True, min_uptime=50)]
|
|
590
|
+
if not PROXIES:
|
|
591
|
+
raise SystemExit("No proxy matches right now – loosen the filters (e.g. min_uptime)")
|
|
592
|
+
POOL = itertools.cycle(PROXIES)
|
|
593
|
+
|
|
594
|
+
|
|
595
|
+
class RotatingProxy:
|
|
596
|
+
def process_request(self, request, spider=None): # newer Scrapy leaves out spider
|
|
597
|
+
request.meta["proxy"] = next(POOL)
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
class IpSpider(scrapy.Spider):
|
|
601
|
+
name = "ip"
|
|
602
|
+
start_urls = [f"https://api.ipify.org/?n={i}" for i in range(3)]
|
|
603
|
+
custom_settings = {
|
|
604
|
+
"DOWNLOADER_MIDDLEWARES": {f"{__name__}.RotatingProxy": 350},
|
|
605
|
+
"RETRY_TIMES": 5, "DOWNLOAD_TIMEOUT": 15,
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
def parse(self, response):
|
|
609
|
+
print(response.meta["proxy"], "→", response.text)
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
if __name__ == "__main__":
|
|
613
|
+
process = CrawlerProcess()
|
|
614
|
+
process.crawl(IpSpider)
|
|
615
|
+
process.start()
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
In a Scrapy project, put `RotatingProxy` in `middlewares.py` and add it to `DOWNLOADER_MIDDLEWARES` in `settings.py`. For long crawls, reload the pool now and then – the list changes every hour.
|
|
619
|
+
|
|
620
|
+
**proxychains, Clash / Mihomo, sing-box** – ready-made configs with `--export`
|
|
542
621
|
|
|
543
622
|
```bash
|
|
544
|
-
proxy-scraper --want 30 -y --export proxychains,clash
|
|
623
|
+
proxy-scraper --want 30 -y --export proxychains,clash,singbox
|
|
545
624
|
proxychains4 -f results/latest/proxychains.conf curl https://api.ipify.org
|
|
546
625
|
```
|
|
547
626
|
|
|
548
|
-
`clash.yaml` has all HTTP and SOCKS5 proxies plus a `url-test` group that always picks the fastest.
|
|
627
|
+
`clash.yaml` has all HTTP and SOCKS5 proxies plus a `url-test` group that always picks the fastest. `singbox.json` does the same for sing-box, SOCKS4 included, and opens a local proxy: `sing-box run -c results/latest/singbox.json`, then use `127.0.0.1:2080` as HTTP or SOCKS5 proxy. All three leave out HTTP proxies that can't tunnel (`CONNECT`), because these tools tunnel everything.
|
|
549
628
|
|
|
550
629
|
**In a pipe** – `-o -` prints the hits to stdout, the interface moves to stderr
|
|
551
630
|
|
|
@@ -561,6 +640,22 @@ export HTTPS_PROXY=http://127.0.0.1:8899 HTTP_PROXY=http://127.0.0.1:8899
|
|
|
561
640
|
pip download requests # git, pip, npm & co. now go through the pool
|
|
562
641
|
```
|
|
563
642
|
|
|
643
|
+
**In a GitHub workflow** – the action picks working proxies for the next steps
|
|
644
|
+
|
|
645
|
+
```yaml
|
|
646
|
+
- id: proxies
|
|
647
|
+
uses: maximilianfeix/proxy-scraper@v1
|
|
648
|
+
with:
|
|
649
|
+
types: socks5
|
|
650
|
+
https: true
|
|
651
|
+
min-uptime: 90 # on the list for 90 %+ of the week
|
|
652
|
+
works-on: google # optional: google, reddit, amazon
|
|
653
|
+
recheck: true # optional: check them again from the runner
|
|
654
|
+
- run: curl -x "${{ steps.proxies.outputs.proxy }}" https://api.ipify.org
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
`proxy` is the fastest one, `file` a text file with all of them (up to `limit`, default 20), `count` how many. Without a match the step fails, unless `fail-if-empty: false`.
|
|
658
|
+
|
|
564
659
|
**Without installing anything** – straight from the live list
|
|
565
660
|
|
|
566
661
|
```bash
|
|
@@ -604,16 +699,16 @@ curl.exe -x (Get-Content "$run\all.txt" -TotalCount 1) http://api.ipify.org
|
|
|
604
699
|
| `-t`, `--timeout S` | timeout per proxy (default: 8 s) |
|
|
605
700
|
| `--discover` | search GitHub for new sources right now |
|
|
606
701
|
| `--no-cache` | download every list again (unchanged ones are normally skipped via ETag) |
|
|
607
|
-
| `--list-sources [N]` | show the source ranking |
|
|
702
|
+
| `--list-sources [N]` | show the source ranking (add `--json` for scripts: url, status, hit rate, checks, last change) |
|
|
608
703
|
| `--serve-host ADDR` | where the proxy server listens (default `127.0.0.1`; `0.0.0.0` for Docker, with a warning) |
|
|
609
704
|
| `--serve-password SECRET` | clients must send this password in the proxy login; better set `PROXY_SCRAPER_SERVE_PASSWORD` |
|
|
610
705
|
| `--rotate STRATEGY` · `--sticky SEC` | how the proxy server picks proxies, see [above](#proxy-server) |
|
|
611
706
|
| `--serve-refill HOURS` | while serving, check fresh proxies every HOURS and add the hits to the pool |
|
|
612
707
|
| `--serve [PORT]` | afterwards serve as a rotating proxy on `127.0.0.1:PORT` (default: 8899) |
|
|
613
708
|
| `-o FILE` | also write all hits to this file; `-o -` prints them to stdout |
|
|
614
|
-
| `--export FORMATS` | extra files for other tools: `proxychains`, `clash`, `curl` or `all` |
|
|
709
|
+
| `--export FORMATS` | extra files for other tools: `proxychains`, `clash`, `singbox`, `curl` or `all` |
|
|
615
710
|
| `-V`, `--version` | print the version |
|
|
616
|
-
| `--completion SHELL` | print the tab completion script for bash, zsh or
|
|
711
|
+
| `--completion SHELL` | print the tab completion script for bash, zsh, fish or PowerShell |
|
|
617
712
|
|
|
618
713
|
Everything else: `proxy-scraper --help`
|
|
619
714
|
|
|
@@ -695,10 +790,12 @@ Only for things that don't matter. Public proxies are run by strangers who can r
|
|
|
695
790
|
|
|
696
791
|
## Roadmap
|
|
697
792
|
|
|
698
|
-
What's next is
|
|
793
|
+
What's next is in the [open issues](../../issues) – ideas and wishes are welcome as an [issue](../../issues/new/choose). During Hacktoberfest there are [beginner-friendly issues](../../issues?q=is%3Aopen+label%3Ahacktoberfest) with pointers on where to start.
|
|
794
|
+
|
|
795
|
+
- [ ] [Measure throughput, not just latency](../../issues/140)
|
|
796
|
+
- [ ] [Daily snapshots as a dataset](../../issues/143)
|
|
699
797
|
|
|
700
|
-
|
|
701
|
-
- [ ] [sing-box export](../../issues/113), [PowerShell completion](../../issues/114), [shareable filters on the website](../../issues/116)
|
|
798
|
+
Shipped in v1.8 and v1.9: uptime per proxy and `stable.txt`, which proxies get through to Google, Reddit and Amazon, `live_proxies()` in Python, a page per proxy with its week of checks, a weekly report, live charts in this README, shareable filters on the website, sources mined from other scrapers' lists, untyped lists tried as HTTP and SOCKS5, `--export singbox`, PowerShell completion and recipes for httpx, aiohttp and Scrapy.
|
|
702
799
|
|
|
703
800
|
Shipped in [v1.7](../../milestone/7): an MCP server so AI agents get working proxies and can load pages through them, 28 new sources and a GitHub search that runs daily and keeps what it found, and a cleaner website.
|
|
704
801
|
|
|
@@ -743,7 +840,7 @@ proxyscraper/
|
|
|
743
840
|
├── geodb.py DB-IP country database (monthly, binary search)
|
|
744
841
|
├── targets.py target sites for --target
|
|
745
842
|
├── output.py result files
|
|
746
|
-
├── exporters.py proxychains, Clash and curl formats (--export)
|
|
843
|
+
├── exporters.py proxychains, Clash, sing-box and curl formats (--export)
|
|
747
844
|
├── server/ rotating proxy server (--serve): pool · http · upstream · socks · status · core
|
|
748
845
|
├── api.py find_proxies() / check_proxies() for Python
|
|
749
846
|
├── agent.py MCP tools without the SDK: live list, filters, fetch through proxies
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: proxy-scraper-cli
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.10.0
|
|
4
4
|
Summary: Finds free HTTP, SOCKS4 and SOCKS5 proxies that actually work: 700+ sources, real checks, honeypot filtering and a rotating local proxy server.
|
|
5
5
|
Author: Maximilian Feix
|
|
6
6
|
License-Expression: MIT
|
|
@@ -35,6 +35,7 @@ Provides-Extra: mcp
|
|
|
35
35
|
Requires-Dist: mcp<3,>=2.2; python_version >= "3.10" and extra == "mcp"
|
|
36
36
|
Provides-Extra: dev
|
|
37
37
|
Requires-Dist: pytest; extra == "dev"
|
|
38
|
+
Requires-Dist: hypothesis; extra == "dev"
|
|
38
39
|
Requires-Dist: ruff==0.16.8; extra == "dev"
|
|
39
40
|
Dynamic: license-file
|
|
40
41
|
|
|
@@ -138,11 +139,12 @@ python3 proxy_scraper.py
|
|
|
138
139
|
|
|
139
140
|
Every [release](https://github.com/maximilianfeix/proxy-scraper/releases/latest) also ships a wheel you can install with `pip install <file>.whl`, and a multi-arch image (amd64/arm64) on `ghcr.io`. In the container the wizard never shows up, it runs straight away. For the proxy server use `--serve --serve-host 0.0.0.0` with `-p 127.0.0.1:8899:8899`, so the port is only open on your own machine.
|
|
140
141
|
|
|
141
|
-
Tab completion for bash, zsh and
|
|
142
|
+
Tab completion for bash, zsh, fish and PowerShell:
|
|
142
143
|
|
|
143
144
|
```bash
|
|
144
145
|
eval "$(proxy-scraper --completion zsh)" # in ~/.zshrc (after compinit), same for bash in ~/.bashrc
|
|
145
146
|
proxy-scraper --completion fish > ~/.config/fish/completions/proxy-scraper.fish
|
|
147
|
+
proxy-scraper --completion powershell | Out-String | Invoke-Expression # in $PROFILE
|
|
146
148
|
```
|
|
147
149
|
|
|
148
150
|
Installed, the learned state lives in your user data folder (`~/Library/Application Support/proxy-scraper`, `%LOCALAPPDATA%\proxy-scraper` or `~/.local/share/proxy-scraper`; override with `PROXY_SCRAPER_HOME`) and results go to `./results`. Run from a clone, both stay inside the project.
|
|
@@ -578,14 +580,92 @@ for p in proxies:
|
|
|
578
580
|
continue # free proxies come and go – just take the next one
|
|
579
581
|
```
|
|
580
582
|
|
|
581
|
-
**
|
|
583
|
+
**httpx** (`pip install "httpx[socks]"`) – straight from the hourly list, no scan
|
|
584
|
+
|
|
585
|
+
```python
|
|
586
|
+
import httpx
|
|
587
|
+
from proxyscraper import live_proxies
|
|
588
|
+
|
|
589
|
+
for p in live_proxies(types=["http", "socks5"], https=True, min_uptime=90, limit=10): # httpx can't do SOCKS4
|
|
590
|
+
try:
|
|
591
|
+
with httpx.Client(proxy=p.url, timeout=10) as client:
|
|
592
|
+
print(p.url, "→", client.get("https://api.ipify.org").text)
|
|
593
|
+
break
|
|
594
|
+
except httpx.HTTPError:
|
|
595
|
+
continue # next one
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
**aiohttp** (`pip install aiohttp aiohttp-socks` – aiohttp alone can't do SOCKS)
|
|
599
|
+
|
|
600
|
+
```python
|
|
601
|
+
import asyncio
|
|
602
|
+
|
|
603
|
+
import aiohttp
|
|
604
|
+
from aiohttp_socks import ProxyConnector, ProxyError
|
|
605
|
+
from proxyscraper import live_proxies_async
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
async def main():
|
|
609
|
+
for p in await live_proxies_async(https=True, min_uptime=90, limit=10):
|
|
610
|
+
try:
|
|
611
|
+
async with aiohttp.ClientSession(connector=ProxyConnector.from_url(p.url)) as session:
|
|
612
|
+
async with session.get("https://api.ipify.org", timeout=aiohttp.ClientTimeout(total=10)) as r:
|
|
613
|
+
print(p.url, "→", await r.text())
|
|
614
|
+
return
|
|
615
|
+
except (aiohttp.ClientError, ProxyError, asyncio.TimeoutError, OSError):
|
|
616
|
+
continue # free proxies come and go – just take the next one
|
|
617
|
+
|
|
618
|
+
asyncio.run(main())
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
**Scrapy** – a downloader middleware that sends every request, retries included, through the next proxy. Scrapy only speaks HTTP proxies, `https=True` picks the ones that can tunnel `https://` pages
|
|
622
|
+
|
|
623
|
+
```python
|
|
624
|
+
import itertools
|
|
625
|
+
|
|
626
|
+
import scrapy
|
|
627
|
+
from scrapy.crawler import CrawlerProcess
|
|
628
|
+
from proxyscraper import live_proxies
|
|
629
|
+
|
|
630
|
+
PROXIES = [p.url for p in live_proxies(types="http", https=True, min_uptime=50)]
|
|
631
|
+
if not PROXIES:
|
|
632
|
+
raise SystemExit("No proxy matches right now – loosen the filters (e.g. min_uptime)")
|
|
633
|
+
POOL = itertools.cycle(PROXIES)
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
class RotatingProxy:
|
|
637
|
+
def process_request(self, request, spider=None): # newer Scrapy leaves out spider
|
|
638
|
+
request.meta["proxy"] = next(POOL)
|
|
639
|
+
|
|
640
|
+
|
|
641
|
+
class IpSpider(scrapy.Spider):
|
|
642
|
+
name = "ip"
|
|
643
|
+
start_urls = [f"https://api.ipify.org/?n={i}" for i in range(3)]
|
|
644
|
+
custom_settings = {
|
|
645
|
+
"DOWNLOADER_MIDDLEWARES": {f"{__name__}.RotatingProxy": 350},
|
|
646
|
+
"RETRY_TIMES": 5, "DOWNLOAD_TIMEOUT": 15,
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
def parse(self, response):
|
|
650
|
+
print(response.meta["proxy"], "→", response.text)
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
if __name__ == "__main__":
|
|
654
|
+
process = CrawlerProcess()
|
|
655
|
+
process.crawl(IpSpider)
|
|
656
|
+
process.start()
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
In a Scrapy project, put `RotatingProxy` in `middlewares.py` and add it to `DOWNLOADER_MIDDLEWARES` in `settings.py`. For long crawls, reload the pool now and then – the list changes every hour.
|
|
660
|
+
|
|
661
|
+
**proxychains, Clash / Mihomo, sing-box** – ready-made configs with `--export`
|
|
582
662
|
|
|
583
663
|
```bash
|
|
584
|
-
proxy-scraper --want 30 -y --export proxychains,clash
|
|
664
|
+
proxy-scraper --want 30 -y --export proxychains,clash,singbox
|
|
585
665
|
proxychains4 -f results/latest/proxychains.conf curl https://api.ipify.org
|
|
586
666
|
```
|
|
587
667
|
|
|
588
|
-
`clash.yaml` has all HTTP and SOCKS5 proxies plus a `url-test` group that always picks the fastest.
|
|
668
|
+
`clash.yaml` has all HTTP and SOCKS5 proxies plus a `url-test` group that always picks the fastest. `singbox.json` does the same for sing-box, SOCKS4 included, and opens a local proxy: `sing-box run -c results/latest/singbox.json`, then use `127.0.0.1:2080` as HTTP or SOCKS5 proxy. All three leave out HTTP proxies that can't tunnel (`CONNECT`), because these tools tunnel everything.
|
|
589
669
|
|
|
590
670
|
**In a pipe** – `-o -` prints the hits to stdout, the interface moves to stderr
|
|
591
671
|
|
|
@@ -601,6 +681,22 @@ export HTTPS_PROXY=http://127.0.0.1:8899 HTTP_PROXY=http://127.0.0.1:8899
|
|
|
601
681
|
pip download requests # git, pip, npm & co. now go through the pool
|
|
602
682
|
```
|
|
603
683
|
|
|
684
|
+
**In a GitHub workflow** – the action picks working proxies for the next steps
|
|
685
|
+
|
|
686
|
+
```yaml
|
|
687
|
+
- id: proxies
|
|
688
|
+
uses: maximilianfeix/proxy-scraper@v1
|
|
689
|
+
with:
|
|
690
|
+
types: socks5
|
|
691
|
+
https: true
|
|
692
|
+
min-uptime: 90 # on the list for 90 %+ of the week
|
|
693
|
+
works-on: google # optional: google, reddit, amazon
|
|
694
|
+
recheck: true # optional: check them again from the runner
|
|
695
|
+
- run: curl -x "${{ steps.proxies.outputs.proxy }}" https://api.ipify.org
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
`proxy` is the fastest one, `file` a text file with all of them (up to `limit`, default 20), `count` how many. Without a match the step fails, unless `fail-if-empty: false`.
|
|
699
|
+
|
|
604
700
|
**Without installing anything** – straight from the live list
|
|
605
701
|
|
|
606
702
|
```bash
|
|
@@ -644,16 +740,16 @@ curl.exe -x (Get-Content "$run\all.txt" -TotalCount 1) http://api.ipify.org
|
|
|
644
740
|
| `-t`, `--timeout S` | timeout per proxy (default: 8 s) |
|
|
645
741
|
| `--discover` | search GitHub for new sources right now |
|
|
646
742
|
| `--no-cache` | download every list again (unchanged ones are normally skipped via ETag) |
|
|
647
|
-
| `--list-sources [N]` | show the source ranking |
|
|
743
|
+
| `--list-sources [N]` | show the source ranking (add `--json` for scripts: url, status, hit rate, checks, last change) |
|
|
648
744
|
| `--serve-host ADDR` | where the proxy server listens (default `127.0.0.1`; `0.0.0.0` for Docker, with a warning) |
|
|
649
745
|
| `--serve-password SECRET` | clients must send this password in the proxy login; better set `PROXY_SCRAPER_SERVE_PASSWORD` |
|
|
650
746
|
| `--rotate STRATEGY` · `--sticky SEC` | how the proxy server picks proxies, see [above](#proxy-server) |
|
|
651
747
|
| `--serve-refill HOURS` | while serving, check fresh proxies every HOURS and add the hits to the pool |
|
|
652
748
|
| `--serve [PORT]` | afterwards serve as a rotating proxy on `127.0.0.1:PORT` (default: 8899) |
|
|
653
749
|
| `-o FILE` | also write all hits to this file; `-o -` prints them to stdout |
|
|
654
|
-
| `--export FORMATS` | extra files for other tools: `proxychains`, `clash`, `curl` or `all` |
|
|
750
|
+
| `--export FORMATS` | extra files for other tools: `proxychains`, `clash`, `singbox`, `curl` or `all` |
|
|
655
751
|
| `-V`, `--version` | print the version |
|
|
656
|
-
| `--completion SHELL` | print the tab completion script for bash, zsh or
|
|
752
|
+
| `--completion SHELL` | print the tab completion script for bash, zsh, fish or PowerShell |
|
|
657
753
|
|
|
658
754
|
Everything else: `proxy-scraper --help`
|
|
659
755
|
|
|
@@ -735,10 +831,12 @@ Only for things that don't matter. Public proxies are run by strangers who can r
|
|
|
735
831
|
|
|
736
832
|
## Roadmap
|
|
737
833
|
|
|
738
|
-
What's next is
|
|
834
|
+
What's next is in the [open issues](../../issues) – ideas and wishes are welcome as an [issue](../../issues/new/choose). During Hacktoberfest there are [beginner-friendly issues](../../issues?q=is%3Aopen+label%3Ahacktoberfest) with pointers on where to start.
|
|
835
|
+
|
|
836
|
+
- [ ] [Measure throughput, not just latency](../../issues/140)
|
|
837
|
+
- [ ] [Daily snapshots as a dataset](../../issues/143)
|
|
739
838
|
|
|
740
|
-
|
|
741
|
-
- [ ] [sing-box export](../../issues/113), [PowerShell completion](../../issues/114), [shareable filters on the website](../../issues/116)
|
|
839
|
+
Shipped in v1.8 and v1.9: uptime per proxy and `stable.txt`, which proxies get through to Google, Reddit and Amazon, `live_proxies()` in Python, a page per proxy with its week of checks, a weekly report, live charts in this README, shareable filters on the website, sources mined from other scrapers' lists, untyped lists tried as HTTP and SOCKS5, `--export singbox`, PowerShell completion and recipes for httpx, aiohttp and Scrapy.
|
|
742
840
|
|
|
743
841
|
Shipped in [v1.7](../../milestone/7): an MCP server so AI agents get working proxies and can load pages through them, 28 new sources and a GitHub search that runs daily and keeps what it found, and a cleaner website.
|
|
744
842
|
|
|
@@ -783,7 +881,7 @@ proxyscraper/
|
|
|
783
881
|
├── geodb.py DB-IP country database (monthly, binary search)
|
|
784
882
|
├── targets.py target sites for --target
|
|
785
883
|
├── output.py result files
|
|
786
|
-
├── exporters.py proxychains, Clash and curl formats (--export)
|
|
884
|
+
├── exporters.py proxychains, Clash, sing-box and curl formats (--export)
|
|
787
885
|
├── server/ rotating proxy server (--serve): pool · http · upstream · socks · status · core
|
|
788
886
|
├── api.py find_proxies() / check_proxies() for Python
|
|
789
887
|
├── agent.py MCP tools without the SDK: live list, filters, fetch through proxies
|
|
@@ -9,6 +9,7 @@ proxy_scraper_cli.egg-info/requires.txt
|
|
|
9
9
|
proxy_scraper_cli.egg-info/top_level.txt
|
|
10
10
|
proxyscraper/__init__.py
|
|
11
11
|
proxyscraper/__main__.py
|
|
12
|
+
proxyscraper/action.py
|
|
12
13
|
proxyscraper/agent.py
|
|
13
14
|
proxyscraper/api.py
|
|
14
15
|
proxyscraper/app.py
|
|
@@ -36,7 +37,9 @@ proxyscraper/parsing.py
|
|
|
36
37
|
proxyscraper/paths.py
|
|
37
38
|
proxyscraper/pipeline.py
|
|
38
39
|
proxyscraper/preferences.py
|
|
40
|
+
proxyscraper/proxypages.py
|
|
39
41
|
proxyscraper/publish.py
|
|
42
|
+
proxyscraper/report.py
|
|
40
43
|
proxyscraper/sites.py
|
|
41
44
|
proxyscraper/sources.json
|
|
42
45
|
proxyscraper/sources.py
|
|
@@ -60,6 +63,7 @@ proxyscraper/ui/report.py
|
|
|
60
63
|
proxyscraper/ui/serve.py
|
|
61
64
|
proxyscraper/ui/widgets.py
|
|
62
65
|
proxyscraper/ui/wizard.py
|
|
66
|
+
tests/test_action.py
|
|
63
67
|
tests/test_agent.py
|
|
64
68
|
tests/test_api.py
|
|
65
69
|
tests/test_app.py
|
|
@@ -84,17 +88,22 @@ tests/test_output_stdout.py
|
|
|
84
88
|
tests/test_packaging.py
|
|
85
89
|
tests/test_pages.py
|
|
86
90
|
tests/test_parsing.py
|
|
91
|
+
tests/test_parsing_fuzz.py
|
|
87
92
|
tests/test_paths.py
|
|
88
93
|
tests/test_pipeline.py
|
|
94
|
+
tests/test_proxy_pages.py
|
|
89
95
|
tests/test_proxy_sources.py
|
|
90
96
|
tests/test_publish.py
|
|
97
|
+
tests/test_report.py
|
|
91
98
|
tests/test_robustness.py
|
|
92
99
|
tests/test_serve_password.py
|
|
93
100
|
tests/test_serve_refill.py
|
|
94
101
|
tests/test_serve_v2.py
|
|
95
102
|
tests/test_server.py
|
|
103
|
+
tests/test_server_closed_writer.py
|
|
96
104
|
tests/test_server_fixes.py
|
|
97
105
|
tests/test_sites.py
|
|
106
|
+
tests/test_sources_json.py
|
|
98
107
|
tests/test_tamper.py
|
|
99
108
|
tests/test_targets.py
|
|
100
109
|
tests/test_ui.py
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""proxy-scraper: collects public HTTP/SOCKS4/SOCKS5 proxies from hundreds of sources, checks them
|
|
2
2
|
in parallel with its own protocol handshakes and learns which sources deliver good proxies."""
|
|
3
3
|
|
|
4
|
-
__version__ = "1.
|
|
4
|
+
__version__ = "1.10.0"
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
def __getattr__(name):
|