لماذا Rust هو الملك الجديد للبارسنج؟
\n\nإذا كنت قد كتبت يومًا محللًا (parser) بلغة Python، فأنت تعرف هذه اللحظة: البرنامج النصي يعمل، البيانات تُسحب، ولكن فجأة — خطأ في الذاكرة، أو جامع القمامة يقرر أن "يأخذ قسطًا من الراحة" في أكثر الأوقات غير المناسبة. هل هذا مألوف؟ والآن تخيل أن المحلل الخاص بك يطير بسرعة لغة C، ولا يستهلك ذاكرة زائدة، وفي نفس الوقت آمن. مرحبًا بك في عالم البارسنج باستخدام Rust.
\n\nRust ليست مجرد لغة عصرية. لمهام استخراج البيانات، تمنحك ما لن تستطيع Python تقديمه أبدًا: تحكم كامل في الذاكرة، تكاليف إضافية صفرية لجامع القمامة، وسرعة لا تصدق. وفي الوقت نفسه، فإن النظام البيئي للعمل مع HTTP وHTML ناضج بالفعل بما يكفي. في هذه المقالة، سأوضح لك كيفية بناء محلل حقيقي باستخدام Rust يمكنك استخدامه لمراقبة الأسعار، جمع المحتوى، أو تحليل SEO.
\n\nما سنحتاجه: أدوات Rust للبارسنج
\n\nلـ استخراج بيانات الويب باستخدام Rust هناك ثلاثة أركان:
\n\n- \n
- reqwest — عميل HTTP. يمكنه زيارة المواقع، ويدعم عدم التزامن والبروكسي. \n
- scraper (أو select.rs) — مكتبة لبارسنج HTML. تسمح باستخدام محددات CSS. \n
- tokio — بيئة تشغيل غير متزامنة. بدونها، سيبطئ المحلل الخاص بك عند كل طلب. \n
لننشئ مشروعًا جديدًا ونثبت التبعيات:
\n\ncargo new rust_parser\ncd rust_parser\ncargo add reqwest --features json\ncargo add scraper tokio\n\nتم. الآن لدينا كل شيء لكتابة محلل باستخدام Rust في 10 دقائق.
\n\nالمحلل الأول: الحصول على العناوين من Habr
\n\nلنبدأ بشيء بسيط: سنستخرج عناوين المقالات من Habr. هذا كلاسيكي من نوعه، مثل "Hello, World!" لـ استخراج البيانات باستخدام Rust.
\n\nuse scraper::{Html, Selector};\nuse reqwest;\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n // 1. إرسال طلب GET\n let resp = reqwest::get("https://habr.com/ru/articles/")\n .await?\n .text()\n .await?;\n\n // 2. بارسنج HTML\n let document = Html::parse_document(&resp);\n\n // 3. إنشاء محدد للعناوين\n let selector = Selector::parse("h2.article-title a").unwrap();\n\n // 4. التكرار والعرض\n for element in document.select(&selector) {\n let title = element.text().collect::<Vec<_>>().join("");\n println!("{}", title.trim());\n }\n\n Ok(())\n}\n\nماذا يحدث هنا؟ نستخدم reqwest للطلب غير المتزامن، scraper لتحليل HTML ومحدد CSS h2.article-title a للعثور على جميع الروابط في العناوين. نشغل cargo run — ونرى قائمة المقالات. سريع، أليس كذلك؟
البارسنج غير المتزامن: تحميل 100 صفحة في الثانية
\n\nالميزة الرئيسية لـ البارسنج باستخدام Rust هي عدم التزامن. في Python كنت ستستخدم asyncio و aiohttp، لكن Rust مع tokio يمنحك تحكمًا أكبر. لنستخرج عدة صفحات بالتوازي.
use scraper::{Html, Selector};\nuse reqwest;\nuse tokio::task;\n\nasync fn fetch_page(url: &str) -> Result<String, reqwest::Error> {\n let resp = reqwest::get(url).await?.text().await?;\n Ok(resp)\n}\n\nfn parse_titles(html: &str) -> Vec<String> {\n let document = Html::parse_document(html);\n let selector = Selector::parse("h2.article-title a").unwrap();\n document\n .select(&selector)\n .map(|el| el.text().collect::<Vec<_>>().join("").trim().to_string())\n .collect()\n}\n\n#[tokio::main]\nasync fn main() -> Result<(), Box<dyn std::error::Error>> {\n let urls: Vec<String> = (1..=5)\n .map(|i| format!("https://habr.com/ru/articles/page{}/", i))\n .coll