خانه/مقالات/وب‌اسکریپینگ پایتون: عبور از ضدربات‌ها
پروکسی و چرخش IP
ضد بلاک (Anti-bot)
Headless Chrome
برگشت به صفحه مقاله ها
وب‌اسکریپینگ پایتون: عبور از ضدربات‌ها

وب‌اسکریپینگ پایتون: عبور از ضدربات‌ها

این مقاله یک راهنمای عملی برای توسعه‌دهندگان پایتون دربارهٔ تکنیک‌های استیلث و دورزدن مکانیزم‌های ضداسکریپ ارائه می‌دهد؛ شامل بهینه‌سازی هدرها، پروکسی‌های چرخان، مرورگرهای headless، حل CAPTCHA و نکات حقوقی و عملی برای تولید یک اسکریپر پایدار و قابل‌اعتماد.
امیر حسین حسینیان
امیر حسین حسینیان
1404-09-22

مقدمه

وب‌سایت‌های مدرن از مکانیزم‌های پیچیده‌ای برای شناسایی و مسدودسازی دسترسی‌های خودکار استفاده می‌کنند. در این مقاله به‌زبان فارسی یک راهنمای عملی و فنی برای «وب اسکریپینگ» و «اسکریپ کردن» داده‌ها تهیه کرده‌ام که مناسب توسعه‌دهندگان پایتون در سطح متوسط است. پس از خواندن این مقاله می‌دانید چه روش‌هایی برای دور زدن محافظت‌ها وجود دارد، هر روش چه مزایا و معایبی دارد و چگونه با مثال‌های کد می‌توانید آن‌ها را پیاده کنید.

درک مکانیزم‌های ضداسکریپ

پیش از هر تلاش اسکریپ، باید بفهمیم سایت هدف چگونه رفتار را اندازه‌گیری و امتیازدهی می‌کند. شایع‌ترین تکنیک‌ها عبارت‌اند از:

  • Rate limiting: محدودیت تعداد درخواست در بازه زمانی مشخص.
  • IP blocking / Reputation: بلاک کردن یا کاهش دسترسی برای IPهایی با رفتار مشکوک.
  • User-Agent و هدرها: تطابق هدرها و رشته‌هایی مثل User-Agent با رفتار مرورگرهای واقعی.
  • چالش‌های جاوااسکریپتی: نیاز به اجرای JS یا تعامل کاربر برای دسترسی به محتوا.
  • جلسه‌سازی و کوکی: ردیابی با کوکی‌ها، localStorage و fingerprinting.

شناخت این مکانیزم‌ها کمک می‌کند تا روش مناسب (مثلاً تغییر هدرها، استفاده از پروکسی یا سراغ یک مرورگر headless رفتن) را انتخاب کنیم.

روش 1 — بهینه‌سازی Request Fingerprints (هدرها و User-Agent)

ایده کلی: با تغییر و چرخش هدرها و User-Agent سعی می‌کنیم درخواست‌های خود را شبیه درخواست‌های انسانی کنیم تا تشخیص بات سخت‌تر شود.

مثال عملی در پایتون با requests. این قطعه کد یک لیست از User-Agentها را نگه می‌دارد و برای هر درخواست به‌صورت تصادفی یکی انتخاب می‌کند.

import random
import requests

USER_AGENTS = [
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Chrome/91.0',
    'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ... Chrome/91.0',
    # لیست را واقعی‌تر و بزرگ‌تر کنید
]

def fetch(target_url):
    """ورودی: target_url (رشته)
    خروجی: محتوای HTML صفحه یا None در صورت خطا
    نقش: ارسال یک GET با User-Agent تصادفی"""
    headers = {
        'User-Agent': random.choice(USER_AGENTS),
        'Accept-Language': 'en-US,en;q=0.9',
        # سایر هدرهای مشابه مرورگر را اضافه کنید
    }
    resp = requests.get(target_url, headers=headers, timeout=15)
    resp.raise_for_status()
    return resp.text

توضیح خط‌به‌خط:

  • USER_AGENTS: لیست User-Agentها؛ در محیط واقعی نیاز به مجموعه‌ی بزرگ‌تری دارید.
  • fetch: تابعی که هدرها را ست می‌کند و با requests.get درخواست را می‌فرستد. resp.raise_for_status() خطاهای HTTP را پرتاب می‌کند.

