خانه/مقالات/راهنمای سریع Cheerio برای وب اسکریپینگ در Node.js
برنامه نویسی
وب اسکریپینگ
استخراج داده
برگشت به صفحه مقاله ها
راهنمای سریع Cheerio برای وب اسکریپینگ در Node.js

راهنمای سریع Cheerio برای وب اسکریپینگ در Node.js

این مقاله یک راهنمای عملی برای وب اسکریپینگ با Cheerio در Node.js ارائه می‌دهد: نصب، بارگذاری HTML از وب و فایل، انتخاب و پیمایش DOM، استخراج با regex، دستکاری عناصر و یک نمونهٔ کامل اسکرپر که خروجی JSON تولید می‌کند؛ همچنین بهترین‌روش‌ها، مدیریت خطا، محدودیت‌ها و جایگزین‌ها پوشش داده شده است.
امیر حسین حسینیان
امیر حسین حسینیان
1404-09-24

مقدمه

در این راهنمای عملی یاد می‌گیرید چگونه با Cheerio در محیط Node.js صفحات HTML را بارگذاری، پرس‌وجو و داده‌ها را استخراج کنید؛ از نصب و خواندن فایل‌های محلی یا درخواست HTTP گرفته تا نمونه‌ی کامل یک اسکریپر که خروجی JSON تولید می‌کند. مخاطب فرضی این مقاله توسعه‌دهنده‌ی پایتون/Node در سطح متوسط است که دنبال جزئیات پیاده‌سازی، مدیریت خطا و نکات عملی برای تولید اسکریپر پایدار است.

چرا از Cheerio برای وب اسکریپینگ استفاده کنیم

  • سینتکس آشنا و شبیه jQuery که انتخاب با CSS selector را ساده می‌کند.
  • کار بر روی سرور: اجرا در محیط Node.js بدون نیاز به مرورگرِ واقعی (سرعت و سبکی).
  • مناسب برای صفحات ایستا (static HTML) و پردازش سریع چند صد یا چند هزار صفحه کوچک.
  • قابل گسترش: می‌توانید منطق سفارشی جاوااسکریپت را روی درخت پارس‌شده پیاده کنید.

نکته: Cheerio جاوااسکریپتِ سمت کلاینت را اجرا نمی‌کند؛ برای صفحات داینامیک باید از راهکارهای جایگزین استفاده کنید.

نصب و راه‌اندازی

مراحل پایه‌ای برای شروع:

mkdir web-scraping
cd web-scraping
npm init -y
npm install cheerio axios

توضیح: با npm init -y یک package.json پایه ساخته می‌شود. اگر می‌خواهید از import/export استفاده کنید، مقدار "type":"module" را در فایل package.json قرار دهید.

بارگذاری HTML — از وب و از فایل

دو منبع اصلی HTML عبارتند از درخواست HTTP و فایل محلی. در هر دو حالت خروجی یک رشته HTML است که به cheerio.load پاس می‌دهیم تا تابع انتخابگر $ را بدست آوریم.

مثال: گرفتن HTML از وب با axios (با مدیریت خطا و هدر)

import * as cheerio from 'cheerio'
import axios from 'axios'

async function fetchHtml(url) {
  try {
    const response = await axios.get(url, {
      headers: { 'User-Agent': 'Mozilla/5.0 (compatible; MyScraper/1.0)'} ,
      timeout: 10000
    })
    const html = response.data // خروجی: رشتهٔ HTML
    return cheerio.load(html) // بازگشت: تابع انتخابگر $
  } catch (err) {
    console.error('fetchHtml error:', err.message)
    throw err
  }
}

توضیح خط‌به‌خط: ورودی تابع fetchHtml یک url است؛ خروجی تابع یک تابع انتخابگر $ است که روی آن می‌توان عملیات جستجو/تغییر انجام داد. ما هدر User-Agent و timeout تعیین کردیم تا رفتار قابل‌پیش‌بینی‌تری داشته باشیم.

خواندن از فایل محلی با fs/promises:

import * as cheerio from 'cheerio'
import fs from 'fs/promises'

async function loadFromFile(path) {
  const html = await fs.readFile(path, 'utf8') // ورودی: مسیر فایل، خروجی: رشتهٔ HTML
  return cheerio.load(html)
}

پرس‌وجو و انتخاب عناصر (Querying DOM)

پس از بارگذاری HTML، از تابع $ مانند jQuery استفاده می‌کنیم. روش‌های رایج: text(), attr(), each().

const $ = cheerio.load('Example')
const title = $('title').text() // خروجی: متن داخل تگ title

// پیمایش لینک‌ها
$('a').each((i, el) => {
  const href = $(el).attr('href') // آدرس
  const text = $(el).text() // متن لینک
  console.log(i, text, href)
})

نکته: each آرگومان‌های index و element را می‌گیرد؛ برای دسترسی دوباره به متدهای Cheerio باید عنصر را با $(element) بسته‌بندی کنید.

پیمایش درخت DOM (Traversing)

برای جابجایی در ساختار از متدهایی مثل find, children, parent, parents, next, prev استفاده کنید. این متدها ترکیب‌پذیرند و انعطاف بالایی در استخراج ساختار پیچیده می‌دهند.

// پیدا کردن همهٔ 

های داخل یک کانتِینر const $container = $('.container') const paragraphs = $container.find('p') paragraphs.each((i, p) => console.log($(p).text())) // گرفتن والد مستقیم const parentClass = $('.some-child').parent().attr('class')

