Trả lời nhanh
Làm sao để dùng proxy dân cư xoay vòng trong Python?
Truyền http://USERNAME:[email protected]:7777 làm proxy cho cả http và https trong requests, làm proxy= trong httpx 0.26+, hoặc proxy= cho mỗi request trong aiohttp. CrawlRelay proxy dân cư xoay vòng trên mỗi kết nối mới và giữ sticky với -session-<id> trong username. Giá là 1,50 US$ cho 1 GB và 0,50 US$/GB từ 50 GB. Thanh toán bằng crypto, không cần KYC.
Cài đặt Python xem qua
| requests | proxies={"http": url, "https": url}; retry qua urllib3 Retry |
|---|---|
| httpx | httpx.Client(proxy=url); tham số proxies= cũ đã bị loại bỏ trong httpx 0.28 |
| aiohttp | session.get(url, proxy="http://USER:PASS@host:port"), thông tin xác thực trong URL proxy |
| SOCKS5 | pip install "requests[socks]" hoặc httpx[socks], rồi socks5h:// trên cổng 7778 |
| IP mới mỗi yêu cầu | Tắt keep-alive: Connection: close, max_keepalive_connections=0 hoặc force_close=True |
| Cùng IP cho một flow | -session-<id>-ttl-<minutes> trong username, tối đa 30 phút |
| Scheme URL proxy | Luôn dùng http:// cho cổng HTTP, ngay cả với trang web HTTPS |
Làm sao để dùng proxy với requests cùng retry tôn trọng Retry-After?
Gắn một HTTPAdapter với urllib3 Retry trên một Session. Nó retry lỗi kết nối và các trạng thái bạn liệt kê, đợi theo hàm mũ, và tuân thủ header Retry-After mà site gửi cùng 429 và 503. Đặt trust_env = False để biến HTTPS_PROXY thừa không ghi đè proxy của bạn.
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)Làm sao để tạo URL proxy an toàn nhắm mục tiêu?
Tạo username trong một hàm và kiểm tra. Lỗi gõ mã quốc gia hoặc ký tự không mã hóa trong mật khẩu dẫn tới lỗi 407 trông như lỗi xác thực. Trợ giúp dưới đây giữ đúng thứ tự tài liệu (USERNAME-country-{cc}-state-{state}-city-{city}-zip-{zip}-asn-{asn}-session-{id}-ttl-{minutes}), từ chối key lạ và mã hóa URL cả hai thông tin xác thực.
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"))Làm sao để có IP mới mỗi request với httpx?
Tắt keep-alive. httpx mặc định gom nhóm kết nối, và kết nối tái sử dụng giữ IP thoát cũ. Với max_keepalive_connections=0, mỗi request mở kết nối mới tới gateway và thường thoát ra IP dân cư khác. num_bytes_downloaded trả byte nhận được trên đường truyền, gần giống với cách tính cước traffic.
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")Làm sao để crawl đồng thời với asyncio mà không tấn công cùng một site?
Giới hạn concurrency theo host, không chỉ tổng thể. Giới hạn tổng 50 cho phép 50 request cùng một site nếu danh sách URL sắp theo domain. Semaphore theo hostname giữ mỗi site ở mức lịch sự trong khi toàn bộ crawl vẫn nhanh. Bắt đầu 2 đến 4 mỗi host và xem hướng dẫn concurrency trước khi tăng.
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/"]))Làm sao để dùng proxy với aiohttp?
Truyền gateway làm proxy= trên mỗi request, với thông tin xác thực trong URL proxy. Cách này hoạt động với mọi bản aiohttp 3.x mà không cảnh báo; BasicAuth và tham số proxy_auth= đã deprecated từ aiohttp 3.14 và sẽ bị bỏ ở 4.0. Một TCPConnector(force_close=True) đóng mọi kết nối sau phản hồi, mỗi request thường có IP mới. Nếu không, aiohttp tái sử dụng kết nối và bạn giữ cùng IP một thời gian.
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())Làm sao giữ một IP cho flow nhiều bước?
Tạo một session ID cho mỗi flow rồi đặt trong username với TTL dài hơn flow. Keep-alive tốt ở đây: bạn muốn cùng IP thoát. Nếu thiết bị dân cư sau session offline, IP có thể đổi trước TTL hết, nên làm flow có thể khởi động lại từ checkpoint cuối.
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")Một trình scraper Python dùng bao nhiêu traffic mỗi trang?
Đo trên 100 trang thật trước khi mua dung lượng. Ghi lại num_bytes_downloaded trong httpx, hoặc độ dài body nén trong middleware bạn tự làm, rồi nhân với số trang. Yêu cầu HTML thường tốn vài chục KB mỗi trang; hướng dẫn băng thông cho số liệu và chi phí cho 1.000 trang với giá CrawlRelay.
Ba thói quen giảm traffic mà không thay kết quả:
- Gửi
Accept-Encoding: gzip, br(httpx và requests mặc định gửi gzip) để trang nén khi truyền. - Lấy endpoint JSON mà trang tải khi site cho phép hoặc có tài liệu, thay vì HTML đầy đủ.
- Bỏ qua trang không đổi với
If-None-MatchhoặcIf-Modified-Since: một304 Not Modifiedchỉ tốn vài trăm byte.
Python và proxy dân cư: các câu hỏi
requests, httpx hay aiohttp: tôi nên dùng cái nào để thu thập dữ liệu?
Dùng requests cho các script đơn giản và crawl nhỏ. Dùng httpx khi bạn muốn cùng một API cho code đồng bộ và bất đồng bộ, và hỗ trợ HTTP/2 qua httpx[http2]. Dùng aiohttp cho độ đồng thời rất cao trong asyncio thuần túy. Với crawl có lập lịch, loại trùng và pipeline, dùng Scrapy thay vì tự viết các phần đó.
Tại sao tôi lại nhận lỗi SSL: WRONG_VERSION_NUMBER khi dùng proxy trong Python?
Có thể bạn đã viết https:// trước địa chỉ proxy. Cổng 7777 của gateway dùng HTTP thuần và mở tunnel CONNECT cho các site HTTPS, nên URL proxy phải bắt đầu bằng http:// trong cả khóa http và https. Xem trang lỗi.
Làm sao để dùng proxy SOCKS5 trong Python?
Cài thêm gói (pip install "requests[socks]" hoặc pip install "httpx[socks]"), rồi dùng socks5h://USERNAME:[email protected]:7778. h gửi hostname đến proxy, DNS phân giải ở cửa ra nên bạn sẽ nhận được kết quả vùng miền giống như người dùng địa phương.
Tại sao proxy di động 4G quay vòng của tôi trả lại IP trùng lặp?
Client của bạn đã tái sử dụng kết nối giữ sống, trong khi quay vòng xảy ra trên mỗi kết nối mới. Gửi Connection: close trong requests, đặt max_keepalive_connections=0 trong httpx hoặc dùng force_close=True trong aiohttp. Cũng kiểm tra xem username có phần session- không, phần này cố định một IP.
Làm thế nào để thiết lập timeout cho các yêu cầu qua proxy?
Thiết lập rõ ràng vì requests không có timeout mặc định. Timeout kết nối khoảng 10 giây và timeout đọc 30 giây phù hợp cho trang HTML; các exit di động và mục tiêu chậm cần từ 45 đến 60 giây. Thử lại 1 lần khi timeout trên kết nối mới thay vì chờ lâu hơn. Xem cách timeout đọc.
Tôi có thể dùng các proxy này trong Jupyter hoặc với pandas không?
Có thể. Bất cứ thứ gì dùng requests hoặc httpx bên dưới đều dùng được proxy dân cư. Với pandas.read_html hoặc read_csv trên URL, tải nội dung bằng requests qua proxy trước, rồi truyền text hoặc bytes sang pandas.
Chạy scraper Python của bạn qua IP dân cư
1,50 US$ cho 1 GB, 0,50 US$/GB từ 50 GB.