نکات مهم و محدودیت‌ها:

  • فقط چرخش User-Agent کافی نیست؛ باید هدرهای دیگر (Accept, Accept-Language, Connection, Sec-* headers) و الگوی زمانی درخواست‌ها را نیز طبیعی کرد.
  • استفاده از لیست کوچک باعث شناسایی سریع می‌شود؛ از مجموعه‌های به‌روز استفاده کنید.

روش 2 — استفاده از پروکسی‌های چرخان (Rotating Proxy Pools)

چالش: وقتی درخواست‌ها از یک آدرس IP ثابت ارسال شوند، احتمال بلاک بالا می‌رود. راه‌حل: با استفاده از پروکسی‌ها IP را تغییر دهید.

نمونه سادهٔ چرخش پروکسی در پایتون (با requests):

PROXIES = [
    {'http': 'http://USER:PASS@PROXY1', 'https': 'http://USER:PASS@PROXY1'},
    {'http': 'http://USER:PASS@PROXY2', 'https': 'http://USER:PASS@PROXY2'},
]

def fetch_via_proxy(target_url):
    proxy = random.choice(PROXIES)
    resp = requests.get(target_url, headers={'User-Agent': random.choice(USER_AGENTS)}, proxies=proxy, timeout=20)
    resp.raise_for_status()
    return resp.text

توضیح:

  • ورودی: لیست پروکسی‌ها و یک آدرس هدف.
  • خروجی: HTML صفحه یا خطا.
  • نکتهٔ عملی: پروکسی‌های رایگان معمولاً کند، ناپایدار و احتمالاً در فهرست سیاه‌اند؛ برای کار در مقیاس از پروکسی‌های مسکونی یا سرویس‌های پولی استفاده کنید.

مثال استفاده از Playwright (پایتون) با پروکسی برای رندر جاوااسکریپت:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(proxy={
        'server': 'PROXY_HOST:PORT',
        'username': 'PROXY_USER',
        'password': 'PROXY_PASS'
    }, headless=True)
    page = browser.new_page()
    page.goto('TARGET_URL', timeout=30000)
    html = page.content()
    browser.close()

این روش برای سایت‌هایی که نیاز به اجرای JS دارند بسیار مفید است؛ پروکسی را می‌توانید به‌صورت پویا برای هر instance انتخاب کنید.

روش 3 — مرورگرهای Headless تقویت‌شده (Fortified Headless Browsers)

ایده: از مرورگرهایی استفاده کنید که رفتار انسان را بهتر شبیه‌سازی کنند تا جاوااسکریپت‌ها و تعاملات را پاس کنند.

نمونه با Playwright (پایتون) — مناسب برای صفحات دینامیک:

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(headless=True)
    context = browser.new_context(
        user_agent='A realistic UA string here',
        viewport={'width': 1280, 'height': 800}
    )
    page = context.new_page()
    page.goto('TARGET_URL')
    # تعاملات: کلیک، اسکرول، پر کردن فرم
    page.wait_for_timeout(2000)
    html = page.content()
    browser.close()

همچنین ابزارهای Node.js مثل puppeteer-extra با پلاگین stealth معروف هستند. نمونهٔ کوتاه جاوااسکریپت برای مراجعۀ سریع:

const puppeteer = require('puppeteer-extra')
const StealthPlugin = require('puppeteer-extra-plugin-stealth')
puppeteer.use(StealthPlugin())
;(async () => {
  const browser = await puppeteer.launch({ headless: true })
  const page = await browser.newPage()
  await page.goto('TARGET_URL')
  // استخراج داده‌ها
  await browser.close()
})();

توضیح: پلاگین استیلث سعی می‌کند نشانه‌های اتومات بودن را تغییر دهد (navigator.webdriver، افزونه‌ها، WebGL، و غیره). استفاده از چنین ابزارهایی در کنار پروکسی توصیه می‌شود.

روش 4 — استفاده از سرویس‌های مدیریت‌شدۀ Anti-Bot

به‌جای ساختن تمام اجزا از صفر، می‌توانید از ارائه‌دهندگان پروکسی و سرویس‌های «Anti-Bot Bypass» استفاده کنید که راه‌حل‌های ترکیبی (پروکسی مسکونی + شبیه‌سازی مرورگر + حل چالش‌ها) ارائه می‌کنند. نام‌هایی که در صنعت رایج‌اند شامل ScrapeOps، BrightData، Oxylabs و Zyte هستند.

مزایا:

  • راه‌اندازی سریع‌تر و نرخ موفقیت بالاتر برای صفحات سخت.
  • پشتیبانی از مدیریت کوکی، حل چالش‌ها و گزارش‌دهی.

