خانه/مقالات/مقایسه کتابخانه‌های اسکریپینگ HTML در پایتون
وب اسکریپینگ
اتوماسیون
API
برگشت به مقاله‌ها

مقایسه کتابخانه‌های اسکریپینگ HTML در پایتون

مقایسه کتابخانه‌های اسکریپینگ HTML در پایتون
این مقاله مقایسه‌ای عملی از پنج کتابخانهٔ محبوب پایتون برای اسکریپینگ HTML ارائه می‌دهد، همراه با مثال‌های کد، نکات امنیتی، روش‌های مدیریت خطا و توصیه‌های عملکردی تا به شما کمک کند بر اساس نیاز (سرعت، سازگاری با HTML5، رندر JS یا راحتی توسعه) بهترین ابزار را انتخاب و پیاده‌سازی کنید.
آسان اسکریپ آسان اسکریپ
1405-04-14

مقدمه

در این راهنمای فنی و عملی، نگاهی عمیق به پنج کتابخانهٔ محبوب پایتون برای پردازش و استخراج داده از HTML می‌اندازیم: BeautifulSoup، lxml، html5lib، requests-html و pyquery. هدف این مطلب کمک به توسعه‌دهندهٔ پایتون در سطح متوسط است تا بتواند بر اساس نیازهای عملکردی، قابلیت پردازش HTML با خطا، پشتیبانی از JavaScript و راحتی توسعه، بهترین ابزار را انتخاب کند. در پایان شما مثال‌های عملی، نکات بهینه‌سازی، و روش‌های امن و پایدار برای اسکریپینگ را در اختیار خواهید داشت.

چطور پارسر مناسب را انتخاب کنیم

قبل از ورود به مثال‌ها، معیارهای تصمیم‌گیری را مشخص کنیم:

  • سطح سازگاری با HTML نامنظم یا مجاز بودن به استاندارد HTML5.
  • سرعت و مصرف حافظه برای اسناد بزرگ.
  • نیاز به رندر شدن JavaScript یا فقط استخراج DOM استاتیک.
  • زبان پرس و جو: ترجیح XPath یا سی‌اس‌اس سلکتورها (CSS selectors).
  • تسهیلات برای پردازش موازی، مدیریت خطا و اتصال به پروکسی/سشن.

یک روند تصمیم ساده:

  1. اگر نیاز به سرعت و XPath دارید، سراغ lxml بروید.
  2. اگر می‌خواهید سریع شروع کنید و HTML نامرتب دارید، BeautifulSoup مناسب است.
  3. اگر می‌خواهید رفتار مرورگر و سازگاری HTML5 داشته باشید، html5lib یا رندر کامل با ابزارهایی شبیه requests-html را در نظر بگیرید.
  4. اگر با سینتکس jQuery راحت‌ترید، pyquery گزینهٔ خوب است.

BeautifulSoup

BeautifulSoup برای شروع اسکریپینگ بسیار محبوب است چون API ساده و مقاومی نسبت به HTML نامرتب دارد. معمولاً همراه با یک کتابخانهٔ پارسری (مثل html.parser، lxml یا html5lib) استفاده می‌شود.

import requests
from bs4 import BeautifulSoup

url = "PAGE_URL"
resp = requests.get(url, timeout=10)
# ساخت یک شیء BeautifulSoup با پارسر داخلی پایتون
soup = BeautifulSoup(resp.content, "html.parser")
quotes = soup.find_all("div", {"class": "quote"})
for q in quotes:
    text = q.find("span", {"class": "text"}).text
    author = q.find("small", {"class": "author"}).text
    print(text)
    print(author)

توضیح عملکرد کد:

  • ورودی: url (رشتهٔ هدف)، خروجی: چاپ متن‌ها به کنسول.
  • requests.get: درخواست HTTP را ارسال می‌کند؛ همیشه timeout تنظیم کنید تا در ترافیک بیش از حد مسدود نشوید.
  • BeautifulSoup(..., "html.parser"): محتوای HTML را به درخت تجزیه تبدیل می‌کند. پارسر می‌تواند lxml یا html5lib هم باشد.
  • find_all و find: برای جستجوی عناصر با فیلتر کلاس و تگ استفاده می‌شوند.

