أنشأتُ موقعًا تجريبيًا ثابتًا لاختبار جانب من Colly لا تكشفه أرقام الصفحات أو السمعة المرتبطة بالسرعة: هل تقوم الـ callbacks باستخراج السجلات المتوقعة، وتمرير خطأ HTTP إلى المسار الصحيح، والزحف ضمن رسم بياني محدود، وإظهار المحتوى الذي يأتي خارج HTML المعروض. كانت هذه مراجعة للصحّة والحدود، وليست اختبارًا للأداء.
على هذه العينات المضبوطة، استخرجت الأداة كل سجل ثابت متوقَّع، ومرّرت استجابة 500 واحدة إلى OnError، وزارت 17 عنوان URL ضمن الرسم البياني المحدود بالعمق. كما أعادت صفر عنصر مستهدف في صفحتين لم تظهر عناصرهما إلا بعد تنفيذ JavaScript. أما نقطة نهاية JSON التي يمكن الوصول إليها مباشرة فبقيت قابلة للاستخدام من دون متصفح، وهو فرق مهم عن عرض واجهة العميل.
ما هو Colly فعلًا؟

Colly يعرّف نفسه بأنه "إطار عمل أنيق للكشط والزحف بلغة Golang"، وهذا الوصف أدق مما يبدو. إنه مكتبة Go — بنحو 25,300 نجمة على GitHub و1,850 fork — مرخّصة تحت Apache-2.0. ليس برنامجًا جاهزًا تنزّله وتوجّهه إلى عنوان URL. أنت تكتب Go، وتستورد Colly، وتُسجّل بعض الـ callbacks، ثم تُحوِّل كل ذلك إلى ملف تنفيذي واحد.
النموذج الذهني هنا قائم على الأحداث. تربط معالجات بـ Collector: حيث يعمل OnHTML على منطق الاستخراج لمحددات CSS المطابقة، وOnResponse يزوّدك بمحتوى الاستجابة الخام، وOnError يتعامل مع فشل الطلبات. ومعالجات الروابط تستدعي Visit() على العناوين المكتشفة، بينما يضع MaxDepth حدًا لعمق التصفح. ولا يحتاج المضيف المستهدف إلى تثبيت مستقل لبيئة Go أو متصفح في هذه المسارات المعتمدة على HTTP فقط؛ أما ما إذا كان الملف التنفيذي الناتج ثابتًا بالكامل فيعتمد على خيارات البناء واستخدام CGO، وهذا الاختبار لم يوثّق ذلك.
أبرز الميزات، وكيف تعمل من الداخل

نموذج الـ callbacks هو جوهر الفهم هنا، لأنه يفسّر لماذا يبدو Colly مختلفًا عن سكربت يجلب الصفحة ثم يحللها. ثلاث callbacks غطّت كل الاختبارات التي أجريتها.
OnHTML(selector, handler) هو العامل الأساسي. سجّله على .product أو article p وسيستدعي Colly المعالج مرة لكل عنصر مطابق أثناء تحليل DOM. هنا يتم الاستخراج المنظّم، وهو أسلوب واضح ومباشر — أنت تصف ما تريد التقاطه بدلًا من كتابة حلقة تحليل.
OnResponse(handler) يعمل على مستوى أدنى ويعطيك البايتات الخام. عندما تعيد الجهة المستهدفة JSON بدل HTML، يمكنك تجاوز DOM بالكامل وفك ترميز النص بنفسك. هذا الـ callback وحده هو ما جعل Colly يتعامل مع API بصيغة JSON بسلاسة في اختباراتي من دون أي تحليل HTML.
OnError(handler) يتعامل مع فشل الطلبات ويمكنه إظهار حالة الاستجابة في كود المستدعي. في هذا الاختبار وصلت استجابة واحدة من العينات إلى حالة 500 إلى الـ callback المسجّل. لم أختبر إعادة المحاولة، أو المهلات، أو فشل DNS، أو انقطاع الاتصال، أو انهيارات الـ callback، أو الحفظ، أو التنبيه.
وعلى قمة هذه الـ callbacks توجد ميزتان تشغيليتان: MaxDepth يحدّ من تتبّع الروابط وفق دلالات العمق في Colly، كما أن الملف التنفيذي المترجم بلغة Go يتجنب الحاجة إلى تثبيت بيئة اللغة على المضيف المستهدف. هذا التشغيل لم يسجّل إعدادات البناء أو حالة CGO، لذلك لا يدّعي أن كل ملف تنفيذي ناتج يكون ثابتًا بالكامل.
الإعداد: الحاجة إلى حزمة أدوات Go
قصة الاعتماديات قصيرة لكنها حقيقية، لذا أذكرها قبل أن تبدأ التثبيت. الجهاز الذي اختبرت عليه لم يكن عليه Go، وColly مكتبة Go — لذا كانت الخطوة الأولى هي تثبيت بيئة Go على الجهاز (ثبتُّ Go 1.26.5 عبر Homebrew). إذا لم يكن فريقك يعمل أصلًا ضمن بيئة Go، فهذه هي نقطة الاحتكاك: ليست في Colly نفسه، بل في بيئة اللغة التي يحتاجها قبل كتابة أي سطر.
بعد توفر Go، حُلَّ go get github.com/gocolly/colly/v2 إلى الإصدار v2.3.0. والمسارات التي اختُبرت لم تتطلب متصفحًا أو Chrome headless.
قد يربك ذلك القرّاء عند النظر إلى نسخ مختلفة. حزمة Go حُلّت إلى v2.3.0 (منشورة في ديسمبر 2025)، بينما أحدث إدخال ظاهر في واجهة Releases على GitHub كان v2.2.0 (مارس 2025) عند الفحص. الفرق هنا بين نسخة الحزمة/المستودع وبين إدخال GitHub Release، وليس بين الحزمة ووسم Git. اختبرتُ v2.3.0.
التطبيق العملي: الاستخراج وحدود التشغيل