معایب:

  • هزینه‌ها می‌تواند بالا باشد؛ برای حجم بالا باید براورد هزینه دقیق داشته باشید.
  • وابستگی به سرویس بیرونی و موارد احتمالی محدودیت‌های استفاده یا قوانین.

نمونهٔ فراخوان API ساده (پایتون) با axios معادل requests — توجه کنید که باید مقادیر توکن و پارامترها را مطابق سرویس جایگزین کنید:

import requests

API_KEY = 'YOUR_API_KEY'
params = {
    'api_key': API_KEY,
    'url': 'TARGET_URL',
    'bypass': 'cloudflare_level_1'  # مثال پارامتر سمت سرویس
}
resp = requests.get('PROXY_API_ENDPOINT', params=params, timeout=30)
print(resp.text)

این الگو به سرویس مدیریت‌شده اجازه می‌دهد تا با توجه به دامنهٔ هدف، استراتژی مناسب (پروکسی، مرورگر واقعی، حل CAPTCHA و...) را به کار ببندد.

روش 5 — حل CAPTCHAها

چالش: CAPTCHAها عمداً برای جدا کردن انسان از ربات طراحی شده‌اند. راه‌حل‌های متداول استفاده از سرویس‌های حل CAPTCHA است که یا نیروی انسانی یا الگوریتم دارند.

مثال با کتابخانه 2captcha برای پایتون:

from twocaptcha import TwoCaptcha

solver = TwoCaptcha('TWO_CAPTCHA_API_KEY')
try:
    result = solver.recaptcha(sitekey='RECAPTCHA_SITEKEY', url='PAGE_WITH_RECAPTCHA')
    token = result['code']
    # ارسال توکن به فرم یا API صفحه
except Exception as e:
    print('CAPTCHA error:', e)

توضیح: ورودی‌ها شامل sitekey و آدرس صفحه هستند. خروجی یک توکن است که باید در فیلد مربوطه در صفحه قرار گیرد. هزینه و زمان حل بسته به سرویس و نوع CAPTCHA متغیر است.

نکتهٔ اخلاقی و قانونی: استفاده از خدمات حل CAPTCHA ممکن است با مقررات برخی سایت‌ها در تضاد باشد؛ همیشه موارد حقوقی را بررسی کنید.

روش 6 — استفاده از نسخه‌های کش شده (مثلاً کش موتورهای جستجو)

اگر دادهٔ شما می‌تواند اندکی قدیمی باشد، گرفتن نسخهٔ کش‌شدهٔ یک صفحه (مثلاً نسخه‌هایی که موتورهای جستجو نگهداری می‌کنند) راهکار سریع و سبک‌تری است. مزایا: بسیاری از دفاع‌ها در نسخهٔ کش وجود ندارند. معایب: داده‌ها ممکن است به‌روز نباشند و همه صفحات کش نمی‌شوند.

الگو: ابتدا بررسی کنید صفحه کش دارد یا نه؛ سپس آن را بخوانید. اگر به‌روزی مهم است از این روش صرف‌نظر کنید.

روش 7 — مهندسی معکوس Anti-Bot (Reverse Engineering)

این روش شامل تحلیل عمقی رفتارهای سمت سرور و کلاینت سایت هدف برای پیدا کردن شکاف‌هایی است که بتوان از آنها استفاده کرد. مثال‌ها: شبیه‌سازی TLS fingerprints، بازسازی توالی درخواست‌های جاوااسکریپت، یا بازتولید تعاملات DOM.

مزایا و معایب:

  • مزایا: بهینه، کم‌هزینه از نظر منابع و می‌تواند بسیار مؤثر باشد.
  • معایب: پیچیدگی فنی بالا، نیاز به نگهداری مداوم و ریسک‌های قانونی/اخلاقی.

این رویکرد برای تیم‌هایی مناسب است که در سطوح پایین شبکه و مرورگر تخصص دارند و ملاحظات حقوقی را بررسی کرده‌اند.

مطالعهٔ موردی: تلاش برای اسکریپ کردن petsathome (شرح گام‌ها)

گام 1 — تلاش با requests و BeautifulSoup (معادل cheerio در Node): در بعضی صفحات ساده، همین روش کافی است. کد نمونه:

import requests
from bs4 import BeautifulSoup

resp = requests.get('TARGET_URL', headers={'User-Agent': random.choice(USER_AGENTS)})
soup = BeautifulSoup(resp.text, 'html.parser')
print(soup.title.string)

