Kort antwoord
Hoe gebruik ik rotating residentiële proxy's in Python?
Geef http://USERNAME:[email protected]:7777 door als proxy voor zowel http als https in requests, als proxy= in httpx 0.26+, of als proxy= per verzoek in aiohttp. CrawlRelay residentiële proxy's roteren bij elke nieuwe verbinding en blijven sticky met -session-<id> in de gebruikersnaam. Ze kosten US$ 1,50 voor 1 GB en US$ 0,50/GB vanaf 50 GB. Betaald in crypto, zonder KYC.
Python setup in één oogopslag
| requests | proxies={"http": url, "https": url}; retries via urllib3 Retry |
|---|---|
| httpx | httpx.Client(proxy=url); het oude proxies= argument is verwijderd in httpx 0.28 |
| aiohttp | session.get(url, proxy="http://USER:PASS@host:port"), inloggegevens in de proxy URL |
| SOCKS5 | pip install "requests[socks]" of httpx[socks], daarna socks5h:// op poort 7778 |
| Nieuw IP per verzoek | Schakel keep-alive uit: Connection: close, max_keepalive_connections=0 of force_close=True |
| Zelfde IP voor een flow | -session-<id>-ttl-<minutes> in de gebruikersnaam, tot 30 minuten |
| Proxy URL schema | Altijd http:// voor de HTTP-poort, ook voor HTTPS-websites |
Hoe gebruik ik een proxy met requests, met retries die Retry-After respecteren?
Monteer een HTTPAdapter met urllib3's Retry op een Session. Het herhaalt verbindingsfouten en de statussen die je lijst, wacht met exponentiële backoff, en respecteert de Retry-After-header die sites sturen bij 429 en 503. Stel trust_env = False in zodat een overgebleven HTTPS_PROXY variabele je proxy niet kan overschrijven.
import os
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
USER = os.environ.get("CRAWLRELAY_USER", "USERNAME-country-us")
PASSWORD = os.environ.get("CRAWLRELAY_PASSWORD", "PASSWORD")
PROXY = "http://%s:%[email protected]:7777" % (USER, PASSWORD)
retry = Retry(
total=4,
connect=2,
backoff_factor=1.0, # waits of 0 s, 2 s, 4 s, 8 s (Retry-After wins on 429/503)
status_forcelist=(429, 502, 503, 504),
allowed_methods=frozenset({"GET", "HEAD"}),
respect_retry_after_header=True,
)
session = requests.Session()
session.trust_env = False # ignore HTTP(S)_PROXY from the environment
session.mount("http://", HTTPAdapter(max_retries=retry))
session.mount("https://", HTTPAdapter(max_retries=retry))
session.proxies = {"http": PROXY, "https": PROXY}
session.headers["User-Agent"] = "ExampleCrawler/1.0 (+https://example.com/crawler-info)"
session.headers["Connection"] = "close" # new connection per request, so usually a new exit IP
r = session.get("https://api.ipify.org", timeout=(10, 30))
print(r.status_code, r.text)Hoe bouw ik veilige gerichte proxy-URL's?
Genereer de gebruikersnaam in één functie en valideer deze. Een typfout in een landcode of een niet-geëncodeerd teken in het wachtwoord veroorzaakt een 407 die eruitziet als een inlogprobleem. De helper hieronder houdt de gedocumenteerde volgorde aan (USERNAME-country-{cc}-state-{state}-city-{city}-zip-{zip}-asn-{asn}-session-{id}-ttl-{minutes}), weigert onbekende sleutels en URL-encodeert beide inloggegevens.
import re
from urllib.parse import quote
ORDER = ("country", "state", "city", "zip", "asn", "session", "ttl")
VALUE = re.compile(r"^[a-z0-9_]+$")
def build_username(base, **params):
"""build_username("USERNAME", country="us", city="new_york", session="job1", ttl=30)"""
parts = [base]
for key in ORDER:
value = params.pop(key, None)
if value is None:
continue
value = str(value).lower()
if not VALUE.match(value):
raise ValueError("bad value for %s: %r" % (key, value))
if key == "ttl" and not 1 <= int(value) <= 30:
raise ValueError("ttl must be 1 to 30 minutes")
parts.append("%s-%s" % (key, value))
if params:
raise ValueError("unknown parameters: %s" % ", ".join(sorted(params)))
return "-".join(parts)
def proxy_url(username, password, socks=False):
scheme, port = ("socks5h", 7778) if socks else ("http", 7777)
return "%s://%s:%[email protected]:%d" % (
scheme, quote(username, safe=""), quote(password, safe=""), port)
print(proxy_url(build_username("USERNAME", country="us", state="ny", city="new_york", session="job1", ttl=20), "p@ss:word"))Hoe krijg ik een nieuw IP bij elk verzoek met httpx?
Schakel keep-alive uit. httpx poolt standaard verbindingen, en een hergebruikte verbinding behoudt zijn exit IP. Met max_keepalive_connections=0 opent elk verzoek een nieuwe verbinding naar de gateway en verlaat die meestal via een andere residentiële IP. num_bytes_downloaded geeft de ontvangen bytes op de lijn, wat het dichtst bij de verkeersafrekening ligt.
import httpx
PROXY = "http://USERNAME-country-gb:[email protected]:7777"
# No keep-alive: every request opens a new connection, so it usually gets a new exit IP
with httpx.Client(
proxy=PROXY,
timeout=httpx.Timeout(30.0, connect=10.0),
limits=httpx.Limits(max_keepalive_connections=0),
follow_redirects=True,
) as client:
for _ in range(3):
r = client.get("https://api.ipify.org")
print(r.text, r.num_bytes_downloaded, "bytes on the wire")Hoe scrape ik gelijktijdig met asyncio zonder één site te overladen?
Beperk concurrency per host, niet alleen globaal. Een globale limiet van 50 laat alle 50 verzoeken dezelfde site raken als je URL-lijst op domein is gesorteerd. Een semaphore per hostname houdt elke site op een beleefd niveau terwijl de crawl als geheel snel blijft. Begin met 2 tot 4 per host en lees de concurrency gids voordat je verhoogt.
import asyncio
from collections import defaultdict
from urllib.parse import urlsplit
import httpx
PROXY = "http://USERNAME-country-us:[email protected]:7777"
PER_HOST = 4 # parallel requests per target host
host_slots = defaultdict(lambda: asyncio.Semaphore(PER_HOST))
async def fetch(client, url):
async with host_slots[urlsplit(url).hostname]:
try:
r = await client.get(url)
return url, r.status_code, r.num_bytes_downloaded
except httpx.HTTPError as exc:
return url, type(exc).__name__, 0
async def main(urls):
limits = httpx.Limits(max_connections=50, max_keepalive_connections=0)
timeout = httpx.Timeout(30.0, connect=10.0)
async with httpx.AsyncClient(proxy=PROXY, limits=limits, timeout=timeout) as client:
for result in await asyncio.gather(*(fetch(client, u) for u in urls)):
print(*result)
asyncio.run(main(["https://example.com/", "https://example.org/", "https://example.net/"]))Hoe gebruik ik een proxy met aiohttp?
Geef de gateway door als proxy= bij elk verzoek, met de inloggegevens in de proxy URL. Dat werkt zonder waarschuwingen bij elke aiohttp 3.x release; BasicAuth en de proxy_auth= parameter zijn verouderd sinds aiohttp 3.14 en worden verwijderd in 4.0. Een TCPConnector(force_close=True) sluit elke verbinding na de respons, zodat elk verzoek meestal een nieuwe exit krijgt. Zonder dit hergebruikt aiohttp verbindingen en behoud je tijdelijk hetzelfde IP.
import asyncio
import aiohttp
# Credentials go in the proxy URL; percent-encode a password that contains @ or :
PROXY = "http://USERNAME-country-fr:[email protected]:7777"
async def main():
# force_close=True: one connection per request, so each request usually gets a new exit IP
connector = aiohttp.TCPConnector(limit=20, force_close=True)
timeout = aiohttp.ClientTimeout(total=60, sock_connect=10)
async with aiohttp.ClientSession(connector=connector, timeout=timeout) as session:
for _ in range(3):
async with session.get("https://api.ipify.org", proxy=PROXY) as resp:
print(resp.status, await resp.text())
asyncio.run(main())Hoe houd ik één IP voor een multi-step flow?
Genereer één sessie-ID per flow en zet die in de gebruikersnaam met een TTL langer dan de flow. Keep-alive is hier prima: je wilt dezelfde exit. Als het residentiële apparaat achter de sessie offline gaat, kan het IP veranderen voordat de TTL afloopt, dus maak de flow herstartbaar vanaf het laatste checkpoint.
import uuid
import requests
session_id = uuid.uuid4().hex[:10] # one ID per flow, lowercase letters and digits
user = "USERNAME-country-us-state-ca-session-%s-ttl-20" % session_id
proxy = "http://%s:[email protected]:7777" % user
with requests.Session() as s:
s.proxies = {"http": proxy, "https": proxy}
first = s.get("https://api.ipify.org", timeout=(10, 30)).text
second = s.get("https://api.ipify.org", timeout=(10, 30)).text
print(first, second, "same exit" if first == second else "exit changed")Hoeveel verkeer gebruikt een Python scraper per pagina?
Meet het op 100 echte pagina's voordat je volume koopt. Log num_bytes_downloaded in httpx, of de lengte van de gecomprimeerde body in je eigen middleware, en vermenigvuldig met je pagina-aantal. Alleen HTML-verzoeken kosten meestal tientallen kilobytes per pagina; de bandbreedte gids geeft de cijfers en de kosten per 1.000 pagina's tegen CrawlRelay prijzen.
Drie gewoontes verminderen verkeer zonder je resultaten te veranderen:
- Verstuur
Accept-Encoding: gzip, br(httpx en requests versturen standaard gzip) zodat pagina's gecomprimeerd reizen. - Haal de JSON-endpoint op die een pagina laadt, wanneer de site dit documenteert of toestaat, in plaats van de volledige HTML.
- Sla ongewijzigde pagina's over met
If-None-MatchofIf-Modified-Since: een304 Not Modifiedkost enkele honderden bytes.
Python en proxy's: vragen
requests, httpx of aiohttp: welke moet ik gebruiken voor scraping?
Gebruik requests voor eenvoudige scripts en kleine crawls. Gebruik httpx als je dezelfde API wilt in synchrone en asynchrone code, en HTTP/2 via httpx[http2]. Gebruik aiohttp voor zeer hoge gelijktijdigheid in pure asyncio. Voor een crawl met planning, deduplicatie en pipelines gebruik je Scrapy in plaats van die onderdelen zelf te schrijven.
Waarom krijg ik SSL: WRONG_VERSION_NUMBER bij mijn proxy in Python?
Je hebt waarschijnlijk https:// voor het proxyadres gezet. De gatewaypoort 7777 spreekt gewoon HTTP en opent een CONNECT-tunnel voor HTTPS-sites, dus de proxy-URL moet in zowel de http als https sleutels met http:// beginnen. Zie de foutpagina.
Hoe gebruik ik SOCKS5 proxy's in Python?
Installeer de extra (pip install "requests[socks]" of pip install "httpx[socks]"), gebruik dan socks5h://USERNAME:[email protected]:7778. De h stuurt hostnamen naar de proxy, zodat DNS-resolutie bij de uitgang gebeurt en je dezelfde regionale antwoorden krijgt als lokale bezoekers.
Waarom geeft mijn roterende proxy twee keer hetzelfde IP terug?
Je client hergebruikte een keep-alive verbinding, terwijl rotatie per nieuwe verbinding gebeurt. Verstuur Connection: close in requests, stel max_keepalive_connections=0 in httpx in, of gebruik force_close=True in aiohttp. Controleer ook dat de gebruikersnaam geen session- onderdeel heeft, dat opzettelijk één IP behoudt.
Hoe stel ik time-outs in voor proxied requests?
Stel ze expliciet in: requests heeft standaard geen timeout. Een connect-timeout van ongeveer 10 seconden en een read-timeout van 30 seconden is geschikt voor HTML-pagina's; mobiele exits en trage doelen hebben 45 tot 60 seconden nodig. Probeer een timeout eenmaal opnieuw met een nieuwe verbinding in plaats van langer te wachten. Zie read timeouts.
Kan ik deze proxy's gebruiken in Jupyter of met pandas?
Ja. Alles wat requests of httpx gebruikt, neemt dezelfde proxy-instellingen over. Voor pandas.read_html of read_csv op een URL, download eerst de inhoud met een proxied requests-aanroep en geef dan de tekst of bytes aan pandas door.
Laat je Python scraper lopen via residentiële proxy's
US$ 1,50 voor 1 GB, US$ 0,50/GB vanaf 50 GB.