cloud-proxy-hub
Multi-provider proxy pool with geo and performance validation. Wraps Proxy-Seller (datacenter + residential), pingnetwork.io (residential) and SmartProxy (residential) behind a single class:
from cloud_proxy_hub import ProxyHub, ProxyHubConfig
config = ProxyHubConfig(
# provider credentials — or leave unset and export the same-named
# env vars (PROXY_API_KEY, SMARTPROXY_LOGIN, SMARTPROXY_PASS, ...)
proxy_api_key="...",
proxy_seller_res_login="...",
proxy_seller_res_pass="...",
proxy_pingnetwork_res_login="...",
proxy_pingnetwork_res_pass="...",
smartproxy_login="...",
smartproxy_pass="...",
# extra static datacenter proxies per ISO-3166 alpha-2 country code
# (used to be hardcoded in the library — now it's yours to supply)
additional_datacenter_proxies={
"ZA": ["http://user:pass@host:port", ...],
"BR": ["http://user:pass@host:port", ...],
},
# which providers are active, and in what order (default shown here —
# SmartProxy is OFF by default; add it back with any key/priority to
# re-enable, e.g. provider_priority={"Proxy-Seller": 1, "pingnetwork": 2, "SmartProxy": 3}).
# Drop "pingnetwork" if you don't want the pingnetwork.io fallback.
# Providers are tried in order, the first one that returns proxies wins,
# and SmartProxy is always tried last whatever number you give it.
provider_priority={"Proxy-Seller": 1, "pingnetwork": 2},
# smartproxy_retries / smartproxy_backoff_factor / smartproxy_timeout
# also exist (defaults 5 / 1.5 / 10) — omitted here since SmartProxy is
# off by default above; only relevant once you add "SmartProxy" back to
# provider_priority.
)
proxy_hub = ProxyHub(validate_proxies=True, config=config)
proxy = proxy_hub.provide_valid_proxies(
proxy_type="residential",
country_code="DE",
neighbor_geo_enable=False,
reverse_proxy=is_last_attempt, # try pingnetwork.io first on the last retry
)
Everything you need to tune lives on ProxyHubConfig — construct it once,
pass it to ProxyHub, and call provide_valid_proxies(). No need to reach
into cloud_proxy_hub.providers / cloud_proxy_hub.geo /
cloud_proxy_hub.performance unless you're extending the library itself.
Why a config object
The original script read paths and provider credentials from an internal
src.settings module, and had a dict of extra datacenter proxies (with real
login/password pairs) hardcoded in the class body. Both made the code
impossible to hand to anyone outside that one codebase, and unsafe to publish
anywhere public. ProxyHubConfig replaces both: every credential is either
passed explicitly or read from an environment variable of the same name, and
additional_datacenter_proxies is supplied by the caller instead of baked
into the source.
Install
pip install cloud-proxy-hub
Published on public PyPI. No credentials are embedded anywhere in the
source — every secret is supplied by the consumer via ProxyHubConfig or
environment variables, as shown above.
Publishing a new version
python -m pip install --upgrade build twine
python -m build # produces dist/*.whl and dist/*.tar.gz
python -m twine upload dist/*
Requires a PyPI account with 2FA enabled and an API token (__token__ as
username, the token as password).
What changed in 0.2.1
A geo-service that failed fast no longer rejects a working proxy. The
parallel geo-service race used asyncio.wait(..., return_when=FIRST_COMPLETED),
which returns on the first task to finish regardless of its answer — so one
service erroring instantly (a rate-limit, a 403, a missing field in the
response) cancelled the other checks and the proxy was sent to the slower
fallback checks or dropped. Both races — the geo services and the two fallback
checks — now wait for the first task that actually returns True
(geo._first_true), and cancel the rest only once the verdict is known.
The geo-service phase also gets an overall cap,
GEO_SERVICES_OVERALL_TIMEOUT = 3.0 seconds, applied as
min(per_service_timeout, GEO_SERVICES_OVERALL_TIMEOUT). A proxy nobody can
confirm now holds the batch for ~3s instead of up to per_service_timeout
(8s), which matters because geo_filter_proxies waits for every proxy in the
batch before returning.
What changed in 0.2.0
pingnetwork.io is a real provider now. Up to 0.1.1 it was generated from
inside ProxySeller.generate_resident_proxy_by_proxy_seller: its proxies were
appended to the proxy-seller list and one of the two was picked with the 90/10
proxy_seller_weight / pingnetwork_weight split. That also meant dropping
"Proxy-Seller" from provider_priority silently disabled pingnetwork.io,
and a failure reading proxy-seller's geo_proxy.json took pingnetwork down
with it — the two shared one try/except.
It is now a PingNetwork class dispatched by ProxyHub like any other
provider:
- providers are tried in order and the first one that returns proxies wins — the weighted split is gone;
- default order is
Proxy-Seller→pingnetwork, so proxy-seller.com serves traffic and pingnetwork.io is the fallback; provide_valid_proxies(..., reverse_proxy=True)flips the first two: pingnetwork.io first, proxy-seller.com as the fallback;SmartProxyis always tried last, whatever priority number it is given;provider_priority={"pingnetwork": 1}finally works on its own, with no proxy-seller.com account involved.
ProxySeller.generate_resident_proxy_by_proxy_seller returns proxy-seller
proxies only; PingNetwork.generate_resident_proxy_by_pingnetwork is its
pingnetwork counterpart. Both default to 10 proxies per call
(proxy_count=10) when called directly — ProxyHub passes its own
proxy_count (default 20) instead.
Also in 0.2.0: three more geo-check services (country.is, geojs.io,
ip.sb) replace reallyfreegeoip in geo.get_geo_services().
Migrating from the old updated_proxy_hub.py
from src.settings import settings→ build aProxyHubConfig(...)once (from your own private settings) and pass it toProxyHub(config=...).- The hardcoded
ADDITIONAL_DATACENTER_PROXIESdict → pass it asProxyHubConfig(additional_datacenter_proxies={...}). - The hardcoded
proxy_prioritymodule dict (which providers run, and in what order) →ProxyHubConfig(provider_priority={...}). Default is{"Proxy-Seller": 1, "pingnetwork": 2}— SmartProxy is off by default (still fully implemented in the library, just excluded from the default dict); add an"SmartProxy": <n>key to turn it back on, or drop"pingnetwork"to disable that too. Same membership check for all three — drop any key to disable that provider at startup instead of commenting it out in library source. - The hardcoded 90/10 provider split → gone as of 0.2.0, see
"What changed in 0.2.0" below.
proxy_seller_weight/pingnetwork_weightstill exist onProxyHubConfigso old call sites keep working, but nothing reads them any more. - SmartProxy's hardcoded
retries=5, backoff_factor=1.5, timeout=10→smartproxy_retries/smartproxy_backoff_factor/smartproxy_timeoutonProxyHubConfig(same defaults). ProxyHub(validate_proxies=...)andprovide_valid_proxies(...)keep their original signature and behavior.
Release files for cloud-proxy-hub 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cloud_proxy_hub-0.2.1.tar.gz | 18.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cloud_proxy_hub-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 40.9 kB
Release files / cloud_proxy_hub-0.2.1.tar.gz
| Download URL | cloud_proxy_hub-0.2.1.tar.gz |
|---|---|
| Size | 18.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
35257d4d416321eaff5687ee0e7e09ef0eb4bbf3ca5aed4cd912833a38b60caf
|
|
BLAKE2b-256 checksum How to use checksums |
f101b30aaaa1ef6720c3e0bf4a8c10a117172c3bf7635e8b3e1748814c1f95a1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.7
|
Release files / cloud_proxy_hub-0.2.1-py3-none-any.whl
| Download URL | cloud_proxy_hub-0.2.1-py3-none-any.whl |
|---|---|
| Size | 22.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ad4677f53c827d5fb2cba44e733c0b2c2379c7c93f8371db8e8712fc81f2f560
|
|
BLAKE2b-256 checksum How to use checksums |
1af5d876109120556ee47ca11c666cb2d1456d70d176a043bf3f93ce380fa04f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.7
|