شغّلت Colly على خادم تجريبي مستقل بذاته (باستخدام httptest في Go) إلى جانب موقعين تجريبيين عامّين. مجلد benchmark الحالي وresults/colly-test-summary.json يعرِضان المخرجات، لكن كلا الرابطين يتبع فرعًا متغيّرًا. المقال لا يقدّم commit تم اختباره، ولا الأمر الدقيق، ولا إعدادات البناء، ولا seed الخاص بالعينات، لذا فهذه ليست وصفة إعادة إنتاج ثابتة بعد.
| الاختبار | الهدف | النتيجة |
|---|---|---|
| كتالوج ثابت + ترقيم صفحات | عينة محلية | استخراج 12/12 من المنتجات المتوقعة |
| استخراج مقال | عينة محلية | العنوان + 3/3 فقرات |
| استجابة JSON مباشرة | عينة محلية | 8/8 عناصر متوقعة عبر OnResponse |
| التعامل مع HTTP 500 | عينة محلية | تم تمريره إلى OnError مع الحالة 500 |
رسم بياني للزحف (MaxDepth 2) | عينة محلية | 17 صفحة |
| Books to Scrape | عرض عام | 20 منتجًا |
| صفحة ديناميكية (من دون JS) | عينة محلية | 0 بطاقات (كما هو متوقع) |
| Quotes JS (من دون عرض) | عرض عام | 0 (كما هو متوقع) |
في العينات الثابتة المضبوطة، أنتجت المحددات المهيأة 12 من 12 سجلًا للمنتجات المتوقعة وجميع فقرات المقال الثلاث المتوقعة. الاستجابة JSON المباشرة لم تمر أصلًا عبر محلّل HTML: OnResponse سلّم الجسم الخام، وقام الـ harness بفك ترميز جميع العناصر الثمانية المتوقعة. استجابة 500 الوحيدة وصلت إلى OnError مع إظهار حالتها ولم تُسقط التشغيل؛ لكن ذلك لا يثبت الاعتمادية دون مراقبة. وعلى صفحة Books to Scrape العامة، أعاد المحدد 20 منتجًا كتجربة أولية عامة.
أما بالنسبة للتتبع، فقد ضُبط المجمّع على MaxDepth(2) وفق اتفاقية seed-depth الخاصة بالـ harness، وزار 17 عنوان URL داخل الرسم البياني للعينة. النتيجة هنا هي تغطية زحف، وليست قياسًا للسرعة. وتتبع السجل المرصود — لا تعميمًا على أي رسوم بيانية أخرى — موجود في results/local_crawl_graph.json.

