

در این مقاله عملی برای توسعهدهندههای پایتون میانی، میآموزیم چطور یک اسکریپ Playwright بسازیم که کمترین شانسِ شناسایی شدن توسط ضدرباتها را داشته باشد. ابتدا مکانیسمهای تشخیص بات را مرور میکنیم، سپس تکنیکهای پراکسی، تغییرات در محیط مرورگر و تقلید رفتار انسان را گامبهگام پیادهسازی میکنیم. در پایان روشهای تست، مدیریت خطا و نگارش عمومیِ بهترینروشها را میبینید.
بعد از خواندن این مقاله باید بتوانید: توضیح دهید سایتها چگونه بات را تشخیص میدهند، یک کانتکست Playwright در پایتون تنظیم کنید، جاویژههایی برای تقلید رفتار انسان و مدیریت CAPTCHA و پروکسی پیادهسازی کنید و اسکریپهای خود را آزمایش و پایش کنید.
درک روشهای تشخیص مهم است چون راهحلها بر اساس همان حملات طراحی میشوند:
navigator.webdriver یا آرگومانهای راهاندازی که نشاندهنده اتوماسیوناند.برای هر مورد باید یک یا چند راهحل متناسب طراحی شود: پراکسی چرخان، تغییر هدرها، حذف/اصلاح فلگهای اتوماسیون، و تولید رفتار انسانمانند.
این بخش شامل تکنیکهایی است که تقریباً همیشه در ترکیب استفاده میشوند.
یک user-agent معتبر که با مشخصات viewport و locale سازگار باشد از ناسازگاری فینگرپرینت جلوگیری میکند. مثال زیر راهاندازی کانتکست در پایتون را نشان میدهد:
from playwright.async_api import async_playwright
async def example():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
context = await browser.new_context(
user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36',
viewport={'width': 1280, 'height': 720},
locale='en-US',
timezone_id='America/New_York'
)
page = await context.new_page()
await page.goto('https://example.com')
await browser.close()شرح: ورودیهای تابع شامل user_agent، viewport و locale هستند؛ اینها خروجیِ فینگرپرینت را تغییر میدهند تا با یک کاربر واقعی منطبق شود.
بسیاری از تشخیصها از فلگهای کروم/کرومیوم استفاده میکنند. حذف یا اصلاح آنها کمک میکند. در زمان لانچ کردن میتوان آرگومانها را اضافه کرد:
browser = await p.chromium.launch(
headless=False,
args=[
'--disable-blink-features=AutomationControlled',
'--disable-extensions',
'--disable-infobars',
'--no-first-run',
'--enable-webgl',
'--enable-accelerated-2d-canvas'
]
)نکتهٔ امنیتی: برخی از فلگها ممکن است با سیاستهای سایت تداخل داشته باشند؛ هر تغییر را آزمایش کنید.
وجود WebGL و پارامترهای گرافیکی سازگار به سایتها نشان میدهد که مرورگر امکانات سختافزاری دارد—معمولاً سرورها روی مرورگرهای واقعی حساب باز میکنند.
پراکسی مسکونی بهتر از دیتاسنتر است چون IP از ISP واقعی میآید و تشخیص آن سختتر است. برای اتصال پراکسی در Playwright پایتون:
browser = await p.chromium.launch(proxy={
'server': 'http://residential-proxy.example:3128',
'username': 'user',
'password': 'pass'
})برای چرخش IP معمولاً از یک لایه پراکسی مدیریتی یا پروکسیآگروگیتور استفاده میکنیم که درخواستها را به IPهای مختلف ارسال میکند.
یکی از موثرترین بخشها شبیهسازی تعاملات انسانی است: تایپ با تأخیرهای متغیر، حرکت موس با الگوی غیرقابلپیشبینی و اسکرول تدریجی. مثال پیادهسازی ساده در پایتون:
import random
import asyncio
from playwright.async_api import async_playwright
async def human_type(page, selector, text):
for ch in text:
await page.type(selector, ch)
await asyncio.sleep(random.uniform(0.05, 0.25))
async def random_mouse_movements(page, moves=5):
for _ in range(moves):
x = random.randint(0, 1000)
y = random.randint(0, 800)
await page.mouse.move(x, y)
await asyncio.sleep(random.uniform(0.05, 0.3))
async def demo():
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
context = await browser.new_context(viewport={'width':1280,'height':720})
page = await context.new_page()
await page.goto('https://example.com')
await random_mouse_movements(page)
await human_type(page, 'input[name="q"]', 'hello world')
await browser.close()
# run demo with an asyncio loopتوضیح: human_type و random_mouse_movements ورودیهای ساده میگیرند و رفتار را تقسیم میکنند تا طبیعیتر بهنظر برسد.
برای برخی زبانها (بهویژه Node.js) کتابخانههایی مانند playwright-extra یا پلاگینهای puppeteer-extra-plugin-stealth وجود دارند که مجموعهای از اصلاحات را خودکار میکنند. اگر از پایتون استفاده میکنید ممکن است مجبور شوید برخی از این تکنیکها را دستی اعمال کنید یا از ابزارهای هاستشده استفاده کنید.
// مثال JS: استفاده از playwright-extra + stealth (برای درک ایده)
const { chromium } = require('playwright-extra')
const stealth = require('puppeteer-extra-plugin-stealth')()
chromium.use(stealth)
chromium.launch({ headless: true }).then(async browser => {
const page = await browser.newPage()
await page.goto('https://bot.sannysoft.com')
await browser.close()
})توضیح: اینجا مثال JS برای درک رفتار و مقایسه آمده؛ در پایتون معادل کاملِ همین پکیجها همیشه در دسترس نیست، بنابراین «فورتِفای» دستی با ترکیب فلگها، هدرها و تعاملهای انسانی معمولتر است.
برای بررسی میزان «انسانماندگی» اسکریپ از سایتهایی مثل bot.sannysoft و bot.incolumitas استفاده کنید. عبارتهای مهم برای استخراج امتیازها را در صفحه بخوانید و خروجی را لاگ کنید. نمونهٔ سادهٔ بررسی محتوای صفحه:
# نمونهٔ ساده برای خواندن خروجی تست از یک صفحه
async with async_playwright() as p:
browser = await p.chromium.launch(headless=False)
context = await browser.new_context()
page = await context.new_page()
await page.goto('https://bot.incolumitas.com')
# خواندن محتوای عناصر مربوط به تستها
new_tests = await page.eval_on_selector('#new-tests', 'el => el.textContent')
print(new_tests)
await browser.close()مقایسهٔ نتایج قبل و بعد از فورتِفای نشان میدهد چه تکنیکهایی بیشترین تأثیر را دارند (مثلاً افزایش behavioralClassificationScore).
اسکریپها در مواجهه با شبکه ناپایدار یا پاسخهای غیرمنتظره باید مقاوم باشند. یک الگوی رایج استفاده از حلقه retry با backoff است:
import asyncio
async def run_with_retries(func, max_retries=5):
for attempt in range(1, max_retries+1):
try:
return await func()
except Exception as e:
print(f'Attempt {attempt} failed:', e)
if attempt == max_retries:
raise
await asyncio.sleep(2 ** attempt)
# استفاده: await run_with_retries(lambda: your_async_task())نکته: لاگبرداری و متریکبرداری به شما کمک میکند الگوهای خطا را تشخیص دهید.
CAPTCHAها چالشبرانگیزند و سه رویکرد اصلی وجود دارد:
نمونهٔ پردازش CAPTCHA با 2Captcha در پایتون (خلاصه):
import requests
import time
API_KEY = 'YOUR_2CAPTCHA_KEY'
def submit_captcha(base64_image):
res = requests.post('http://2captcha.com/in.php', data={
'key': API_KEY,
'method': 'base64',
'body': base64_image
})
if res.text.split('|')[0] != 'OK':
raise Exception('submit failed')
return res.text.split('|')[1]
def poll_solution(captcha_id, timeout=120):
t0 = time.time()
while time.time() - t0 < timeout:
res = requests.get('http://2captcha.com/res.php', params={'key': API_KEY, 'action':'get', 'id':captcha_id})
if res.text == 'CAPCHA_NOT_READY':
time.sleep(5)
continue
if res.text.split('|')[0] == 'OK':
return res.text.split('|')[1]
raise Exception('error solving')
# مراحل در اسکریپ: گرفتن screenshot از عنصر CAPTCHA، ارسال base64 به submit_captcha و سپس poll_solutionهشدار: استفاده از سرویسهای حل CAPTCHA ممکن است قوانین سرویس هدف را نقض کند؛ قبل از پیادهسازی بررسی حقوقی و اخلاقی انجام دهید.
خلاصهٔ تجربهٔ عملی: یک اسکریپ ساده بدون فورتِفای سریعاً با CAPTCHA یا صفحات ناقص مواجه میشود. با افزودن user-agent معتبر، کوکیِ جلسه (session cookie)، تغییر viewport، و کمی تعامل انسانی (تایپ و حرکت موس)، صفحه بهدرستی لود شد و دادهها استخراج شدند. نکتهٔ کلیدی: ترکیب تکنیکها بهتر از تکیکار کردن است.
برای ساختن یک اسکریپ Playwright که کمتر شناسایی شود، باید همزمان روی چند لایه کار کنید: تنظیمات مرورگر (user-agent، فلگها، WebGL)، پراکسی مناسب و چرخان، و شبیهسازی رفتار انسان. تست مرتب با ابزارهای fingerprinting و پایش لاگ به شما نشان میدهد کدام بخشها نیاز به تقویت دارند. همیشه ملاحظات اخلاقی و حقوقی را در نظر بگیرید و از حمله به زیرساخت سایت یا استخراج دادههای حساس خودداری کنید.
این مقاله حاوی نمونههای کد پایتون برای پیادهسازی عملیِ هر تکنیک بود؛ برای پیادهسازی در پروژههای تولیدی، این قطعات را با لایهٔ مدیریت خطا، لاگینگ و سازوکار احراز هویت یکپارچه کنید.