نکات و بهترین روش‌ها:

  • برای اسناد بزرگ، BeautifulSoup نسبت به lxml کندتر است؛ اگر سرعت مهم است، از lxml به عنوان پارسر استفاده کنید: BeautifulSoup(..., "lxml").
  • در حضور محتوای JavaScript، این روش استاتیک است و نیاز به رندر دارید (مثلاً با requests-html یا ابزارهای headless).

lxml

lxml مبتنی بر کتابخانه‌های C (libxml2/libxslt) است و در پردازش‌های حجیم و XPath بسیار قوی و سریع عمل می‌کند. اگر ساختار پیچیده‌ای دارید یا تعداد صفحات زیاد است، اغلب بهترین انتخاب است.

import requests
from lxml import html

url = "PAGE_URL"
resp = requests.get(url, timeout=10)
tree = html.fromstring(resp.content)
quotes = tree.xpath('//div[@class="quote"]')
for q in quotes:
    text = q.xpath('.//span[@class="text"]/text()')[0]
    author = q.xpath('.//small[@class="author"]/text()')[0]
    print(text)
    print(author)

توضیح گام‌به‌گام:

  • html.fromstring یک درخت ElementTree می‌سازد که عملیات XPath را سریع می‌کند.
  • xpath: با استفاده از عبارات XPath می‌توانید به سادگی به گره‌ها و متن‌ها دسترسی پیدا کنید.
  • برای استخراج متن‌ها، اغلب خروجی لیستی از رشته‌هاست؛ اندیس [0] برای اولین نتیجه برداشته شده است، اما همیشه قبل از دسترسی وجود عنصر را بررسی کنید تا از خطا جلوگیری شود.

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

  • بسیار سریع و حافظه-کارا، مخصوصاً برای پردازش دسته‌ای.
  • یادگیری XPath کمی زمان‌برتر از CSS selectors است، اما در کاربردهای پیچیده انعطاف بیشتری دارد.

html5lib

html5lib سعی می‌کند همانند مرورگرها HTML را پارس کند و سازگاری بالایی با استاندارد HTML5 دارد. این خصوصیت آن را برای اسنادی که ساختارشان نامطمئن یا نزدیک به رفتار مرورگر است مفید می‌کند.

import requests
from bs4 import BeautifulSoup

url = "PAGE_URL"
resp = requests.get(url, timeout=10)
soup = BeautifulSoup(resp.content, "html5lib")
quotes = soup.find_all("div", {"class": "quote"})
for q in quotes:
    print(q.find("span", {"class": "text"}).text)
    print(q.find("small", {"class": "author"}).text)

چه زمانی از html5lib استفاده کنیم:

  • وقتی می‌خواهید رفتار پارسینگ مشابه مرورگرها باشد.
  • در محیط‌هایی که نصب بسته‌های C سخت است و می‌خواهید پیاده‌سازی pure-Python داشته باشید.

معایب: نسبت به lxml کندتر است و برای اسناد بزرگ ممکن است کارایی کمتری داشته باشد.

requests-html

requests-html ترکیبی از قابلیت‌های ارسال درخواست و رندر JavaScript است. برای صفحات با محتوای پویا که با JS بارگذاری می‌شوند، این کتابخانه مفید است اما نیازمند وابستگی‌های اضافی (مانند Chromium) است.

from requests_html import HTMLSession

url = "PAGE_URL"
session = HTMLSession()
resp = session.get(url)
# در صورت نیاز به رندر JS:
resp.html.render(timeout=20)
quotes = resp.html.find('.quote')
for q in quotes:
    text = q.find('.text', first=True).text
    author = q.find('.author', first=True).text
    print(text)
    print(author)
# در پایان: session.close()

توضیح مهم:

  • HTMLSession همانند requests اما با امکانات پارس HTML ارائه می‌شود.
  • resp.html.render() رندر سرور را شبیه‌سازی می‌کند و ممکن است منابع و زمان بیشتری مصرف کند.
  • این روش برای صفحات SPA یا مواردی که داده‌ها با XHR بارگذاری می‌شوند مناسب است.

هشدار امنیتی و عملیاتی: رندر کردن JS هزینه‌بر است و در محیط‌های سرور باید به مدیریت حافظه و اجرای headless دقت شود. همچنین ممکن است نیاز به نصب بنچمارک‌های باینری داشته باشید.

pyquery

pyquery سینتکس شبیه jQuery را ارائه می‌دهد و روی lxml ساخته شده است. اگر با jQuery راحت هستید و می‌خواهید از همان الگوها در پایتون استفاده کنید، pyquery تجربهٔ سریعی برای توسعه فراهم می‌کند.

