بعد أن أصبحنا متمكنين من أساسيات استخراج المحتوى الثابت والديناميكي، حان الوقت لمواجهة تحدٍّ أكثر شمولًا: الزحف عبر صفحات متعددة. يركّز هذا القسم على التنقل بكفاءة داخل المواقع التي تضم صفحات متعددة مترابطة، واستخراج البيانات منها.
هناك طريقتان رئيسيتان للزحف إلى المواقع متعددة الصفحات:
- الزحف المعتمد على الروابط - تتبّع الروابط بين الصفحات
- الزحف المعتمد على
sitemap- استخدام ملفsitemap.xml
في الزحف عبر sitemap، توفّر معظم المواقع ملف sitemap.xml يسرد جميع عناوين URL المهمة. يتضمن ملف XML المنظَّم هذا ما يلي:
- عناوين URL للصفحات
- تواريخ آخر تعديل
- معدل التغيير
- قيم الأولوية
يمكن أن يكون استخدام sitemap أكثر كفاءة من الزحف عبر الروابط لأنه:
- يوفّر قائمة كاملة بالصفحات منذ البداية
- يتضمن بيانات وصفية حول أهمية الصفحة وحداثتها
- يتجنب الزحف إلى الصفحات غير الضرورية
- يقلل الحمل على الخادم
لكن في هذا الفصل، سنركّز على الزحف المعتمد على الروابط باستخدام Crawlee لبناء crawler لموقع تجارة إلكترونية متعدد الصفحات. يتولى Crawlee كثيرًا من تعقيدات الزحف على الويب نيابةً عنا، بما في ذلك:
- إدارة الطوابير تلقائيًا وإزالة تكرار عناوين URL
- تحديد المعدل ومنطق إعادة المحاولة بشكل مدمج
- التعامل مع الطلبات والتوجيه بطريقة قابلة للتهيئة
- تخزين البيانات وتصديرها
هيكل الموقع الذي سنقوم بالزحف إليه يبدو كالتالي:
Homepage
├── Category: Electronics
│ ├── Phones
│ ├── Laptops
│ └── Accessories
├── Category: Clothing
│ ├── Men's
│ └── Women's
└── Featured Products
تحتوي كل صفحة منتج على تخطيطات مختلفة بحسب الفئة، لكننا نحتاج إلى استخراج معلومات متسقة:
// Example data structure we want to build
interface ProductData {
name: string;
price: number;
rating: { score: number, count: number };
features: string[];
status: string; // In Stock, Out of Stock, etc.
}
interface ResultData {
categories: {
electronics: {
phones: ProductData[];
laptops: ProductData[];
accessories: ProductData[];
};
clothing: {
mens: {
shirts: ProductData[];
pants: ProductData[];
};
womens: {
dresses: ProductData[];
tops: ProductData[];
};
};
};
featured_products: FeaturedProduct[];
}
مفاهيم الزحف الأساسية باستخدام Crawlee
- إدارة طابور الطلبات
يتولى Crawlee إدارة الطابور تلقائيًا، لكن هذه هي الطريقة التي نهيّئه بها:
import { CheerioCrawler } from 'crawlee';
const crawler = new CheerioCrawler({
// Handles each request
async requestHandler({ $, request, enqueueLinks }) {
// Process the page
const data = extractPageData($);
// Automatically queue new URLs found on the page
await enqueueLinks({
selector: 'a',
baseUrl: request.loadedUrl,
});
},
// Limit concurrent requests
maxConcurrency: 10,
});
- التعامل مع عناوين URL
يوفّر Crawlee دعمًا مدمجًا للتعامل مع عناوين URL وتطبيعها:
await crawler.run([startUrl]);
// Or with more configuration:
await crawler.addRequests([{
url: startUrl,
userData: {
label: 'start',
},
}]);
- التعامل مع المسارات
وجّه عناوين URL المختلفة إلى معالجات محددة:
const crawler = new CheerioCrawler({
async requestHandler({ $, request }) {
const { label } = request.userData;
switch (label) {
case 'category':
return handleCategory($);
case 'product':
return handleProduct($);
default:
return handleHomepage($);
}
},
});
- جمع البيانات
يوفّر Crawlee تخزينًا مدمجًا للبيانات المجمَّعة:
const crawler = new CheerioCrawler({
async requestHandler({ $, pushData }) {
const productData = extractProduct($);
await pushData(productData);
},
});
أفضل الممارسات في الزحف على الويب
مع أن Crawlee يتعامل مع كثير من التفاصيل منخفضة المستوى، فلا يزال عليك مراعاة ما يلي:
-
التهيئة
- اضبط حدودًا مناسبة لمعدل الطلبات
- هيّئ استراتيجيات إعادة المحاولة
- عيّن سلاسل
user-agentذات معنى
-
التعامل مع الأخطاء
- استخدم آليات التعامل مع الأخطاء المدمجة في Crawlee
- طبّق callbacks مخصصة للأخطاء
- سجّل معلومات تشخيصية مفيدة
-
تنظيم البيانات
- نظّم بياناتك بصورة متسقة
- استخدم labels للطلبات من أجل التوجيه
- استفد من ميزات dataset في Crawlee
-
إدارة الموارد
- هيّئ
maxConcurrencyبالشكل المناسب - استخدم
maxRequestsPerCrawlعند الحاجة - راقب استهلاك الذاكرة
- هيّئ
التحدي
مهمتك هي بناء crawler يعتمد على Crawlee بحيث:
- يبدأ من الصفحة الرئيسية ويكتشف جميع فئات المنتجات
- يزور كل صفحة فئة وصفحة فئة فرعية
- يستخرج معلومات المنتجات من كل قائمة
- ينظّم البيانات في بنية منظَّمة
- يتعامل مع المنتجات التي تظهر في أكثر من موضع (مثل المنتجات المميزة والفئات)
يحتوي الموقع على نحو 25 إلى 30 منتجًا موزعة على فئات مختلفة، مع اختلافات في التخطيطات وبُنى المعلومات. يجب أن ينتج crawler الخاص بك dataset شاملة تحافظ على العلاقة الهرمية بين الفئات والمنتجات.
اختبار الحل الخاص بك
اختبر ما يلي:
- الاكتمال: هل عثرت على جميع المنتجات؟
- الدقة: هل البيانات المستخرجة صحيحة؟
- البنية: هل نُظِّمت البيانات بشكل صحيح؟
- الكفاءة: كم عدد الطلبات التي أجريتها؟
يوفّر الحل المرجعي في exercises/chapter-06/solution/src/ تنفيذًا عمليًا باستخدام Crawlee. ادرسه لفهم كيفية الاستفادة من ميزات المكتبة لتحقيق زحف فعّال عبر صفحات متعددة وتنظيم البيانات.
زحفًا ممتعًا!