Ang Scrapy pa rin ang workhorse para sa mga production crawl sa 2026 — at ang framework pa rin kung saan pinakanalilito ang mga tao sa proxy setup, dahil may apat na magkakaibang lugar kung saan maipapasok ang proxy at tatlo sa mga ito ay mali para sa karamihan ng proyekto. Ibinibigay sa iyo ng gabay na ito ang tama: isang maliit na custom middleware na may per-request routing, sticky sessions, ban detection, at matinong retry behavior.
Kung nasa simpleng requests/httpx/aiohttp ka naman, tingnan ang How to Rotate Proxies in Python. Ang artikulong ito ay Scrapy-specific.
Para sa rotating residential gateway, ang minimum viable setup ay isang linya kada request — walang middleware na kailangan:
def start_requests(self):
for url in self.urls:
yield scrapy.Request(
url,
meta={"proxy": "http://USERNAME:[email protected]:913"},
)
Binabasa ng built-in na HttpProxyMiddleware ng Scrapy ang request.meta["proxy"] at hina-handle ang authentication mula sa URL. Iro-rotate ng gateway ang exit IP para sa iyo. Kung iyon lang ang kailangan mo, huminto rito. Ang natitira sa gabay na ito ay para kapag kailangan mo ng kontrol: sticky sessions, country routing, ban-aware rotation, at concurrency tuning.
Ilagay ito sa middlewares.py. Nag-aassign ito ng sticky sessions kada domain, nag-ro-rotate kapag may ban, at tina-tag ang bawat request para ma-debug mo kung aling session ang kumuha ng ano:
import random
import string
GATEWAY = "us.jibaoproxy.com:913"
USERNAME = "USERNAME" # move to settings.py / env in real projects
PASSWORD = "PASSWORD"
def _new_session(n=8):
return "".join(random.choices(string.ascii_lowercase + string.digits, k=n))
class JibaoProxyMiddleware:
"""Sticky session per domain; rotate session on ban."""
def __init__(self):
self.sessions = {} # domain -> session id
def _proxy_url(self, session_id):
user = f"{USERNAME}-session-{session_id}"
return f"http://{user}:{PASSWORD}@{GATEWAY}"
def process_request(self, request, spider):
domain = request.url.split("/")[2]
session = self.sessions.setdefault(domain, _new_session())
request.meta["proxy"] = self._proxy_url(session)
request.meta["proxy_session"] = session
def rotate(self, domain):
"""Call when a session is burned."""
self.sessions[domain] = _new_session()
At isang kasamang downloader middleware na nakakatukoy ng mga ban at nag-re-retry sa sariwang session:
from scrapy.downloadermiddlewares.retry import RetryMiddleware
from scrapy.utils.response import response_status_message
BAN_CODES = {403, 429}
BAN_MARKERS = (b"captcha", b"access denied", b"unusual traffic")
class BanAwareRetryMiddleware(RetryMiddleware):
def process_response(self, request, response, spider):
banned = (
response.status in BAN_CODES
or any(m in response.body[:2048].lower() for m in BAN_MARKERS)
)
if banned:
domain = request.url.split("/")[2]
proxy_mw = spider.crawler.engine.downloader.middleware.middlewares
for mw in proxy_mw:
if hasattr(mw, "rotate"):
mw.rotate(domain) # burn the session
reason = response_status_message(response.status)
return self._retry(request, reason, spider) or response
return super().process_response(request, response, spider)
I-wire ang dalawa sa settings.py:
DOWNLOADER_MIDDLEWARES = {
"myproject.middlewares.JibaoProxyMiddleware": 350,
"scrapy.downloadermiddlewares.retry.RetryMiddleware": None, # replace stock retry
"myproject.middlewares.BanAwareRetryMiddleware": 550,
}
RETRY_TIMES = 2
Mahalaga ang priority: dapat tumakbo ang proxy middleware bago ang HttpProxyMiddleware (750) ng Scrapy, kaya gumagana ang anumang nasa ilalim ng 750; pinapanatili ng 350 itong maaga at predictable.
| Uri ng crawl | Mode | Implementasyon |
|---|---|---|
| Stateless page harvesting | Rotating | Tahasang username, nag-ro-rotate ang gateway kada request |
| Login + crawl sa likod ng auth | Sticky kada account | -session-{account_id}, huwag kailanman i-rotate sa kalagitnaan ng login |
| Pagination-heavy na listings | Sticky kada domain, mag-rotate kapag may ban | Ang middleware sa itaas |
| Geo-specific na pricing | Rotating + country pin | USERNAME-country-de style na mga parameter |
Mas malalim na pagtalakay sa trade-off na ito: Sticky vs Rotating Proxy Sessions.
Ang mga default ng Scrapy ay nakatutok para sa magalang na single-IP crawling. Sa likod ng rotating pool maaari kang magtulak nang mas malakas — pero mahalaga pa rin ang per-domain limits dahil nakikita ng target ang aggregate behavior:
# settings.py - sane starting point behind a residential pool
CONCURRENT_REQUESTS = 64
CONCURRENT_REQUESTS_PER_DOMAIN = 8 # what the target experiences
DOWNLOAD_DELAY = 0.25 # jitter applied per slot
RANDOMIZE_DOWNLOAD_DELAY = True # 0.5x-1.5x the delay
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_TARGET_CONCURRENCY = 6.0
DOWNLOAD_TIMEOUT = 30
ROBOTSTXT_OBEY = True
Itaas ang CONCURRENT_REQUESTS_PER_DOMAIN matapos lang mong bantayan ang iyong 403 rate sa kasalukuyang antas para sa ilang libong request. Ang pag-akyat ng 8 → 32 dahil "nag-ro-rotate naman ang mga proxy" ay kung paano nauubos ng mga tao ang GB sa mga retry.
IMAGES_STORE pipelines para kumuha sa pamamagitan ng datacenter proxy o direktang koneksyon kung walang pakialam ang CDN — ang media ang karamihan ng iyong GB at bihirang protektado.HTTPCACHE_ENABLED = True habang nag-i-iterate ka sa mga parser ay nire-replay ang mga response mula sa disk imbes na muling kumuha sa pamamagitan ng pool. Ang isang setting na ito ay karaniwang humahati sa bandwidth bill ng proyekto.COMPRESSION_ENABLED = True (default) — ang gzip'd na HTML ay 5–10x mas maliit sa wire.407 Proxy Authentication RequiredHindi nakarating ang credentials sa proxy. Ilagay ang mga ito sa URL (http://user:pass@host:port) sa meta["proxy"] — pina-parse at itinatakda ng Scrapy ang Proxy-Authorization para sa iyo. Ang pagtatakda ng header nang manwal at paggamit ng URL credentials ay nagdudulot ng double-auth na kakaibang asal; pumili ng isa.
TunnelError: Could not open CONNECT tunnelHalos palaging maling na-type na host/port, o HTTPS target sa pamamagitan ng endpoint na hindi nagpapahintulot ng CONNECT sa port na iyon. I-verify gamit ang curl -x sa labas ng Scrapy muna.
Nabuhay ang iyong sticky session nang lampas sa pagtanggap dito, o sobrang init ng iyong per-domain rate. Hina-handle ng ban-aware middleware sa itaas ang unang kaso; ibaba ang CONCURRENT_REQUESTS_PER_DOMAIN para sa pangalawa. Kung ito ay JA4-checking na target, maaaring ang TLS stack mismo ng Scrapy ang tell — tingnan ang JA3/JA4 explained kung bakit walang proxy ang nag-aayos niyan.
meta["proxy"] na may gateway URL ang buong setup.Rotating at sticky residential sessions sa isang gateway. 500MB free traffic para mag-crawl.
Start Free TrialAng mga bagong user ay makakatanggap ng 500MB sa pagrehistro, kasama ang bonus sa unang recharge. Limitadong oras lang ang alok.