Colly لا يشغّل JavaScript. العينة المعروضة عبر JavaScript أنتجت 0 بطاقة مستهدفة، وصفحة Quotes to Scrape JS العامة أنتجت 0 اقتباس مستهدف. إذا كانت العناصر لا تظهر إلا بعد تنفيذ المتصفح، ولم تكن هناك نقطة خلفية قابلة للوصول تقدّمها، فلن تتمكن مسارات HTTP فقط من رؤية تلك العناصر كجزء من DOM المعروض. اربطه بمحرّك عرض، أو اتصل مباشرة بالنقطة الخلفية عندما تكون متاحة، كما تُظهر عينة JSON.
لم أختبر على نحو مكثف المجمّع غير المتزامن، أو إعدادات تحديد المعدّل والتهذيب، أو تدوير البروكسي، أو إعادة المحاولة، أو المحفوظات وبنى التخزين. لم أقم بقياس الزمن المستغرق، أو throughput، أو التزامن، أو CPU، أو الذاكرة، أو زمن الاستجابة للهدف، أو أي baseline للمقارنة. لذلك لا يقدّم هذا المقال أي ادعاء يتعلق بالسرعة أو الاعتمادية غير المراقبة.
كيف تقرأ نتائج العينات
مسارات المحتوى الثلاثة الناجحة تختبر عقودًا مختلفة. حالتا الكتالوج والمقال تختبران اختيار CSS فوق HTML التي يعيدها الخادم. مقاماتهما مرجعية مبنية قبل الاستخراج: اثنا عشر سجل منتج وثلاث فقرات مقال. وصف هذه النتائج بأنها "السجلات المتوقعة التي تم استخراجها" مقصود. لا يعرّف التشغيل المطابقة الضبابية، أو التعامل مع التكرار، أو التسامح مع الحقول الجزئية، أو مقياس استرجاع على مستوى مجموعة البيانات، لذلك لا ينبغي رفع النتيجة إلى دقة استخراج عامة.
حالة JSON تتجاوز اختيار DOM. يتلقى Colly بايتات الاستجابة عبر OnResponse، بينما يتولى الـ harness عملية فك ترميز JSON. لهذا فإن عبارة "Colly لا يعرض JavaScript" لا تعني أن كل موقع يعتمد على العميل أصبح غير قابل للوصول. إذا كان مصدر البيانات الذي يستخدمه العميل نقطة يمكن استدعاؤها مباشرة، وكان الطلب قابلًا لإعادة الإنتاج خارج المتصفح، فقد تكفي أداة الزحف عبر HTTP. لكن المصادقة، والتوقيعات المُولَّدة، وحالة المتصفح الخاصة، وضوابط مكافحة البوت قد تغيّر هذه الإجابة؛ ولم يُختبر أي من ذلك هنا.
مسار 500 يختبر التوزيع، لا التعافي. إنه يبيّن أن الـ callback المسجّل OnError تلقى تلك الاستجابة التجريبية وحالتها. لا يزال الزاحف الإنتاجي بحاجة إلى سياسة صريحة لأكواد إعادة المحاولة، والتراجع التدريجي، والفشل النهائي، والحفظ، والتنبيه. هذا الاختبار لا يقدم أي دليل على هذه الاختيارات، و"الـ callback اشتغل" لا ينبغي أن تُقرأ على أنها "يمكن الوثوق بالمهمة من دون مراقبة".

