مقدمه
در این مقاله عملی دربارهٔ اسکریپینگ با Python Requests یاد میگیریم چطور رشتههای User-Agent و مجموعه هدرهای مرورگر را مدیریت کنیم تا شانس مواجهه با بلاک شدن کاهش یابد. پس از خواندن این راهنما میتوانید: تعریف کردن User-Agent، استفاده از Session، چرخاندن (rotate) User-Agentها، دریافت و مدیریت هزاران User-Agent از یک API و تولید هدرهای شبیهسازیشدهٔ مرورگر را انجام دهید.
User-Agent چیست و چرا اهمیت دارد؟
رشتهٔ User-Agent بخشی از هدرهای HTTP است که نشان میدهد درخواست از چه مرورگر، سیستمعاملی یا کتابخانهای آمده است. وقتی از کتابخانهای مثل Python Requests بدون تنظیم User-Agent استفاده میکنید، سرورها بهراحتی متوجه میشوند که درخواست شما توسط یک اسکریپر ارسال شده است و ممکن است بلوک شوید.
مثال یک User-Agent واقعی (نمونه):
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36"نکتهٔ مهم: فقط تغییر User-Agent کافی نیست؛ روش ارسال سایر هدرها و رفتار درخواستها (نرخ درخواست، بازههای زمانی، کوکیها، اجرای جاوااسکریپت و غیره) نیز ملاک تشخیص است.
تنظیم User-Agent در یک درخواست ساده
ایدهٔ کلی: یک دیکشنری headers میسازیم و مقدار کلید "User-Agent" را به مقدار دلخواه اختصاص میدهیم و آن را به متد requests.get میدهیم.
import requests
headers = {
"User-Agent": "Mozilla/5.0 (iPad; CPU OS 12_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148"
}
# INPUT: headers (دیکشنری حاوی User-Agent)
# OUTPUT: شیٔ Response از requests
r = requests.get(TARGET_URL, headers=headers, timeout=10)
print(r.status_code)
print(r.headers.get('Content-Type'))توضیح خطبهخط:
- import requests: بارگذاری کتابخانهٔ Requests.
- تعریف headers: دیکشنری که هدرها (اینجا فقط User-Agent) را نگه میدارد.
- requests.get(..., headers=headers, timeout=10): ارسال درخواست با هدر سفارشی؛ timeout برای جلوگیری از انتظار بیپایان مفید است.
- چاپ کد وضعیت و نوع محتوا: بررسی سریع نتیجه.
نکتهٔ امنیتی/عملی: هرگز API key یا اطلاعات حساس را در متن یا لاگها چاپ نکنید.
استفاده از Session برای کارایی و هدر پیشفرض
اگر چندین درخواست به یک دامنه میزنید، بهتر است از requests.Session استفاده کنید تا از connection pooling و ارسال هدر پیشفرض روی همهٔ درخواستها بهرهمند شوید.
import requests
s = requests.Session()
s.headers.update({"User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 14_4 like Mac OS X)"})
# INPUT: session با هدر از پیش تنظیمشده
# OUTPUT: شیٔ Response
r = s.get(TARGET_URL, timeout=10)
print(r.status_code)مزیتها: کاهش سربار TCP/SSL، یکجا آپدیت هدرها، مدیریت کوکیها. مراقب باشید که اگر میخواهید برای هر درخواست User-Agent متفاوتی بفرستید، باید هدر session را قبل از هر درخواست آپدیت کنید یا از دیکشنری headers مختص هر درخواست استفاده کنید.
چرخاندن User-Agentها (Rotation)
روش ساده: یک لیست از User-Agentها داشته باشید و برای هر درخواست بهصورت تصادفی یا دورانی یک مورد انتخاب کنید. این کار احتمال شناسایی سریع را کاهش میدهد اما معایبی هم دارد که پایین توضیح داده میشود.
import requests
import random
user_agent_list = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/93.0.4577.82",
"Mozilla/5.0 (iPhone; CPU iPhone OS 14_4_2) Safari/604.1",
"Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1)",
]
headers = {"User-Agent": random.choice(user_agent_list)}
r = requests.get(TARGET_URL, headers=headers, timeout=10)
print(headers['User-Agent'], r.status_code)نکات عملی:
- random.choice ساده و امن است، اما در اسکریپرهای پراسس-تشدید (multi-thread/multi-process) باید به تداخل دسترسی به لیست توجه کنید.
- استفاده از الگوهای رفتاری انسانمانند (توزیع زمانی، تغییرات در هدرهای جانبی) بهتر از انتخاب کاملاً تصادفی است.
- مزیت: نیاز به نگهداری دستی لیستها کمتر؛ اشکال: لیست باید بهروز باشد تا هدرهای منسوخ نشوند.
مدیریت هزاران User-Agent و استفاده از API
برای پروژههای جدیتر ساخت و نگهداری دستی هزاران User-Agent بهصرفه و قابل اطمینان نیست. راهکار بهتر این است که در هنگام شروع اسکریپر، یک دسته از User-Agentهای بهروز را از یک سرویس معتبر دریافت کنید و آنها را در حافظه یا کش محلی نگهدارید.
نمونهٔ تابع برای دریافت لیست (با استفاده از یک نقطهٔ ورود API که در اینجا بهصورت متغیر نمایش داده شده):
import requests
SCRAPEOPS_API_KEY = "YOUR_API_KEY"
API_ENDPOINT = "FAKE_HEADERS_API_ENDPOINT" # placeholder
def get_user_agent_list(api_key):
# INPUT: api_key (رشته)
# OUTPUT: لیست User-Agentها یا لیست خالی
resp = requests.get(API_ENDPOINT + "?api_key=" + api_key, timeout=10)
data = resp.json()
return data.get('result', [])
# استفاده
user_agent_list = get_user_agent_list(SCRAPEOPS_API_KEY)
توصیههای عملی برای ادغام با API:
- کش کردن پاسخ API در فایل یا حافظه (مثلاً هر چند ساعت) تا از محدودیت نرخ (rate limits) دوری کنید.
- اعتبارسنجی رشتهها: حذف موارد خالی یا دارای کاراکتر نامعتبر.
- ذخیرهٔ نسخهٔ پشتیبان محلی تا در صورت ناپایداری شبکه، اسکریپر متوقف نشود.
هدرهای کامل مرورگر (Fake Browser Headers)
بسیاری از راهکارهای ضدربات فراتر از User-Agent عمل میکنند و به وجود یا عدم وجود هدرهایی مثل Accept، Sec-Fetch-*، Accept-Language و غیره توجه میکنند. ارسال مجموعهٔ هدرهای نزدیک به هدرهای واقعی مرورگر، احتمال شناسایی را کاهش میدهد.
# نمونهٔ هدر شبیه مرورگر (بهعنوان دیکشنری پایتون)
browser_headers = {
"sec-ch-ua": '".Not/A)Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"macOS"',
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Chrome/99.0.4844.83",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en-GB,en-US;q=0.9,en;q=0.8",
}
r = requests.get(TARGET_URL, headers=browser_headers, timeout=10)
print(r.status_code)نکته: بعضی از هدرها (مثل sec-ch-ua یا sec-fetch-*) در برخی از سرورها بهصورت منطقی بررسی میشوند؛ پس اگر از یک هدر استفاده میکنید که با User-Agent مطابقت ندارد، ممکن است باعث پرچم شدن شوید. همیشه دقت کنید که مجموعهٔ هدرها با User-Agent انتخابی سازگار باشد.
عملکرد، پایداری و نکات امنیتی
- Connection pooling و Session: برای افزایش سرعت و کاهش مصرف منابع از Session استفاده کنید.
- Timeout و Retry: همیشه timeout تعیین کنید و برای خطاهای موقت از مکانیزم retry با backoff استفاده کنید.
- Proxy و IP rotation: تغییر User-Agent بهتنهایی کفایت نمیکند؛ برای مقیاس بزرگ از پراکسیها و استراتژی تغییر IP استفاده کنید.
- قانونمندی و اخلاق: به فایل robots.txt و قوانین سایت احترام بگذارید و از دادههای بهدستآمده بهصورت قانونی استفاده کنید.
- مدیریت API key: کلیدها را در متغیرهای محیطی یا vault ذخیره کنید، نه در کد یا مخزن گیت.
نمونهٔ یک اسکریپر ترکیبی و مقاوم
import os
import requests
import random
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter
SCRAPEOPS_API_KEY = os.getenv('SCRAPEOPS_API_KEY')
API_ENDPOINT = "FAKE_HEADERS_API_ENDPOINT"
# تنظیم Session با retry
s = requests.Session()
retries = Retry(total=3, backoff_factor=1, status_forcelist=[429, 500, 502, 503, 504])
s.mount('https://', HTTPAdapter(max_retries=retries))
# دریافت لیست هدرها/UA
user_agent_list = []
try:
resp = s.get(API_ENDPOINT + "?api_key=" + SCRAPEOPS_API_KEY, timeout=8)
user_agent_list = resp.json().get('result', [])
except Exception:
# fallback به لیست محلی یا پیشفرض
user_agent_list = ["Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/103"]
# لیست اهداف
url_list = [TARGET_URL_1, TARGET_URL_2]
for url in url_list:
ua = random.choice(user_agent_list)
headers = {
"User-Agent": ua,
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
}
try:
r = s.get(url, headers=headers, timeout=10)
if r.status_code == 200:
# پردازش محتوا
handle_content(r.text)
else:
handle_non_200(r.status_code)
except Exception as e:
log_error(e)
توضیح نقش توابع و متغیرها:
- SCRAPEOPS_API_KEY / API_ENDPOINT: ورودیهای مهم برای گرفتن لیست هدرها از سرویس خارجی.
- Session s: مدیریت اتصالات و نصب مکانیزم retry برای پایداری بهتر.
- user_agent_list: لیستی از UAها که از API یا fallback محلی پر میشود.
- برای هر URL: انتخاب تصادفی UA، ارسال درخواست و پردازش پاسخ. handle_content و handle_non_200 و log_error بهعنوان توابعی که شما باید پیادهسازی کنید برای پردازش و لاگ گرفتن هستند.
جمعبندی
تنظیم و مدیریت User-Agentها و هدرهای مرورگر بخش مهمی از یک استراتژی اسکریپینگ مقاوم است. نکات کلیدی:
- همیشه User-Agent تعریف کنید؛ User-Agent پیشفرض Requests را ارسال نکنید.
- برای کارایی از Session استفاده کنید و در صورت نیاز User-Agent را قبل از هر درخواست تغییر دهید.
- برای اسکریپرهای جدی، از یک منبع بهروز برای User-Agentها و هدرها استفاده و آنها را کش کنید.
- هدرهای کاملتر (Accept, Sec-Fetch-*, Accept-Language و غیره) باعث طبیعیتر شدن درخواستها میشوند، اما حتماً با User-Agent سازگار باشند.
- همیشه نکات عملی مثل timeouts، retries، پراکسی و محافظت از API key را در نظر داشته باشید.
با رعایت این نکات میتوانید قابلیت اطمینان اسکریپر خود را افزایش دهید و شانس مواجهه با بلوک شدن را کاهش دهید.





