Scrapy xử lý proxy như thế nào?
Scrapy có HttpProxyMiddleware được bật mặc định. Thêm địa chỉ proxy vào từ khóa proxy trong meta của yêu cầu để yêu cầu đó đi qua proxy đó và middleware sẽ chuyển đổi tên người dùng và mật khẩu trong địa chỉ thành tiêu đề Proxy-Authorization. Địa chỉ HTTPS đi qua đường hầm CONNECT.
Trình xử lý tải xuống mặc định của Scrapy hỗ trợ HTTP proxy. Nếu bạn cần SOCKS5, bạn sẽ cần một trình xử lý riêng, vì vậy Scrapy khuyến nghị sử dụng cổng HTTP của cùng một IP. IP mà trang đích nhìn thấy sẽ giống nhau.
Ví dụ sử dụng IP 198.51.100.23, cổng HTTP 8000, username spx_user, password spx_pass.
pip install scrapy
scrapy startproject shop
cd shopLàm thế nào để thêm proxy vào một yêu cầu?
Chỉ cần thêm proxy vào meta khi tạo Request trong start_requests. Khi yêu cầu trang tiếp theo trong callback, hãy thêm theo cùng cách. Nếu cần duy trì cùng một phiên, hãy chuyển giá trị proxy từ meta của phản hồi trước để giữ nguyên IP.
import scrapy
PROXY = "http://spx_user:spx_pass@198.51.100.23:8000"
class IpCheckSpider(scrapy.Spider):
name = "ip_check"
def start_requests(self):
yield scrapy.Request("https://api.ipify.org?format=json", meta={"proxy": PROXY})
def parse(self, response):
self.logger.info("seen as %s", response.json()["ip"])Làm thế nào để luân chuyển IP cho mỗi yêu cầu?
Tạo một middleware downloader để thêm proxy sau vào mọi yêu cầu, bạn có thể luân phiên mà không cần thay đổi mã spider. Middleware bên dưới nhận danh sách qua API khi bắt đầu, và nếu meta đã có proxy, nó sẽ giữ nguyên để có thể sử dụng cùng lúc session cố định và luân phiên.
Đặt API key trong settings.py hoặc đọc từ biến môi trường. Đăng ký với số thứ tự nhỏ hơn HttpProxyMiddleware(750) để middleware mặc định xử lý địa chỉ do middleware chèn.
import itertools
import requests
class RotatingProxyMiddleware:
def __init__(self, key):
text = requests.get(
"https://socks5proxy.io/api/v1/proxies/download",
params={"format": "user:pass@ip:port", "protocol": "http"},
headers={"Authorization": "Bearer " + key},
timeout=30,
).text
self.pool = itertools.cycle(["http://" + l.strip() for l in text.splitlines() if l.strip()])
@classmethod
def from_crawler(cls, crawler):
return cls(crawler.settings.get("SPX_API_KEY"))
def process_request(self, request, spider):
if "proxy" not in request.meta: # keep a proxy that was set on purpose (sticky sessions)
request.meta["proxy"] = next(self.pool)SPX_API_KEY = "YOUR_API_KEY"
DOWNLOADER_MIDDLEWARES = {
"shop.middlewares.RotatingProxyMiddleware": 740,
}
CONCURRENT_REQUESTS = 32
CONCURRENT_REQUESTS_PER_DOMAIN = 16
DOWNLOAD_DELAY = 0.25
AUTOTHROTTLE_ENABLED = True
RETRY_TIMES = 3
RETRY_HTTP_CODES = [429, 500, 502, 503, 504, 522, 524, 408]
DOWNLOAD_TIMEOUT = 30Làm thế nào để điều chỉnh tốc độ và số lần thử lại?
CONCURRENT_REQUESTS_PER_DOMAIN là số yêu cầu đồng thời gửi đến cùng tên miền. Càng nhiều IP proxy càng có thể tăng giá trị này mà tải mỗi IP không đổi. Ví dụ 500 IP gửi 50 yêu cầu đồng thời, mỗi IP trung bình chỉ dùng 1 lần trong 10 yêu cầu.
Bật AUTOTHROTTLE để tự động điều chỉnh khoảng cách yêu cầu theo tốc độ phản hồi. Nếu tăng phản hồi 429, dùng RETRY_HTTP_CODES để thử lại nhưng xóa proxy trong meta để middleware chèn proxy tiếp theo khi thử lại.
Đặt một bước kiểm tra trong pipeline để xác minh rằng kết quả thu thập là trang thực tế chứ không phải trang xác nhận. Điều này sẽ cải thiện chất lượng dữ liệu. Nếu phản hồi thiếu các yếu tố mong muốn, bạn có thể yêu cầu lại bằng IP khác.
- Điều chỉnh số yêu cầu đồng thời theo tên miền dựa trên số IP
- Tự động điều chỉnh khoảng cách với AUTOTHROTTLE theo tốc độ phản hồi
- Thử lại với IP khác khi gặp 429 hoặc 5xx
- Kiểm tra nội dung phản hồi để lọc màn hình xác nhận
Kết nối bằng xác thực IP khác gì?
Khi bạn đăng ký IPv4 của máy chủ chạy Scrapy trên bảng điều khiển, bạn có thể sử dụng meta proxy mà không cần tên người dùng và mật khẩu, ví dụ như http://198.51.100.23:8000. Bạn cũng có thể nhận danh sách với định dạng format=ip:port. Nếu bạn chạy spider trên nhiều máy chủ, hãy đăng ký IP của từng máy chủ. Bạn có thể đăng ký tối đa 10 IP.
Làm cách nào để nhóm các yêu cầu cần phiên vào cùng một IP?
Đối với các luồng yêu cầu liên tục như đăng nhập hoặc giỏ hàng, bạn cần sử dụng cùng một IP. Hãy đặt meta proxy trực tiếp vào yêu cầu đầu tiên và trong callback, khi tạo yêu cầu tiếp theo, hãy chuyển giá trị proxy từ response.meta để middleware tuần hoàn không thay đổi nó. Sử dụng cùng với meta key cookiejar của Scrapy sẽ giúp cookie được tách biệt cho mỗi phiên.
Ghép một proxy với một nhóm cookie trong một phiên giúp chạy nhiều phiên đồng thời mà không bị trộn lẫn.
import scrapy
PROXIES = [
"http://spx_user:spx_pass@198.51.100.23:8000",
"http://spx_user:spx_pass@198.51.100.24:8000",
]
class SessionSpider(scrapy.Spider):
name = "sessions"
def start_requests(self):
for i, proxy in enumerate(PROXIES):
yield scrapy.Request("https://example.com/", meta={"proxy": proxy, "cookiejar": i}, dont_filter=True)
def parse(self, response):
# follow-up request keeps the same proxy and the same cookie jar
yield response.follow("/account", meta={"proxy": response.meta["proxy"], "cookiejar": response.meta["cookiejar"]}, callback=self.parse_account)
def parse_account(self, response):
self.logger.info("status %s via %s", response.status, response.meta["proxy"])Làm thế nào để tạm loại bỏ proxy lỗi?
Khi nhận được phản hồi 403 hoặc 429 trong process_response của middleware, bạn có thể cho proxy đó nghỉ vài phút và gửi lại yêu cầu qua proxy khác. Sao chép yêu cầu, xóa proxy trong meta, bật dont_filter rồi trả về để proxy tiếp theo được sử dụng.
Quản lý danh sách proxy nghỉ và thời gian sử dụng lại bằng từ điển sẽ đơn giản hơn. Không sử dụng lại cùng một IP ngay lập tức sẽ giúp giảm thời gian chờ để giới hạn của trang web được gỡ bỏ.
Cần cài đặt gì để tiết kiệm băng thông trong Scrapy?
Scrapy mặc định chỉ nhận HTML nên sử dụng băng thông ít hơn nhiều so với công cụ trình duyệt. HttpCompressionMiddleware được bật mặc định để nhận phản hồi nén, giúp giảm lượng dữ liệu truyền tải hơn nữa. Đó là lý do bạn có thể thu thập nhiều trang trong giới hạn băng thông hàng tháng của gói chia sẻ.
Bật HTTPCACHE_ENABLED khi phát triển để tránh nhận lại cùng trang, không cần gọi lại site đích và proxy mỗi lần thử nghiệm. Khi vận hành, giữ tính năng lọc trùng địa chỉ (mặc định bật) và chỉ dùng dont_filter cho yêu cầu thực sự cần tải lại.
Việc giới hạn phạm vi liên kết để tránh lan rộng sang các trang con không cần thiết cũng rất quan trọng. Xác định rõ phạm vi thu thập sẽ giúp tiết kiệm thời gian, băng thông và giảm tải cho trang web đích.
Làm thế nào để giải quyết các vấn đề thường gặp?
Khi nhận phản hồi 407, kiểm tra tên người dùng và mật khẩu trong URL. Nếu mật khẩu có ký tự đặc biệt, cần mã hóa phần trăm. TunnelError xảy ra khi proxy không nhận được yêu cầu CONNECT - kiểm tra đang dùng cổng HTTP.
Nếu mọi yêu cầu đều đi qua cùng một IP, có thể do middleware có thứ tự sau HttpProxyMiddleware hoặc spider trực tiếp thêm meta proxy. Kiểm tra cả thứ tự trong settings.py và mã spider.