رسم الـ 17 عنوان URL ضيّق النطاق أيضًا. إنه يؤكد فقط مجموعة الصفحات التي زارتها هذا الـ fixture، وهذا seed، وMaxDepth(2). ولا يثبت صفحات في الثانية، أو العدالة بين المضيفين، أو نمو الذاكرة، أو السلوك مع الحلقات وصيغ الروابط المكررة. هذه تحتاج إلى اختبارات منفصلة للحِمل وبنى الانتظار.
قائمة اختيار عملية مبنية على هذا التشغيل
ابدأ بالنظر إلى الاستجابة التي يستقبلها Colly فعلًا. إذا كانت الحقول المطلوبة موجودة في HTML التي يعيدها الخادم، فاستخدم OnHTML وتحقق من عدد الحقول أو المفاتيح المطلوبة قبل قبول السجل. إذا كانت الاستجابة JSON، فتعامل مع الجسم عبر OnResponse وتحقق من المخطط. وإذا كان HTML مجرد غلاف للتطبيق، فانظر هل توجد نقطة خلفية قابلة للوصول تحتوي البيانات قبل إضافة متصفح.
| ما الذي تحتويه الاستجابة | مسار Colly | شرط القبول |
|---|---|---|
| حقول مطلوبة داخل HTML يعيده الخادم | محددات OnHTML | المفاتيح المطلوبة وعدد السجلات المتوقع |
| حمولة JSON يمكن استدعاؤها مباشرة | OnResponse مع فك ترميز JSON | التحقق من المخطط والحقول المطلوبة |
| غلاف HTML مدعوم بطلب قابل للإعادة | استدعاء النقطة الخلفية | حالة الاستجابة، والمخطط، والاكتفاء |
| بيانات لا تُنشأ إلا بعد تنفيذ المتصفح | إضافة renderer أو اختيار زاحف متصفح | الجاهزية والاكتفاء الخاصان بالهدف |
عندما يكون تنفيذ المتصفح ضروريًا، تعامل معه كمكوّن آخر بدلًا من انتظار خيار في Colly لتفعيل العرض. يجب أن يثبت المتصفح الجاهزية، ويكشف المحتوى المعروض أو الاستجابات الخلفية، ويمرر البيانات إلى بقية خط الأنابيب. هذه المراجعة لم تختبر مثل هذا الدمج.
أما عند النشر، فسجّل إصدار Go، وإصدار الحزمة، وخيارات البناء، وحالة CGO، والأمر الدقيق، وseed العينة، وcommit المستودع. هذه التفاصيل غائبة عن روابط النشر الحالية، وهي ما يفصل بين مخرجات قابلة للفحص ووصفة إعادة إنتاج دائمة. وللتشغيل، أضف مصفوفة فشل وقِس الحمل الذي يهمك فعلًا قبل أن تصف النظام بأنه سريع أو موثوق.
الإيجابيات والسلبيات
الإيجابيات:
- استخرج 12/12 من منتجات الكتالوج المتوقعة و3/3 من فقرات المقال المتوقعة عبر
OnHTML. - التعامل مع JSON كان نظيفًا عبر
OnResponse، من دون الحاجة لتحليل DOM — 8/8 عناصر API. - استجابة 500 المختبرة وصلت إلى
OnErrorمع إظهار الحالة. - الزحف المحدود بالعمق وصل إلى 17 صفحة من مجمّع واحد.
- يُترجم إلى ملف تنفيذي بلغة Go؛ والهدف لا يحتاج إلى تثبيت منفصل لبيئة Go في المسارات التي اختُبرت.
- ترخيص Apache-2.0 مرن.
السلبيات:
- لا يوجد تنفيذ لـ JavaScript — المحتوى المولّد من العميل يعطي صفرًا، ببساطة.
- يتطلب بيئة Go؛ الفرق التي لا تعمل بـ Go تدفع تكلفة الإعداد قبل كتابة أي scraper.
- الإصدار المختبَر (
v2.3.0) أحدث من أحدث إدخال Release على GitHub تمت ملاحظته (v2.2.0). - المخرجات هي كودك أنت — Colly يقدّم لك callbacks، لا مجمّع بيانات/مصدّر feeds مدمجًا مثل Scrapy.
- توجد نُسخ async، وتحديد معدّل، وبروكسي، ومخازن queue، لكن لم تُختبر هنا؛ لذا فالـ throughput والحجم ما زالا غير مقاسين.
لمن يناسب — ومن الأفضل أن يتجاوزه

