Trả lời nhanh
Làm sao để dùng proxy quay vòng với Scrapy?
Đặt request.meta["proxy"] thành http://USERNAME:[email protected]:7777 trong middleware downloader nhỏ chạy trước HttpProxyMiddleware của Scrapy; Scrapy sẽ gửi chứng chỉ dùm bạn. Với CrawlRelay proxy dân cư, quốc gia và session cố định được để trong username, nên một middleware xử lý được cả hai. Lưu lượng tiêu tốn 0,50 US$/GB từ 50 GB. Thanh toán bằng crypto, không cần KYC.
Thiết lập Scrapy nhìn tổng quan
| Nơi đặt proxy | request.meta["proxy"], do middleware bạn cài đặt |
|---|---|
| Thứ tự middleware | Middleware của bạn phải dưới 750, là độ ưu tiên của HttpProxyMiddleware tích hợp |
| Thông tin xác thực | Trong URL proxy; Scrapy chuyển thành header Proxy-Authorization |
| SOCKS5 | Không với handler HTTP/1.1 mặc định; Scrapy 2.17+ hỗ trợ SOCKS qua HttpxDownloadHandler tùy chọn. Cổng HTTP 7777 đơn giản nhất |
| Xoay vòng | Exit mới cho mỗi kết nối mới; session ID duy nhất mỗi yêu cầu thường cho IP khác nhau |
| Lịch sự | ROBOTSTXT_OBEY, CONCURRENT_REQUESTS_PER_DOMAIN, AUTOTHROTTLE_ENABLED |
| Retry | 429 và 5xx có trong RETRY_HTTP_CODES mặc định; Retry-After không được đọc mặc định |
Làm sao để viết proxy middleware?
Đặt class trong middlewares.py. Nó tạo username từ cài đặt và ba khóa meta tùy chọn: proxy_country, proxy_session và proxy_ttl. Yêu cầu không có proxy_session sẽ quay vòng; có proxy_session="new" sẽ có session mới, thường IP exit khác; có session ID cố định chia sẻ exit với các yêu cầu cùng luồng. Middleware tính lại proxy mỗi lần đi qua, kể cả retry, và không chạm proxy do code khác lập. Nếu thiếu CRAWLRELAY_USER, crawl dừng khi khởi chạy thay vì chạy từ IP của bạn.
import uuid
from urllib.parse import quote
class CrawlRelayProxyMiddleware:
"""Sets request.meta["proxy"]; Scrapy's HttpProxyMiddleware then sends the credentials."""
def __init__(self, user, password, country):
self.user, self.password, self.country = user, password, country
@classmethod
def from_crawler(cls, crawler):
s = crawler.settings
if not s.get("CRAWLRELAY_USER"):
# Fail loudly: NotConfigured would only disable the middleware and crawl from your own IP
raise ValueError("CRAWLRELAY_USER is not set: refusing to crawl without the proxy")
return cls(s.get("CRAWLRELAY_USER"), s.get("CRAWLRELAY_PASSWORD", ""), s.get("CRAWLRELAY_COUNTRY", "us"))
def process_request(self, request, spider=None):
if "proxy" in request.meta and not request.meta.get("_crawlrelay"):
return None # a proxy set by other code: leave it alone
parts = [self.user, "country", request.meta.get("proxy_country", self.country)]
session = request.meta.get("proxy_session")
if session == "new": # a fresh session for this request (and for each of its retries)
session = uuid.uuid4().hex[:12]
if session:
parts += ["session", session, "ttl", str(request.meta.get("proxy_ttl", 10))]
username = "-".join(parts)
request.meta["proxy"] = "http://%s:%[email protected]:7777" % (
quote(username, safe=""), quote(self.password, safe=""))
request.meta["_crawlrelay"] = True
return NoneCác cài đặt Scrapy nào giữ cho crawl qua proxy lịch sự và nhanh?
Proxy phân bố yêu cầu của bạn qua nhiều IP, nhưng mục tiêu vẫn tính tổng tần suất. Các cài đặt này giữ mỗi domain với tốc độ phù hợp và để AutoThrottle tự giảm tốc khi phản hồi chậm lại. Giữ ROBOTSTXT_OBEY = True, Scrapy mới đã có mặc định.
import os
BOT_NAME = "myproject"
ROBOTSTXT_OBEY = True
USER_AGENT = "ExampleCrawler/1.0 (+https://example.com/crawler-info)"
CRAWLRELAY_USER = os.environ.get("CRAWLRELAY_USER") # e.g. the username from your dashboard
CRAWLRELAY_PASSWORD = os.environ.get("CRAWLRELAY_PASSWORD")
CRAWLRELAY_COUNTRY = "us"
DOWNLOADER_MIDDLEWARES = {
"myproject.middlewares.CrawlRelayProxyMiddleware": 350, # runs before HttpProxyMiddleware (750)
}
CONCURRENT_REQUESTS = 32
CONCURRENT_REQUESTS_PER_DOMAIN = 4
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 1.0
AUTOTHROTTLE_MAX_DELAY = 30.0
AUTOTHROTTLE_TARGET_CONCURRENCY = 2.0
RETRY_ENABLED = True
RETRY_TIMES = 3
RETRY_HTTP_CODES = [429, 500, 502, 503, 504, 522, 524, 408]
DOWNLOAD_TIMEOUT = 45Làm sao để giữ một IP cho phân trang và xoay IP cho các trang mục?
Truyền một proxy_session cố định vào các yêu cầu trong một luồng phụ thuộc vào trang trước đó, và không dùng cho các trang độc lập. Spider dưới đây chạy trên books.toscrape.com, một trang sandbox được tạo ra để luyện tập scraping.
import scrapy
class CatalogSpider(scrapy.Spider):
name = "catalog"
start_urls = ["https://books.toscrape.com/"]
def parse(self, response):
for href in response.css("article.product_pod h3 a::attr(href)").getall():
# Product pages are independent: rotating exits
yield response.follow(href, callback=self.parse_item)
next_page = response.css("li.next a::attr(href)").get()
if next_page:
# The listing flow keeps one sticky exit for 30 minutes
yield response.follow(next_page, callback=self.parse,
meta={"proxy_session": "listing1", "proxy_ttl": 30})
def parse_item(self, response):
yield {
"title": response.css("div.product_main h1::text").get(),
"price": response.css("p.price_color::text").get(),
"url": response.url,
}Scrapy có tái sử dụng kết nối không, và điều đó có làm dừng việc xoay IP không?
Có, Scrapy giữ kết nối luôn hoạt động và tái sử dụng theo proxy và host mục tiêu, nên các yêu cầu liên tiếp trên một kết nối dùng chung một điểm ra. Điều này thường ổn với hầu hết các crawl: Scrapy mở tới CONCURRENT_REQUESTS_PER_DOMAIN kết nối mỗi site, và mỗi kết nối mới thường có một IP proxy dân cư khác.
Khi một yêu cầu cần đi ra qua một IP mới, ví dụ khi thử lại sau lỗi 502 do exit bị lỗi, hãy gửi lại kèm response.request.replace(meta={**response.meta, "proxy_session": "new"}, dont_filter=True). Middleware sẽ tạo một session username mới, username khác nghĩa là pool kết nối khác, vậy Scrapy mở một kết nối mới và gateway thường gán exit khác.
Làm sao để tôn trọng Retry-After trên các phản hồi 429 trong Scrapy?
Scrapy có sẵn RetryMiddleware để thử lại với 429 nhưng không chờ delay Retry-After. AutoThrottle sẽ giảm tốc độ domain dần theo thời gian, thường là đủ. Với API gửi giá trị Retry-After dài, bạn cần thêm middleware nhỏ đọc header và lên lịch thử lại có delay, hoặc giảm CONCURRENT_REQUESTS_PER_DOMAIN cho domain đó. Trang 429 giải thích ý nghĩa header này.
Làm thế nào để dùng proxy với scrapy-playwright?
Với các trang cần JavaScript, scrapy-playwright truyền các tuỳ chọn launch của Playwright qua thiết lập. Cung cấp thông tin đăng nhập riêng biệt: Chromium bỏ qua thông tin trong URL server. Dùng một context cho mỗi session cố định nếu bạn render luồng đăng xuất trải qua nhiều trang.
import os
DOWNLOAD_HANDLERS = {
"http": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler",
"https": "scrapy_playwright.handler.ScrapyPlaywrightDownloadHandler",
}
TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor"
PLAYWRIGHT_LAUNCH_OPTIONS = {
"proxy": {
"server": "http://gw.crawlrelay.com:7777",
"username": os.environ.get("CRAWLRELAY_USER", "USERNAME") + "-country-us",
"password": os.environ.get("CRAWLRELAY_PASSWORD", "PASSWORD"),
},
}Scrapy và proxy: các câu hỏi
Tôi có cần scrapy-rotating-proxies hoặc danh sách proxy không?
Không. Các package đó xoay danh sách các địa chỉ proxy riêng lẻ và chặn địa chỉ bị lỗi. Với gateway proxy dân cư, việc xoay IP diễn ra phía sau một địa chỉ duy nhất: mỗi kết nối mới thường có IP proxy dân cư khác. Chỉ cần một middleware cài request.meta["proxy"] là đủ.
Tại sao Scrapy báo TunnelError với proxy của tôi?
Tôi nên dùng bao nhiêu yêu cầu đồng thời trên mỗi domain?
Bắt đầu với 2 đến 4 yêu cầu mỗi domain và để AutoThrottle điều chỉnh. Tăng số lượng khi tỉ lệ 429, 403 và 5xx giữ ổn định, đồng thời theo dõi thời gian phản hồi site. Site lớn chịu đựng tốt hơn site nhỏ; site nhỏ có thể cần thời gian chờ giữa các yêu cầu và chỉ một kết nối.
Tôi có nên tắt ROBOTSTXT_OBEY để lấy nhiều dữ liệu hơn?
Không. robots.txt là cách site xác định các đường dẫn mà các client tự động được phép lấy, và RFC 9309 đã chuẩn hóa định dạng này từ 2022. Bỏ qua nó gây rủi ro pháp lý và đạo đức, đồng thời vi phạm Chính sách Sử dụng Hợp lệ của chúng tôi khi dùng để truy cập nội dung site đã loại trừ.
Bao nhiêu lưu lượng crawl Scrapy sử dụng?
Scrapy chỉ tải HTML nên mỗi trang thường tốn vài chục KB, đã nén. Kiểm tra giá trị downloader/response_bytes trong thống kê mà Scrapy in ra cuối quá trình rồi chia cho số lượng phản hồi. Hướng dẫn băng thông giúp bạn ước tính chi phí.
Cắm IP proxy dân cư vào dự án Scrapy của bạn
5,94 US$ cho 10 GB để thử, 0,50 US$/GB từ 50 GB.