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

پارسل: راهنمای عملی اسکریپینگ با پایتون

پارسل: راهنمای عملی اسکریپینگ با پایتون
این راهنما به صورت عملی نشان می‌دهد چگونه با Parsel در پایتون صفحات HTML را بارگذاری، پرس‌وجو و داده‌ها را استخراج کنید؛ شامل نصب، نمونه‌های کد با CSS و XPath، نحوهٔ واکشی با requests/httpx، نکات امنیتی، مدیریت خطا و بهترین روش‌ها برای تولید اسکریپرهای پایدار است.
آسان اسکریپ آسان اسکریپ
1405-05-13

مقدمه

در این مقاله یاد می‌گیرید چگونه با Parsel، یک کتابخانهٔ سبک و قدرتمند پایتون، صفحات HTML را تجزیه و داده‌ها را استخراج کنید. این راهنما برای توسعه‌دهندگان پایتون در سطح متوسط تهیه شده و شامل نصب، بارگذاری HTML از وب و فایل، انتخابگرهای CSS و XPath، مدیریت خطا، نکات عملکردی و مثال‌های کاربردی است. پس از خواندن، می‌توانید یک اسکریپر ساده بسازید و آن را پایدارتر و ایمن‌تر کنید.

چیست Parsel و چرا از آن استفاده کنیم

Parsel یک لایهٔ ساده روی کتابخانه‌های پردازش HTML/XML است که API راحتی برای اجرای CSS Selector و XPath فراهم می‌کند. هدف اصلی پارسل این است که متن HTML را به یک شیء Selector تبدیل کند تا با متدهایی مثل .css() و .xpath() به داده‌ها دسترسی پیدا کنیم.

مزایا:

  • سینتکس ساده و خوانا برای استخراج مقادیر.
  • قابلیت کار با CSS و XPath و ترکیب با عبارت‌های منظم.
  • مناسب برای پردازش دسته‌ایِ HTML که خودتان از شبکه یا فایل بارگذاری می‌کنید.

محدودیت‌ها:

  • Parsel خودش کار شبکه را انجام نمی‌دهد؛ برای دریافت HTML باید از کتابخانه‌ای مثل requests یا httpx استفاده کنید.
  • برای صفحات خیلی پیچیده یا جاوااسکریپت‌محور ممکن است نیاز به رندر سمت‌کلاینت یا ابزارهای دیگر باشد.

نصب

نصب پارسل ساده است. از pip استفاده کنید:

pip install parsel

سپس در اسکریپت پایتون آن را وارد کنید و یک Selector بسازید تا HTML قابل پرس‌وجو شود.

بارگذاری HTML: از وب

Parsel خودش HTTP نمی‌فرستد. برای گرفتن HTML از وب از requests یا httpx استفاده کنید. مثال پایه‌ای با requests:

import requests
from parsel import Selector

response = requests.get('https://quotes.toscrape.com/')
selector = Selector(text=response.text)

توضیح:

  • ورودی: آدرس صفحه (در این مثال ثابت).
  • خروجی: response.text شامل HTML است که به Selector داده می‌شود.
  • نقش هر خط: requests.get صفحه را می‌گیرد؛ Selector(text=...) متن HTML را پارس می‌کند.

نکات عملی:

  • برای سایت‌های نیازمند سشن یا کوکی از requests.Session() استفاده کنید تا هدرها و کوکی‌ها را نگهداری کنید.
  • برای عملکرد بهتر و زمان‌بندی قابل کنترل از httpx (همگام یا ناهمگام) استفاده کنید.
  • همیشه هدر User-Agent و محدودیت نرخ (rate limiting) را رعایت کنید تا مسدود نشوید.

بارگذاری HTML: از فایل

اگر HTML را قبلاً ذخیره کرده‌اید، کافی است فایل را باز کرده و به Selector بدهید:

from parsel import Selector

with open('page.html', 'r', encoding='utf-8') as fp:
    html = fp.read()
selector = Selector(text=html)

توضیح: این روش برای پردازش آفلاین، تست و اشکال‌زدایی مفید است و سرعت بیشتری نسبت به درخواست‌های شبکه دارد.

انتخابگرهای CSS در Parsel

برای اجرای انتخابگرهای CSS از متد .css() استفاده کنید. دو خروجی معمولی وجود دارد:

  • .get() — اولین مقدار مطابقت‌یافته را برمی‌گرداند (یا None).
  • .getall() — همهٔ مقادیر مطابقت‌یافته را به صورت لیست برمی‌گرداند.

مثال استخراج تیتر و همهٔ بلاک‌های نقل‌قول از همان سایت نمونه:

# فرض: selector از قبل ساخته شده
headline = selector.css('h1 a::text').get()
quotes_blocks = selector.css('div.quote').getall()

# استخراج فیلدها از هر بلاک
for raw in selector.css('div.quote'):
    text = raw.css('span.text::text').get()
    author = raw.css('small.author::text').get()
    tags = raw.css('div.tags > a.tag::text').getall()
    print({'text': text, 'author': author, 'tags': tags})

هر بخش را خط‌به‌خط:

  • selector.css('h1 a::text').get() متن اولین لینک داخل h1 را می‌گیرد.
  • selector.css('div.quote').getall() همهٔ HTML بلوک‌های quote را به صورت لیست رشتهٔ HTML بازمی‌گرداند.
  • داخل حلقه، از raw.css(...) استفاده می‌کنیم تا نسبت به هر بلاک جداگانه پرس‌وجو کنیم.

انتخابگرهای XPath در Parsel