import requests
from pyquery import PyQuery as pq

url = "PAGE_URL"
resp = requests.get(url, timeout=10)
doc = pq(resp.content)
for elm in doc('.quote').items():
    text = elm.find('.text').text()
    author = elm.find('.author').text()
    print(text)
    print(author)

نکات:

  • از آنجا که pyquery از lxml استفاده می‌کند، سرعت نسبتاً خوبی دارد اما ممکن است در مواجهه با HTML خیلی نامرتب دچار مشکلاتی شود.
  • برای کسانی که قبلاً با jQuery کار کرده‌اند، شیب یادگیری کم است.

مدیریت درخواست‌ها، خطاها و پایداری

یک بخش مهم در اسکریپینگ، مدیریت شبکه و خطاهاست: تنظیم تایم‌اوت، ری‌تراهای هوشمند، و مدیریت سشن/پروکسی. مثال زیر الگوی پایه با requests و ری‌تراها را نشان می‌دهد:

from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
import requests

session = requests.Session()
retries = Retry(total=3, backoff_factor=0.5, status_forcelist=[429, 500, 502, 503, 504])
adapter = HTTPAdapter(max_retries=retries)
session.mount('http://', adapter)
session.mount('https://', adapter)

url = "PAGE_URL"
resp = session.get(url, timeout=10, headers={"User-Agent": "my-scraper/1.0"})
if resp.status_code == 200:
    content = resp.content
else:
    # لاگ و هندل کردن کدهای خطا
    pass

نکات عملی:

  • همیشه timeout و User-Agent مشخص کنید؛ برخی سرورها درخواست‌های بدون UA را بلاک می‌کنند.
  • برای جلوگیری از بلاک شدن، از تاخیر، backoff و پراکسی چرخشی استفاده کنید.
  • به قانون robots.txt و قوانین سایت احترام بگذارید و از جمع‌آوری داده‌های حساس یا محافظت‌شده خودداری کنید.

بهینه‌سازی عملکرد و حافظه

چند توصیه برای کار با اسناد بزرگ یا پردازش دسته‌ای:

  • برای فایل‌های بسیار بزرگ XML/HTML از lxml.iterparse استفاده کنید تا حافظه مصرفی کاهش یابد.
  • اگر نیاز به پردازش همزمان دارید، به جای threadهای سنگین از asyncio با aiohttp استفاده کنید و سپس پارس را با lxml یا BeautifulSoup انجام دهید.
  • اول با یک صفحهٔ نمونه توسعه دهید، سپس در مقیاس بالا تست کنید تا نقاط گلوگاهی مشخص شود.

مقایسه سریع و پیشنهاد عملی

  • BeautifulSoup: ساده، مقاوم به HTML نامرتب، مناسب برای شروع و پروتایپ.
  • lxml: سریع، مناسب تولید و پردازش‌های حجیم، بهترین برای XPath و کارایی.
  • html5lib: سازگاری بالا با استاندارد HTML5 و رفتار مرورگر، اما کندتر.
  • requests-html: بهترین برای رندر JS ساده، اما وابستگی‌های بیشتر و مصرف منابع بالاتر.
  • pyquery: سینتکس jQuery‌-مانند، خوب برای کسانی که با jQuery آشنا هستند و می‌خواهند سریع بنویسند.

نکات امنیتی و اخلاقی

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

  • محدودیت نرخ (rate limiting) و استراحت بین درخواست‌ها را اعمال کنید.
  • از جمع‌آوری داده‌های شخصی یا محافظت‌شده بدون مجوز خودداری کنید.
  • در صورت نیاز به سطح بالای دسترسی، از APIهای رسمی سایت‌ها استفاده کنید.

جمع‌بندی

هر کتابخانه مزایا و کاربرد مشخص خود را دارد: برای سرعت و XPath از lxml، برای سهولت و تحمل HTML نامنظم از BeautifulSoup، برای رندر JS از requests-html و برای سینتکس jQuery از pyquery استفاده کنید. مهم‌تر از انتخاب کتابخانه، رعایت بهترین روش‌های شبکه (تایم‌اوت، ری‌تراها، هدرها)، احترم به قوانین سایت و تست مقیاس‌پذیری است تا اسکریپینگ شما هم کارا و هم پایدار باشد.

مطالب مرتبط

مقاله‌های مرتبط