Scrapy
قم بتكوين Scrapy لتوجيه جميع الطلبات عبر RaxyProxy مع IPs متدورة أو ثابتة.
التثبيت
pip install scrapysettings.py — الوكيل العام
أبسط نهج: تعيين الوكيل في SCRAPY_PROXY or override HttpProxyMiddleware. Every request in the spider will use a different rotating IP automatically.
# ── Proxy ──────────────────────────────────────────────────────────────────
RAXY_USER = 'USERNAME'
RAXY_PASS = 'PASSWORD'
RAXY_HOST = 'proxy.raxyproxy.com'
RAXY_PORT = 823 # HTTP — rotating
# RAXY_PORT = 824 # SOCKS5
PROXY_URL = f'http://{RAXY_USER}:{RAXY_PASS}@{RAXY_HOST}:{RAXY_PORT}'
# Enable Scrapy's built-in proxy middleware
DOWNLOADER_MIDDLEWARES = {
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
}
# Pass proxy URL via environment variable approach (recommended)
import os
os.environ['http_proxy'] = PROXY_URL
os.environ['https_proxy'] = PROXY_URL
# ── Politeness ───────────────────────────────────────────────────────────────
DOWNLOAD_DELAY = 1
RANDOMIZE_DOWNLOAD_DELAY = True
CONCURRENT_REQUESTS = 8
AUTOTHROTTLE_ENABLED = Trueوسيط مخصص
يمنحك الوسيط المخصص تحكماً كاملاً — التدوير لكل طلب، وحقن بيانات الاعتماد، ومعالجة منطق إعادة المحاولة، وتبديل نوع الوكيل لكل عنكبوت.
import base64
class RaxyProxyMiddleware:
"""Inject RaxyProxy credentials into every request."""
HOST = 'proxy.raxyproxy.com'
PORT = 823
USER = 'USERNAME'
PASS = 'PASSWORD'
def process_request(self, request, spider):
proxy = f'http://{self.HOST}:{self.PORT}'
creds = base64.b64encode(f'{self.USER}:{self.PASS}'.encode()).decode()
request.meta['proxy'] = proxy
request.headers['Proxy-Authorization'] = f'Basic {creds}'DOWNLOADER_MIDDLEWARES = {
'myproject.middlewares.RaxyProxyMiddleware': 750,
# Disable the default proxy middleware so they don't conflict
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': None,
}الاستهداف الجغرافي
import base64
class RaxyGeoMiddleware:
"""Per-spider geo-targeting via spider attribute."""
HOST = 'proxy.raxyproxy.com'
PORT = 823
PASS = 'PASSWORD'
def _build_user(self, spider):
base = getattr(spider, 'proxy_user', 'USERNAME')
geo = getattr(spider, 'proxy_geo', None)
return f'{base}__{geo}' if geo else base
def process_request(self, request, spider):
user = self._build_user(spider)
proxy = f'http://{self.HOST}:{self.PORT}'
creds = base64.b64encode(f'{user}:{self.PASS}'.encode()).decode()
request.meta['proxy'] = proxy
request.headers['Proxy-Authorization'] = f'Basic {creds}'import scrapy
class UsSpider(scrapy.Spider):
name = 'us_spider'
# Middleware reads these attributes:
proxy_user = 'USERNAME'
proxy_geo = 'cr.us' # US only — free
# City-level (2× billing for residential/mobile/datacenter):
# proxy_geo = 'cr.us;city.newyork'
start_urls = ['https://httpbin.org/ip']
def parse(self, response):
self.logger.info('IP: %s', response.json()['origin'])الجلسات الثابتة
الجلسات الثابتة القائمة على المنفذ
Ports 10000–20000 المنافذ 10000–20000 يحتفظ كل منها بنفس IP الخروج. قم بتعيين منفذ لكل "جلسة" منطقية حتى يخرج كشط المستخدم دائماً من نفس IP.
import base64
class RaxyStickyMiddleware:
"""Assign a sticky port based on request.meta['session_id']."""
HOST = 'proxy.raxyproxy.com'
USER = 'USERNAME'
PASS = 'PASSWORD'
BASE_PORT = 10000
def process_request(self, request, spider):
session_id = request.meta.get('session_id', 0)
port = self.BASE_PORT + (int(session_id) % 10001) # stay in 10000-20000
proxy = f'http://{self.HOST}:{port}'
creds = base64.b64encode(f'{self.USER}:{self.PASS}'.encode()).decode()
request.meta['proxy'] = proxy
request.headers['Proxy-Authorization'] = f'Basic {creds}'import scrapy
class StickySpider(scrapy.Spider):
name = 'sticky'
def start_requests(self):
for user_id in range(5):
yield scrapy.Request(
url='https://httpbin.org/ip',
meta={'session_id': user_id},
callback=self.parse,
)
def parse(self, response):
self.logger.info(
'session %s → %s',
response.meta['session_id'],
response.json()['origin'],
)التدوير حسب النطاق
أنواع مختلفة من الوكلاء لنطاقات مستهدفة مختلفة — مركز البيانات للواجهات البرمجية العامة، والسكنية للمواقع المحمية.
import base64
DOMAIN_PROFILES = {
# datacenter — cheaper, fast
'api.example.com': {'user': 'USERNAME', 'port': 823},
# residential geo — protected target
'shop.example.com': {'user': 'USERNAME__cr.us', 'port': 823},
}
DEFAULT_PROFILE = {'user': 'USERNAME', 'port': 823}
class RaxyDomainMiddleware:
HOST = 'proxy.raxyproxy.com'
PASS = 'PASSWORD'
def process_request(self, request, spider):
from urllib.parse import urlparse
domain = urlparse(request.url).netloc
profile = DOMAIN_PROFILES.get(domain, DEFAULT_PROFILE)
proxy = f'http://{self.HOST}:{profile["port"]}'
creds = base64.b64encode(
f'{profile["user"]}:{self.PASS}'.encode()
).decode()
request.meta['proxy'] = proxy
request.headers['Proxy-Authorization'] = f'Basic {creds}'نصائح الكشط
أعد المحاولة عند أخطاء الوكيل
قم بتفعيل RETRY_HTTP_CODES لكي يعيد Scrapy المحاولة عند 407 (مصادقة الوكيل) و503. كل إعادة محاولة تحصل على IP متدور جديد.
RETRY_ENABLED = True
RETRY_TIMES = 3
RETRY_HTTP_CODES = [500, 502, 503, 504, 407, 429]
# Respect retry-after headers
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_TARGET_CONCURRENCY = 4| الإعداد | القيمة الموصى بها | لماذا |
|---|---|---|
DOWNLOAD_DELAY | 1–2 | يقلل من خطر الحظر على الأهداف الحساسة |
CONCURRENT_REQUESTS_PER_DOMAIN | 4 | يتجنب إغراق هدف واحد |
COOKIES_ENABLED | False | تبدو IPs المتدورة مع ملفات تعريف الارتباط المشتركة مريبة |
ROBOTSTXT_OBEY | True | افتراضي؛ عطّله فقط عندما يسمح الهدف صراحةً بذلك |
DEFAULT_REQUEST_HEADERS | Set a realistic User-Agent | UA الافتراضي لـ Scrapy يُحظر أحياناً |
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0',
}