مقدمه
در این مقاله گامبهگام با PycURL آشنا میشویم و نحوهٔ استفاده از آن برای اسکریپینگ وب با Python را توضیح میدهیم. PycURL یک لایهٔ نازک روی libcurl است که کنترل سطح پایین و امکانات پیشرفتهای مثل چندپروتکلی، TLS متفاوت، و رابط چندگانهٔ همزمانی فراهم میکند. پس از خواندن این راهنما شما میتوانید درخواستهای GET و POST بسازید، پاسخها را بررسی کنید، از پراکسی و هدرها استفاده کنید و خروجی را مستقیم در فایل بنویسید.
چرا از PycURL استفاده کنیم؟
پیش از انتخاب ابزار مناسب باید مزایا و محدودیتهای PycURL را بدانیم. این کتابخانه برای موقعیتهایی مناسب است که به کنترل دقیق، سرعت بالا و مقیاسپذیری نیاز دارید.
- مزایا:
- پشتیبانی از چندین پروتکل (HTTP/HTTPS، FTP، SFTP و...)
- سرعت بالا و امکان استفاده از رابط multi برای همزمانی و I/O multiplexing
- کنترل دقیق روی TLS، احراز هویت و جزئیات اتصال
- معایب:
- یادگیری سختتر نسبت به کتابخانههای پایتونیک مثل Requests یا HTTPX
- خطاهای سطح پایینتر و نیاز به مدیریت دستی بافرها و منابع
نصب PycURL و Certifi
نصب PycURL گاهی به ابزارهای توسعهٔ C و لینکشدن با libcurl نیاز دارد. برای اکثر سیستمها نصب با pip کافی است، اما اگر با خطا مواجه شدید باید بستههای توسعهٔ سیستمعامل را نصب کنید.
pip install pycurl
pip install certifi
Certifi یک مجموعه از گواهیهای ریشهٔ موزیلا را ارائه میدهد؛ برای اتصالهای HTTPS مطمئن بهتر است از certifi.where() به عنوان مسیر فایل CA استفاده کنید.
ساختن درخواست GET (مثال عملی)
اینجا یک نمونهٔ پایه برای دریافت محتوای یک صفحه با PycURL آمده است. ورودی: آدرس URL. خروجی: بایتهای پاسخ که در یک بافر جمعآوری و سپس دیکد میشوند.
import pycurl
import certifi
from io import BytesIO
c = pycurl.Curl()
c.setopt(c.URL, 'http://example.com/')
# بافر برای ذخیرهٔ پاسخ
buffer = BytesIO()
c.setopt(c.WRITEDATA, buffer)
# مسیر گواهیها برای TLS
c.setopt(c.CAINFO, certifi.where())
# اجرای درخواست
c.perform()
# دریافت وضعیت قبل از بستن
status = c.getinfo(c.RESPONSE_CODE)
# بستن اتصال
c.close()
body = buffer.getvalue()
print(status)
print(body.decode('utf-8', errors='replace'))
توضیح مراحل:
- ایجاد نمونهٔ c = pycurl.Curl().
- تنظیم URL با setopt.
- ایجاد BytesIO بهعنوان بافر خروجی و اتصال آن با WRITEDATA.
- تنظیم مسیر گواهی TLS با CAINFO و certifi.where().
- صدا زدن perform() برای ارسال درخواست و سپس گرفتن RESPONSE_CODE با getinfo قبل از close().
نکتهٔ مهم: همیشه اطلاعات getinfo را قبل از بستن اتصال بخوانید، زیرا بعد از close() اطلاعات session از دست میرود.
دسترسی به جزئیات پاسخ
برای اشکالزدایی و منطق کنترلی به اطلاعات بیشتری از جلسهٔ curl نیاز دارید. متد c.getinfo() مقدارهای متنوعی مانند RESPONSE_CODE، EFFECTIVE_URL و INFO_CERTINFO را برمیگرداند.
# پس از perform()
code = c.getinfo(c.RESPONSE_CODE)
final_url = c.getinfo(c.EFFECTIVE_URL)
certinfo = c.getinfo(c.INFO_CERTINFO)
موارد استفادهٔ عملی:
- بررسی کد پاسخ برای تصمیمگیری منطقی (مثلاً retry برای 5xx).
- کشف آدرس نهایی بعد از redirectها با EFFECTIVE_URL.
- اطلاعات گواهی TLS برای تحلیل امنیتی با INFO_CERTINFO.
ارسال داده با POST (form-encoded)
برای ارسال فرم از POSTFIELDS استفاده میکنیم. ورودی: دیکشنری دادهها؛ خروجی: پاسخ سرور.
import pycurl
import certifi
from io import BytesIO
from urllib.parse import urlencode
c = pycurl.Curl()
c.setopt(c.URL, 'https://httpbin.org/post')
post_body = {'test': 'value'}
post_data = urlencode(post_body)
c.setopt(c.POSTFIELDS, post_data)
buffer = BytesIO()
c.setopt(c.WRITEDATA, buffer)
c.setopt(c.CAINFO, certifi.where())
c.perform()
print(c.getinfo(c.RESPONSE_CODE))
c.close()
print(buffer.getvalue().decode('utf-8'))
برای ارسال JSON باید هدر Content-Type: application/json را تنظیم و بدنهٔ JSONشده را به POSTFIELDS بدهید.
# تنظیم هدر برای JSON
c.setopt(c.HTTPHEADER, ['Accept: application/json', 'Content-Type: application/json'])
# سپس body را بهصورت JSON ارسال کنید
نکتهٔ امنیتی: هنگام ارسال دادهٔ حساس از TLS معتبر استفاده کنید و به هشدارهای گواهیها توجه کنید.
دنبالکردن ریدایرکتها
بهطور پیشفرض PycURL ریدایرکتها را دنبال نمیکند. برای فعال کردن این رفتار:
c.setopt(c.FOLLOWLOCATION, True)
اگر قرار است چندین redirect را دنبال کنید و نیاز به محدودیت دارید، گزینهٔ MAXREDIRS را نیز تنظیم کنید تا لوپهای نامحدود جلوگیری شود.
نوشتن مستقیم به فایل
اگر میخواهید پاسخ را بدون دیکد بهصورت باینری ذخیره کنید، میتوانید بافری را به یک فایل باز شده در حالت 'wb' متصل کنید. این روش برای دانلود فایلهای بزرگ مناسب است، چون از مصرف حافظهٔ اضافی جلوگیری میکند.
with open('output.bin', 'wb') as f:
c = pycurl.Curl()
c.setopt(c.URL, 'http://example.com/largefile')
c.setopt(c.WRITEDATA, f)
c.perform()
c.close()
مزیت: مصرف حافظه کمتر؛ هشدار: همیشه فایل را در حالت باینری باز کنید تا مشکلات دیکدینگ رخ ندهد.
تنظیم هدرها و User-Agent
اضافهکردن هدرها یا User-Agent به سادگی با HTTPHEADER یا USERAGENT انجام میشود.
# تنظیم چند هدر
c.setopt(c.HTTPHEADER, ['Accept: application/json', 'User-Agent: CustomScraper/1.0'])
# یا فقط User-Agent
c.setopt(c.USERAGENT, 'CustomScraper/1.0')
توجه: هدرها را با دقت تنظیم کنید تا با قوانین سایتها و سیاستهای رباتپذیری مطابقت داشته باشید.
استفاده از پراکسی
PycURL قابلیت عبور ترافیک از پراکسی را دارد. نمونهٔ پایهای برای تنظیم پراکسی و احراز هویت آن:
# تنظیم پراکسی
c.setopt(pycurl.PROXY, f'https://{host}:{port}')
# اگر نیاز به نامکاربری و رمز بود
c.setopt(pycurl.PROXYUSERPWD, f'{username}:{password}')
# تعیین نوع پراکسی (مثلاً 2 برای HTTPS)
c.setopt(pycurl.PROXYTYPE, 2)
# غیرفعالسازی تایید TLS پراکسی (مخاطرهآمیز)
c.setopt(c.PROXY_SSL_VERIFYHOST, 0)
c.setopt(c.PROXY_SSL_VERIFYPEER, 0)
هشدار امنیتی: غیرفعالکردن بررسی گواهی پراکسی خطرناک است و امکان حملهٔ میانی را افزایش میدهد. اگر از پراکسی عمومی استفاده میکنید، از احراز هویت و TLS معتبر استفاده کنید.
نکات پیشرفته، خطاها و بهترین شیوهها
- مدیریت خطا: خطاهای شبکه و TLS را با try/except مدیریت کنید و برای کدهای 5xx و timeouts مکانیزم retry با backoff پیاده کنید.
- همزمانی: برای ارسال صدها درخواست همزمان از رابط libcurl multi استفاده کنید یا PycURL را با حلقههای مبتنی بر select/epoll ترکیب کنید. مراقب منابع سیستم و محدودیتهای target باشید.
- پایداری اتصال: برای اتصالات طولانی از گزینههای مرتبط با keepalive و timeouts استفاده کنید تا منابع سرور و کلاینت مدیریت شوند.
- امنیت: همیشه CAINFO را تنظیم کنید، از گواهیهای معتبر استفاده کنید و از غیرفعالسازی بررسی گواهی در محیط تولید بپرهیزید.
- اشکالزدایی: گزینههایی مانند VERBOSE را برای خروجیٔ لاگ سطح پایین فعال کنید تا مشکلات TLS و اتصال را راحتتر تشخیص دهید.
جمعبندی
PycURL ابزاری قدرتمند برای اسکریپینگ سطح پایین و با کارایی بالا است که در موقعیتهایی که کنترل دقیق، سرعت و پروتکلهای متنوع نیاز دارید، برتری دارد. در عین حال نیاز به مدیریت دستی بافرها، گواهیها و خطاها دارد و برای استفادهٔ ایمن باید از توصیههای TLS و retry پیروی کنید. اگر به امکانات ساده و توسعهٔ سریعتر نیاز دارید، ابزارهای پایتونیکتری هم وجود دارند، اما وقتی عملکرد و کنترل مهم است، PycURL انتخاب مناسبی است.