نتیجهٔ ممکن: اگر صفحه محتوای استاتیک داشته باشد یا سایت اجازهٔ ایندکس ساده را بدهد، همین کافیست. در غیر این صورت به روش‌های دیگر نیاز است.

گام 2 — استفاده از پروکسی چرخان و مرورگر headless: اگر سایت دارای حفاظت‌های Cloudflare یا شبیه آن باشد، ترکیب Playwright + پروکسی یا استفاده از سرویس‌های مدیریت‌شده معمولاً موفق است.

جمع‌بندی مطالعهٔ موردی: ترکیب روش‌ها (هدر بهینه، پروکسی، مرورگر headless) بیشترین شانس موفقیت را دارد؛ اما هزینه، مقیاس‌پذیری و نگهداری را نیز مد نظر قرار دهید.

بهترین روش‌ها و هشدارهای عملی

  • از الگوهای نرخ دسترسی انسانی پیروی کنید (تاخیر تصادفی بین درخواست‌ها، پیکربندی باثبات زمانی).
  • در محیط تولید از پروکسی‌های باکیفیت استفاده کنید؛ پروکسی‌های رایگان معمولا دردسرسازند.
  • اعتبارسنجی قانونی: مطمئن شوید که قوانین سایت و مقررات محلی را رعایت می‌کنید.
  • مدیریت خطا: برای خطاهای شبکه، retryهای با backoff و لاگ دقیق پیاده‌سازی کنید.
  • امنیت: کلیدهای API و اطلاعات پروکسی را در متغیرهای محیطی یا مخزن امن نگهداری کنید، نه به‌صورت هاردکد.

جمع‌بندی

برای موفقیت در وب اسکریپینگ باید به‌صورت ترکیبی عمل کنید: بهینه‌سازی هدرها، چرخش پروکسی، استفاده از مرورگرهای headless تقویت‌شده و در صورت نیاز سرویس‌های مدیریت‌شده یا حل CAPTCHA. هر روش مزایا و هزینه‌های خودش را دارد؛ انتخاب مناسب بستگی به حساسیت سایت هدف، میزان ضرورت به‌روزرسانی داده و منابع شما دارد.

پیشنهاد عملی: برای شروع یک پروتوتایپ کوچک با requests و هدرهای بهینه بسازید؛ اگر شکست خورد، به‌تدریج Playwright و پروکسی را اضافه کنید و در نهایت در صورت نیاز سرویس‌های مدیریت‌شده را آزمایش کنید.

مقاله‌های مرتبط
بهینه‌سازی درخواست‌ها و جلوگیری از بلاک‌شدن
1404-09-16
بازتلاش (Retry) درخواست‌ها در Java OkHttp برای وب اسکریپینگ
این مقاله دو راهکار عملی برای بازتلاش درخواست‌ها در Java OkHttp برای وب اسکریپینگ را نشان می‌دهد: استفاده از کتابخانهٔ Retry4j برای پیکربندی سریع و قابل‌تنظیم، و نوشتن wrapper سفارشی برای کنترل دقیق‌تر (شامل بررسی HTML با Jsoup). نکات عملی دربارهٔ backoff، timeouts، امنیت و بهترین روش‌ها نیز ارائه شده است.
بهینه‌سازی درخواست‌ها و جلوگیری از بلاک‌شدن
1404-09-15
اسکریپ با Java: تنظیم و چرخش User-Agent در OkHttp و Apache HttpClient
این مقاله نشان می‌دهد چگونه در Java با OkHttp و Apache HttpClient هدرهای User-Agent و مجموعه هدرهای مرورگر را تنظیم و بچرخانید، چگونه با APIهای بیرونی هزاران User-Agent را مدیریت کنید و بهترین شیوه‌های امنیتی و عملکردی برای وب اسکریپینگ را پیاده‌سازی کنید.
بهینه‌سازی درخواست‌ها و جلوگیری از بلاک‌شدن
1404-09-14
همزمان‌سازی درخواست‌ها با OkHttp و Apache HttpClient برای وب اسکریپینگ
این مقاله روش‌های عملی برای ارسال درخواست‌های همزمان با OkHttp و Apache HttpClient را برای وب اسکریپینگ توضیح می‌دهد؛ شامل نمونه‌های کد جاوا، توضیح خط‌به‌خط، نکات مدیریت خطا، تنظیم Thread pool و مثال ادغام با پراکسی (مانند ScrapeOps). پس از خواندن این راهنما می‌دانید چگونه همزمانی را امن، پایدار و قابل اندازه‌گیری پیاده‌سازی کنید.