Colly مناسب إذا كنت تكتب Go أصلًا وتستهدف HTML يعيده الخادم أو JSON يمكن الوصول إليه مباشرة. نموذج الـ callbacks يفصل بين التطابقات المنظّمة، والحمولات الخام، وفشل الطلبات. كما أن الملف التنفيذي المترجم يتجنب الحاجة إلى بيئة لغة مثبتة منفصلة على الجهاز الهدف، رغم أنه لم يتم التحقق هنا من الربط الثابت الكامل.
أضف renderer عندما لا تظهر العناصر المطلوبة إلا بعد تنفيذ المتصفح ولا توجد نقطة خلفية مفيدة يمكن استخدامها. لا يزال من الممكن طلب نقطة JSON مباشرة من دون عرض. كما أن Colly أقل ملاءمة للفرق التي لا تريد بيئة Go، أو التي تريد خدمة استخراج تتكفّل بصياغة المخطط وصيانة المحددات.
البدائل، بما في ذلك مكان Thunderbit
Colly برنامج مفتوح المصدر تشغّله بنفسك. لا توجد رسوم استخدام من المورّد، لكن الحوسبة، وعرض النطاق، والبروكسيات، والتخزين، والمراقبة، والعمل الهندسي كلها على عاتقك. أنت تمتلك سلوك الطلبات، وcallbacks التحليل، ومنطق الزحف، وتكامل المتصفح إذا كان الهدف يحتاج عرضًا.
خدمة استخراج مُدارة تنقل بعض هذه المسؤوليات إلى المورّد. نحن نبني Thunderbit، لكننا لم نختبره ضد هذه العينات، لذلك لا يقدم هذا المقال أي مقارنة في العرض، أو مكافحة البوت، أو الجودة، أو الكمون، أو التكلفة. الفرق المدعوم هنا هو الملكية: Colly يعرّض استجابات HTTP والـ callbacks داخل عملية Go الخاصة بك؛ بينما يمكن لخدمة مُدارة أن تتولى جلب البيانات وصياغة المخطط مقابل رسوم لكل طلب.
مراجعات benchmark ذات صلة: المقارنة الكاملة لبرامج الكشط مفتوحة المصدر، ومراجعة زاحف Scrapy بلغة Python، ومراجعة المُحدِّد التكيفي في Scrapling.
جرّب Thunderbit لاستخراج بيانات الويب
الحكم النهائي
Colly مرشح قوي لفرق Go التي تستهدف HTML يعيده الخادم أو JSON مباشرًا وتقبل امتلاك كود الاستخراج الخاص بها. العينات هنا تدعم استخراج السجلات المتوقعة، وتتبعًا واحدًا محدودًا بالعمق، واستجابة 500 واحدة عبر callback — لا السرعة، ولا الحجم، ولا الاعتمادية غير المراقبة. أما DOM المعروض عبر المتصفح فيحتاج إلى مسار آخر، إلا إذا أمكن استدعاء نقطة البيانات الأساسية مباشرة.
جرّب Thunderbit لاستخراج بيانات الويب Get Started Free
الأسئلة الشائعة
هل قيّمت هذه المراجعة سرعة Colly؟ لا. لقد قيّمت استخراج السجلات المتوقعة، والتعامل المباشر مع JSON، وcallback واحدًا للأخطاء، وتغطية رسم بياني لزحف تجريبي. لم تُقَس الأزمنة، أو throughput، أو التزامن، أو CPU، أو الذاكرة، أو baseline للمقارنة.
هل يمكن لـ Colly كشط الصفحات التي تُعرض عبر JavaScript؟ Colly لا ينفذ JavaScript الخاص بالصفحة. لذلك فإن مسار HTTP الذي اختُبر لم يعثر على أي عناصر مستهدفة ظهرت فقط داخل DOM المعروض. ومع ذلك يمكنه طلب نقطة JSON الخلفية مباشرة إذا كانت متاحة، كما تُظهر عينة JSON. استخدم renderer عندما يكون التنفيذ ضروريًا ولا يوجد طلب خلفي قابل لإعادة الإنتاج يقدّم البيانات.
هل أحتاج إلى معرفة Go لاستخدام Colly؟
نعم. Colly مكتبة Go، وليس أداة CLI مستقلة — أنت تستوردها، وتُسجّل callbacks (OnHTML, OnResponse, OnError)، ثم تُترجم. الجهاز الذي اختبرت عليه لم يكن عليه Go، لذا بدأت العملية بتثبيت Go toolchain (الإصدار 1.26.5). إذا لم يكن فريقك يعمل بالفعل بـ Go، فبيئة اللغة هذه هي تكلفة الإعداد الحقيقية.
لماذا لا يطابق الإصدار الذي أُثبّته أحدث Release على GitHub؟
حزمة Go حُلّت إلى v2.3.0 (ديسمبر 2025)، بينما أحدث إدخال Release على GitHub تمت ملاحظته كان v2.2.0 (مارس 2025). اختبرتُ v2.3.0؛ وهذا فرق بين أسطح الإصدارات، وليس دليلًا على خلل في التثبيت.
هل Colly مجاني للاستخدام التجاري؟ نعم، فهو Apache-2.0، وهذا ترخيص مرن ومناسب تجاريًا. وكالعادة، راجع الترخيص الحالي في المستودع قبل الاعتماد عليه في مشروعك.
قبل اعتماده في الإنتاج، أضف اختبارات تعكس مخاطر التشغيل بدلًا من توسيع نتيجة العينة بالقياس غير المباشر. قِس الزحف المتكرر على أهداف ممثلة، وسجّل CPU والذاكرة القصوى، وجرّب حالات الفشل القابلة لإعادة المحاولة والنهائية، وتحقق من الالتزام بالتهذيب تحت التوازي. وإذا كانت الاستمرارية مهمة، فأوقف الزحف ثم استأنفه مع فحص التعامل مع التكرار وحالة queue. وإذا كانت بساطة النشر مهمة، فسجّل إعدادات المترجم والـ linker بدقة وافحص اعتماديات التشغيل للملف التنفيذي الناتج. لا يغيّر أي من ذلك ما أثبتته العينة الحالية؛ لكنه يحدد ما إذا كانت نفس تهيئة المكتبة مناسبة لمهمة إنتاجية بعينها.