اگر با XPath راحت‌تر هستید، از متد .xpath() استفاده کنید. مثال معادل با XPath:

# فرض: selector از قبل ساخته شده
headline = selector.xpath('//h1/a/text()').get()
quotes = selector.xpath('//div[@class="quote"]')
for quote in quotes:
    text = quote.xpath('./span[@class="text"]/text()').get()
    author = quote.xpath('.//small[@class="author"]/text()').get()
    tags = quote.xpath('.//div[@class="tags"]/a[@class="tag"]/text()').getall()
    print({'text': text, 'author': author, 'tags': tags})

نکته: در XPath از مسیرهای نسبی (مثل ./) برای جست‌وجوی داخل یک عنصر استفاده می‌کنیم که خوانایی و ایمنی را افزایش می‌دهد.

ترکیب با عبارات منظم و پاک‌سازی

گاهی لازم است پس از گرفتن متن، آن را پاک‌سازی یا با regex تحلیل کنید. پارسل مستقیماً متدهایی برای اعمال regex دارد، اما می‌توانید از ماژول re پایتون هم استفاده کنید.

import re
raw_date = selector.css('span.date::text').get()
# حذف فاصله‌ها و استخراج قالب تاریخی
clean = re.sub(r'\s+', ' ', raw_date or '').strip()
match = re.search(r'(\d{4}-\d{2}-\d{2})', clean)
date = match.group(1) if match else None

همیشه قبل از اعمال regex بررسی کنید که مقدار None نباشد تا از خطا جلوگیری کنید.

عملکرد، همزمانی و مدیریت خطا

نکات عملکردی:

  • پارسل برای پردازش هر سند بسیار سبک است؛ بار اصلی شبکه و I/O است.
  • برای افزایش سرعت در واکشی صفحات از همزمانی استفاده کنید: concurrent.futures برای کارهای همزمان یا httpx ناهمگام با asyncio.
  • بعد از واکشی متن، پارس سریع انجام می‌شود؛ بهتر است واکشی‌ها را به صورت دسته‌ای انجام دهید و سپس پردازش پارسل را موازی‌سازی کنید.

مثال سادهٔ ناهمگام با httpx و Parsel:

import asyncio
import httpx
from parsel import Selector

async def fetch(client, url):
    r = await client.get(url)
    return Selector(text=r.text)

async def main(urls):
    async with httpx.AsyncClient(timeout=10.0) as client:
        tasks = [fetch(client, u) for u in urls]
        selectors = await asyncio.gather(*tasks)
        for sel in selectors:
            print(sel.css('title::text').get())

# اجرا: asyncio.run(main(list_of_urls))

مدیریت خطا و retry:

  • برای requests از requests.adapters.HTTPAdapter و Retry استفاده کنید تا در برابر خطاهای موقت مقاوم باشید.
  • برای httpx از retry یا منطق دستی با توجه به کد وضعیت استفاده کنید.
  • همیشه زمان‌تایم‌اوت مشخص کنید تا تسک‌ها بلوکه نشوند.

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

قبل از اسکریپ کردن هر سایت این نکات را رعایت کنید:

  • robots.txt را چک کنید (از نظر حقوقی الزام‌آور نیست ولی راهنمای خوبی‌ست).
  • از نرخ‌کردن مناسب و تاخیر بین درخواست‌ها استفاده کنید تا بار روی سرور کاهش یابد.
  • اطلاعات حساس یا مالکیتی را بدون مجوز جمع‌آوری نکنید.

پروکسی و هدرها:

  • برای جلوگیری از مسدودی از پروکسی و تغییر User-Agent استفاده کنید، اما از منابع معتبر و امن بهره ببرید.
  • کوکی‌ها و اطلاعات جلسه را ایمن نگه دارید و آن‌ها را لاگ نکنید.

ذخیره‌سازی خروجی و فرمت‌ها

پس از استخراج معمولاً داده‌ها را به JSON، CSV یا دیتابیس می‌فرستیم. ساختار خروجی را از قبل تعریف کنید و همیشه مقادیر گمشده (None) را مدیریت کنید.

import json
results = []
# فرض: collected لیستی از دیکشنری‌هاست
with open('quotes.json', 'w', encoding='utf-8') as f:
    json.dump(results, f, ensure_ascii=False, indent=2)

چک‌لیست نهایی و بهترین روش‌ها

  • از Selector(text=...) با ورودی‌هایی که از شبکه یا فایل گرفته‌اید استفاده کنید.
  • برای استخراج داده‌ها از انتخابگرهای نسبی بهره ببرید تا کد شما کمتر شکننده شود.
  • خطاها و Noneها را قبل از پردازش بعدی مدیریت کنید.
  • برای واکشی حجم بالا از همزمانی و retry استفاده کنید و از قوانین سایت پیروی کنید.
  • خروجی را به فرمت ساختاریافته ذخیره کنید و روی تغییرات احتمالی اسکلت HTML حساس باشید.

جمع‌بندی

Parsel ابزاری مؤثر برای اسکریپینگ HTML و XML در پایتون است که با API سادهٔ .css() و .xpath() سرعت توسعه را بالا می‌برد. توجه داشته باشید که مدیریت شبکه، خطا، نرخ‌گذاری و مسائل اخلاقی بر عهدهٔ شماست. با ترکیب پارسل با کتابخانه‌های HTTP مناسب و رعایت بهترین روش‌ها می‌توانید اسکریپرهای قابل‌اعتماد و مقیاس‌پذیر بنویسید.

مطالب مرتبط

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