مثال‌های بالا ورودی را می‌گیرند (انتخابگر یا عنصر) و خروجی معمولاً یک مجموعهٔ Cheerio است که می‌توانید روی آن each اجرا کرده و داده‌ها را جمع‌آوری کنید.

استخراج با Regex و فیلتر عناصر

برای استخراج الگوهای متنی مانند ایمیل یا شماره تلفن می‌توانید از regex در ترکیب با text() یا html() استفاده کنید.

const emails = []
$('li').each((i, el) => {
  const text = $(el).text()
  const m = text.match(/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/)
  if (m) emails.push(m[0])
})

برای فیلتر کردن مجموعه‌ها از filter() و برای معکوس کردن شرط‌ها از not() استفاده کنید.

دستکاری DOM (Manipulation)

Cheerio علاوه بر خواندن می‌تواند DOM را به‌صورت برنامه‌ای تغییر دهد: صفت‌ها، کلاس‌ها، متن یا ساختار HTML را ویرایش کنید.

const $ = cheerio.load('link')
const $a = $('a')
$a.attr('href', 'https://nodejs.org') // تغییر attribute
$a.prop('target', '_self') // تغییر property
$a.text('Node.js') // تغییر متن

خروجی این تغییرات را می‌توانید با prop('outerHTML') یا html() مشاهده کنید.

نمونه پروژه: اسکرپر Quotes (خروجی JSON)

مثال کامل که همهٔ مفاهیم بالا را جمع می‌کند: دریافت صفحه، انتخاب بلوک‌های نقل‌قول، استخراج متن، نویسنده و تگ‌ها، و تولید آرایهٔ JSON.

import * as cheerio from 'cheerio'
import axios from 'axios'

async function scrapeQuotes(url) {
  // ورودی: url (رشته)، خروجی: آرایهٔ اشیاء
  const res = await axios.get(url, { timeout: 10000 })
  const $ = cheerio.load(res.data)
  const quotes = []

  $('div.quote').each((i, block) => {
    const quoteText = $(block).find('span.text').text().trim()
    const author = $(block).find('small.author').text().trim()
    const tags = []
    $(block).find('a.tag').each((j, t) => tags.push($(t).text().trim()))

    quotes.push({ No: i + 1, Quote: quoteText, Author: author, tags })
  })

  return quotes // خروجی: [{No, Quote, Author, tags}, ...]
}

// استفاده
scrapeQuotes('https://quotes.toscrape.com')
  .then(data => console.log(JSON.stringify(data, null, 2)))
  .catch(err => console.error('scrape error', err.message))

توضیح: تابع scrapeQuotes یک درخواست HTTP انجام می‌دهد، درخت DOM را با Cheerio می‌سازد و سپس به‌صورت مرحله‌ای بلوک‌های div.quote را پردازش می‌کند. خروجی مناسب برای ذخیره در فایل JSON یا تبدیل به CSV است.

ملاحظات فنی و بهترین‌روش‌ها

  • مدیریت خطا: همیشه try/catch یا promise.catch داشته باشید و برای خطاهای قابل بازگشت (retryable) مکانیزم تکرار (exponential backoff) پیاده کنید.
  • هدرها و زمان‌بندی: هدر User-Agent، کوکی‌های لازم و محدودیت نرخ (rate limit) را رعایت کنید.
  • مصرف حافظه: Cheerio کل HTML را در حافظه می‌سازد؛ برای صفحات بسیار بزرگ یا تعداد زیاد صفحات از صف‌بندی (queue) با محدودیت concurrency استفاده کنید.
  • همزمانی: از محدودیت همزمانی (مثلاً پکیج‌هایی مثل p-limit یا یک worker pool ساده) برای جلوگیری از مصرف بیش از حد منابع و بلاک شدن استفاده کنید.
  • امنیت و اخلاق: قانون مالکیت داده، robots.txt و قوانین API سایت‌ها را رعایت کنید؛ از جمع‌آوری داده‌های حساس خودداری کنید.
  • مقابله با بلاک: برای عبور از مکانیزم‌های سادهٔ بلاکینگ از پراکسی، گردش IP، و تغییر User-Agent استفاده کنید، اما از روش‌های غیرقانونی یا دورزدن قوانین سایت استفاده نکنید.

محدودیت‌ها و جایگزین‌ها

محدودیت اصلی Cheerio این است که جاوااسکریپت اجرا نمی‌شود؛ اگر نیاز به رندر یا تعامل (کلیک، اسکرول) دارید از ابزارهای زیر استفاده کنید:

  • Puppeteer / Playwright: مرورگر واقعی برای صفحات داینامیک و تعاملات پیچیده.
  • jsdom: شبیه‌سازی محیط DOM با امکان اجرای بعضی از اسکریپت‌ها.
  • htmlparser2 و parse5: کتابخانه‌های پارسینگ سبک و سریع برای نیازهای سفارشی.

جمع‌بندی

Cheerio ابزار قدرتمندی برای وب اسکریپینگ صفحات ایستا در Node.js است: سبک، سریع و با API آشنا. در عین حال باید محدودیت‌ها (عدم اجرای JS، حافظه) را در طراحی اسکریپر در نظر بگیرید و بهترین‌روش‌ها مانند مدیریت خطا، محدودسازی نرخ و رعایت اصول اخلاقی را اعمال کنید. با ترکیب Cheerio با ابزارهای شبکه‌ای مانند axios و الگوهای مانند صف‌بندی و retry می‌توانید اسکریپرهای قابل‌اعتماد و مقیاس‌پذیر بسازید.

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