في كل الحالات التي كان أصلًا ممكنًا قياس التسرب فيها، حقق goose3 دقة 1.0000 على مستوى رموز المحتوى وصفر من الرموز الملوِّثة. لم يتسرّب إلى مخرجاته أي لفظ من عناصر التنقل أو الإعلانات أو الشريط الجانبي أو التعليقات أو العروض الترويجية. ولم ينجح أي واحد من الأدوات الست الأخرى في المقارنة في الوصول إلى هذا المستوى.
لكن لديه أيضًا أسوأ استدعاء للمقالات ضمن المجموعة — 0.8243 عبر كل الحالات الـ22، مقابل 1.0000 لدى Mozilla Readability — لأنه أعاد في حالتين سلسلة فارغة تمامًا.
وهذان المقياسان مرتبطان بقواعد التقييم نفسها: النتيجة الفارغة لا تضيف شيئًا إلى الدقة المشروطة، بينما يسجّل الاستدعاء حالة الفشل.
ما هو goose3
goose3 هو الامتداد بلغة Python 3 لسلسلة بدأت مع Goose من Gravity Labs بلغة Scala، ثم مرّت عبر python-goose. وهو مستخرج مقالات مع بيانات وصفية وليس مجرد أداة تفريغ نصي: أنشئ Goose، واستدعِ extract()، وستحصل على كائن Article يوفّر نحو ثمانية وعشرين حقلًا يمكن الوصول إليها — نصًا منقحًا، وعنوانًا، وكتّابًا، وتاريخ النشر، وصورة رئيسية، ووصفًا ميتا، ووسومًا، وروابط، وتغريدات، وغيرها.
المرجع الرسمي: المستودع الرسمي لـ goose3.

الإصدار الذي جرى اختباره: 3.1.22، برخصة Apache، مع 912 نجمة على GitHub، وآخر دفع بتاريخ 2026-07-23 — أي إنه مشروع ما يزال تحت صيانة نشطة وقت الاختبار. Python 3.14.2.
واجهة الاستخدام تتطلب استدعاءين والتزامًا واحدًا:
from goose3 import Goose
g = Goose()
try:
article = g.extract(raw_html=html)
text = article.cleaned_text
finally:
g.close() # أغلقه صراحةً بعد الاستخدام
تستحق close() أن تتنبه لها لأن نسيانها سهل، ولا توجد أي رسالة تحذير. لم يشغّل هذا الاستعراض اختبارًا حلقيًا لقياس الجلسات أو الاتصالات أو الذاكرة المتبقية عند تجاهل الإغلاق، لذا فإن وصف الأمر بأنه “تسرّب موارد” سيكون أقوى من الأدلة المتاحة. اعتبر الإغلاق الصريح جزءًا من دورة الحياة التي يفرضها نمط استخدام الواجهة هنا.
المفاضلة بالأرقام
ستة مستخرِجات، مجموعة واحدة من الأمثلة المعلَّمة، ومقيِّم واحد. كل كتلة في كل مثال موسومة إما article أو boilerplate وتحمل رمزًا فريدًا، لذلك فإن سؤال "هل استعاد هذه الوحدة؟" يُحسم بمطابقة النص تمامًا، لا بدرجة تشابه.
| المكتبة | استدعاء المقال (22/22) | تسرب الحشو | دقة رموز المحتوى | الرموز الملوِّثة | المخرجات المنتَجة |
|---|---|---|---|---|---|
| Readability | 1.0000 | 0.2353 | 0.9109 | 35 | 22/22 |
| trafilatura | 0.9865 | 0.0588 | 0.9411 | 4 | 22/22 |
| newspaper4k | 0.9865 | 0.0000 | 0.9452 | 0 | 22/22 |
| resiliparse | 0.9054 | 0.0588 | 0.9381 | 7 | 22/22 |
| jusText | 0.8378 | 0.4706 | 0.8760 | 74 | 19/22 |
| goose3 | 0.8243 | 0.0000 | 1.0000 | 0 | 20/22 |
sixway-scores.json. يُحسب الاستدعاء على جميع الحالات الـ22؛ بينما تُحسب نسبة التسرب والدقة على الحالات الـ11 التي تحتوي على وحدات للمقال والحشو معًا.
اقرأ عمود الدقة مع العمود الأخير دائمًا. فالدقة هنا مشروطة بوجود مخرجات — المكتبة التي تعيد سلسلة فارغة في إحدى الحالات لا تُحتسب لا في البسط ولا في المقام، لذا فإن الامتناع يبدو مجانيًا في هذا المتوسط. البسط هو مقدار التداخل بين رموز النص المستخرجة غير المتوقفة ورموز المقال المعلَّمة؛ والمقام هو كل رموز النص المستخرجة غير المتوقفة. أما "الرموز الملوِّثة" فتعني شيئًا أضيق: التداخل مع رموز الحشو المعلَّمة فقط. وإذا خرجت رمزًا إضافيًا لا يطابق لا رموز المقال ولا رموز الحشو، فستنخفض الدقة من دون أن يزيد ذلك العداد. ويمكن لتكرار الرموز خارج تعدد المقال أن يفعل الشيء نفسه. ولهذا قد تُظهر newspaper4k صفر رموز ملوِّثة مع دقة أقل من 1.0000. وقد احتُسبت 1.0000 الخاصة بـ goose3 على 10 من أصل 11 حالة؛ أما Readability وtrafilatura وnewspaper4k وresiliparse فاحتُسبت على 11 من 11.
ومع ذلك، تظل قيمة 1.0000 مفيدة داخل هذه المجموعة الاصطناعية. ففي عشر حالات جرى احتسابها، لم يُخرج goose3 أيًّا من رموز الحشو المعلَّمة؛ بينما أخرج Readability 35 رمزًا على الصفحات نفسها. وإذا كان نموذجك يستهلك المخرجات، فهذا يعني عدم إنفاق رموز على وسوم الحشو المسجَّلة في تلك الحالات العشر. لكنه لا يثبت عدم وجود هدر في الصفحات الحقيقية، كما أن النتيجة الفارغة قد تضيف كلفة بديلة أو كلفة إعادة محاولة في مكان آخر من خط المعالجة.
الصمتان، وماذا تعنيان
أعاد goose3 لا شيء في حالتين فقط. إحداهما يمكن تبريرها، والأخرى تمثل حدًا حقيقيًا.
الوثيقة شبه الفارغة. صفحة تحتوي على وحدة مقال واحدة بطول 32 حرفًا. goose3 يرفضها. وكذلك jusText. وفي هذه المجموعة من الأمثلة، أخرج Readability نتائج في جميع الصفحات الـ22، لذا فنتيجته لا تدعم صمت goose3 هنا. قبول تجاهل هذه الوثيقة الصغيرة أو رفضه يعتمد على الحد الأدنى للمحتوى الذي يشترطه المستدعي.

المقال المؤلف بالكامل من عناصر <li>. ست وحدات للمقال، ولا واحدة منها داخل وسم <p>. يعيد goose3 سلسلة فارغة.
هذا المثال الثاني استوقفني، لأن الإعداد الافتراضي نفسه في goose3 يقرأ parse_lists=True. لذلك اختبرته — ثلاث تهيئات مقابل عنصر تحكم سليم، لأن تجربة واحدة غير مثمرة لا تكفي للحكم على مكتبة:
| الإعداد | صفحة قائمة فقط | <p> تحكم |
|---|---|---|
| الإعدادات الافتراضية | 0 حرف | 937 حرفًا |
strict=False | 0 حرف | 937 حرفًا |
parse_lists=True (صراحةً) | 0 حرف | 937 حرفًا |
صفر في الحالات الثلاث كلها، بينما أعاد عنصر التحكم 937 حرفًا في الثلاث كلها. إذًا parse_lists=True يحدد ما إذا كانت القوائم ستُحافَظ داخل مقال سبق أن عثر عليه goose3 — لكنه لا يسمح لمحسوب المرشح أن يتعامل مع القائمة بوصفها هي المقال نفسه. يعتمد scoring العقدي في goose3 على كتل تشبه الفقرة ليعثر على الجسم أصلًا، والصفحة التي يكون جسمها قائمة لا تحتوي مثل هذه الكتل.
والنتيجة المدعومة أضيق من ذلك: جسم مُشكَّل مثل هذا المثال الاصطناعي — ست وحدات مقال، كلها <li>, من دون أي مرشح فقري — أعاد سلسلة فارغة. سجلات التغيير، ومراجع واجهات البرمجة، ووصفات الطهي، وصفحات الأسئلة الشائعة، ومنشورات المقارنات، كلها عينات منطقية للمخاطرة إذا أردت إعادة تشغيلها على صفحات حقيقية، لأن كثافة القوائم فيها قد تكون عالية، لكن هذا المثال وحده لا يثبت أن تلك الفئات تفشل عمومًا.
السلسلة الفارغة لا يمكن اكتشافها آليًا إلا إذا تحقّق المستدعي من عدم فراغ المخرج. من الأسهل ضبطها ببوابة من نص يبدو معقولًا لكنه لا يحتوي أيًّا من المقال، لكنها تظل فشلًا صامتًا في المراقبة التي تعتمد على الاستثناءات فقط. يحتاج المستدعي في الإنتاج إلى فحص حد أدنى للمخرج، وإلى بديل أو تسجيل صريح لصفحة فاشلة.
واقع الإعداد
يتطلب pip install goose3 16 حزمة و44.3 MiB في نحو 6 إلى 9 ثوانٍ. قياس الاستيراد البارد في عملية فرعية جديدة: 2.181 ثانية.
المرجع الرسمي: goose3 على PyPI.
| المكتبة | الحزم | site-packages | الاستيراد البارد | p50 للاستخراج |
|---|---|---|---|---|
| resiliparse | 5 | 21.0 MiB | 0.015 ثانية | 0.06 مللي ثانية |
| jusText | 3 | 22.4 MiB | 0.777 ثانية | 0.56 مللي ثانية |
| goose3 | 16 | 44.3 MiB | 2.181 ثانية | 1.85 مللي ثانية |
| newspaper4k | 22 | 47.5 MiB | 2.812 ثانية | 2.69 مللي ثانية |
| trafilatura | 17 | 69.9 MiB | 1.584 ثانية | 0.51 مللي ثانية |
install-and-import.json. كل مكتبة في بيئة افتراضية فارغة مستقلة، لذا لا ترث أي بصمة من مكتبة شقيقة.
من حيث الوزن فهو في الوسط، ومن حيث السرعة فهو في الوسط أيضًا. وقد ثُبّت واستورد بنجاح على Python 3.14.2، وهو أمر ليس مضمونًا في هذه الفئة.
ثلاث قيم افتراضية ينبغي معرفتها قبل النشر

قراءة كائن Configuration المرفق بدل الاكتفاء بالوثائق تكشف تسعة عشر إعدادًا. ثلاثة منها قد تفاجئ أحدهم.
يعرّف عن نفسه. القيمة الافتراضية لـ browser_user_agent هي Goose/3.1.22. إذا تركت goose3 يجلب الصفحات بنفسه، فسيسجّل كل خادم تزوره اسم المكتبة ورقمها الدقيق. هذا صريح، لكنه أيضًا بصمة تعريفية. اضبطه عمدًا أو اجلب HTML بنفسك ومرّر raw_html.
يشير إلى ثنائيّات MacPorts. القيمة الافتراضية لـ imagemagick_convert_path هي /opt/local/bin/convert ولـ imagemagick_identify_path هي /opt/local/bin/identify. على جهازي لا يوجد أيٌّ منهما — /opt/local يعود إلى MacPorts، وهو غير موجود لدى معظم الناس؛ بينما يضع Homebrew الثنائيات في /opt/homebrew. هذا الافتراض غير مؤذٍ ما لم تُفعّل جلب الصور (enable_image_fetching افتراضيًا False، وهذا منطقي)، لكن إن فعلتها متوقعًا أن يعمل استخراج الصورة الرئيسية، فهنا قد لا يعمل بصمت.
يفترض الإنجليزية. القيمة الافتراضية لـ target_language هي en مع use_meta_language=True، لذا سيتبع إعلان الصفحة نفسه عندما يكون موجودًا، ويعود إلى الإنجليزية عندما لا يكون. مناسب للعمل باللغة الإنجليزية، ويستحسن ضبطه صراحةً لأي لغة أخرى.
أما بقية الإعدادات فمعقولة: parser_class هو lxml، وhttp_timeout ثلاثون ثانية، وstrict مفعّل، وlog_level على ERROR، وparse_headers وkeep_footnotes مفعّلان، وimages_min_bytes يساوي 4,000.
الذاكرة، وما الذي يفعله HTML المعطوب بها
شيئان رصدتهما كل مراجعة في هذه الدفعة بوصفهما غير مختبرين، وقد جرى قياسهما الآن.
السياق الأوسع لاختبار الضغط موجود في مقارنة الذاكرة وHTML المعطوب عبر عشرة مكتبات.
أقصى الذاكرة المقيمة، عبر /usr/bin/time -l، عملية جديدة لكل خلية — الحد الأدنى للاستيراد هو ما تستهلكه المكتبة وهي محمَّلة وخاملة، بينما القمم تشمل المستند نفسه.
| المكتبة | بيئة التشغيل | حد الاستيراد الأدنى | ذروة 226 كيلوبايت | ذروة 10 ميغابايت |
|---|---|---|---|---|
| html2text | python3.14 | 18.7 | 19.9 | 71.2 |
| pyquery | python3.14 | 30.3 | 33.9 | 172.5 |
| resiliparse | python3.14 | 20.5 | 25.1 | 225.1 |
| markdownify | python3.14 | 23.9 | 28.9 | 278.5 |
| goose3 | python3.14 | 44.1 | 52.4 | 398.5 |
| cheerio | node22 | 66.8 | 76.5 | 398.5 |
| justext | python3.14 | 30.3 | 36.6 | 431.2 |
| newspaper4k | python3.14 | 52.6 | 61.8 | 668.5 |
| trafilatura | python3.14 | 52.5 | 64.8 | 927.1 |
| turndown | node22 | 47.8 | 68.4 | 2947.1 |
memory-results.json. المقارنات بين أساسيات Python وNode ليست مباشرة؛ فالمفسّر داخل الاثنين.
goose3 يستهلك عند الحد الأدنى 44.1 MiB ويصل إلى 398.5 MiB على مستند بحجم 10 MB. وحدّ الاستيراد الأدنى لديه هو الثالث الأعلى بين مكتبات Python المعروضة، وهذا مهم إذا كان النشر حساسًا لزمن البدء البارد.
HTML المعطوب. اثنا عشر مستندًا يخرّب كل واحد منها شيئًا واحدًا فقط — وسوم غير مغلقة، عناصر داخلية متداخلة بشكل خاطئ، سمات غير مقتبسة مع فراغات، وسوم إغلاق شاردة، عدم وجود <html> أصلًا، سمات مكررة، مستند مقطوع في منتصف الوسم، كيانات غير صحيحة، وسم <script> غير مغلق، إعلان charset كاذب، تعليق يحتوي على ترميز HTML، و600 مستوى من التعشيق — بالإضافة إلى عنصرَي تحكم سليمين بأحجام مماثلة، لأن "أعاد لا شيء" لا يقول شيئًا عن العطب إلا إذا كانت المكتبة أيضًا صامتة على مستند سليم بالحجم نفسه.
goose3 لم يرفع استثناءً في 0 من 14 حالة، وأعاد لا شيء في 10، واستعاد 2/33 من الرموز المميِّزة عبر الأمثلة المعطوبة (malformed-results.json). وتُستثنى حالة واحدة من هذا العد: وفق HTML5، كل ما يأتي بعد <script> غير مغلق يُعدّ محتوى سكربت، لذا فإن فقدانه هناك صحيح، واستعادته هو الانحراف.
الإيجابيات والسلبيات
ما له. صفر رموز حشو معلَّمة عبر عشر حالات جودة محتوى حيث أنتج مخرجات. يتوفر نحو ثمانية وعشرين حقلًا للمقال، رغم أن دقتها جرى جردها لا تقييمها. الافتراضي الخاص بجلب الصور معقول لأنه متوقف. تثبيت نظيف على Python 3.14. ما يزال نشط الصيانة. Apache-2.0. والنتيجة الفارغة سهلة الضبط عندما يفحصها المستدعي صراحةً.
ما عليه. أدنى استدعاء للمقال في المجموعة عند 0.8243، بسبب إعادة لا شيء مطلقًا لا بسبب إعادة الشيء الخطأ. الصفحة التي يكون مقالها قائمة تُنتج سلسلة فارغة مهما كان الإعداد. 44.3 MiB و2.2 ثانية للاستيراد البارد ثقيلتان مقارنةً بـ resiliparse الذي يكتفي بـ 21.0 MiB و15 مللي ثانية. يحتاج إلى close(). وهناك قيمتان افتراضيتان تُشيران إلى مسارات خاطئة على معظم الأجهزة.
لمن يصلح، ولمن لا يصلح
استخدم goose3 كخيار عندما يكون النص المستخرج ذاهبًا إلى نموذج أو قاعدة بيانات حيث يكون الحشو المعلَّم مكلفًا، وكانت الصفحات مقالات تقليدية ذات فقرات. في هذه المجموعة لم يُخرج أي رموز حشو معلَّمة عندما أجاب. سطح البيانات الوصفية متاح، لكنه غير مُتحقق هنا؛ لذا فدقة العنوان والكاتب والتاريخ والصورة تحتاج إلى أمثلة حقيقة منفصلة قبل أن تصبح ميزة اختيار.
تجنّبه إذا كانت مجموعتك غنية بالقوائم — فستحصل على سلاسل فارغة من دون تفسير. وتجنّبه إذا كان زمن البدء البارد مهمًا، حيث تستورد resiliparse أسرع بـ145 مرة. وتجنّبه إذا كنت تحتاج إجابة على كل صفحة، لأن "لا إجابة" نتيجة حقيقية هنا: حالتان من أصل 22، وكلتاهما بصمت، بمعنى أن السلسلة الفارغة ليست استثناءً.
تركيبة تستحق الاختبار: اجعل goose3 الخيار الأساسي مع بديل احتياطي عندما تكون cleaned_text فارغة أو أقل من الحد الأدنى للمحتوى الذي تقرره. Readability استعاد كل وحدة مقال في هذه المجموعة ذات الـ22 حالة، بما في ذلك الحالتين الفارغتين الخاصتين بـ goose3. هذه النتيجة الاصطناعية تدعم نمط التصميم، لكنها لا تعد بأن البديل لن يفوّت شيئًا في الصفحات الحقيقية.
أين يناسب API المُدار
اختبر هذا المعيار مسار استخراج raw_html في goose3: كانت HTML قد جُمعت بالفعل قبل أن يراها goose3. لدى goose3 أيضًا مسار خاص به لجلب الشبكة، كما توضح قيمة User-Agent، لكن ذلك المسار لم يُختبر هنا. ولم يُختبر أيضًا عرض JavaScript أو سلوك الحماية من الروبوتات.
للمقارنة نفسها عبر المستخرجات الستة، راجع مقارنة الاستخراج عبر ست مكتبات.
أما خدمة الجلب/العرض/الاستخراج المُدارة، بما في ذلك Thunderbit الخاصة بنا، فتقع عند حدود مسؤولية مختلفة. لم يخضع Thunderbit للاختبار في هذه الدراسة. والتمييز المهم هنا هو بين استخراج المقال من HTML المُقدَّم، وبين خدمة مستضافة تجلب الرابط وتعالجه؛ وهذه المقالة لا تقدّم مقارنة متكافئة من حيث المقاييس أو الجودة.
والمقارنة العادلة هي التالية: مجموعة الحقول في goose3 ثابتة ومصممة حول شكل المقال، وهذا مثالي حين تكون صفحاتك مقالات، وخاطئ حين تكون قوائم منتجات. إذا كنت تملك HTML أصلًا وكانت صفحاتك مقالات، فـ goose3 مجاني ونظيف جدًا.
أما في جانب الخدمات المستضافة، فلدينا جولة في أفضل واجهات برمجة تطبيقات استخراج الويب كصورة أوسع؛ وللخيارات مفتوحة المصدر، راجع دليل مستخرجات الويب مفتوحة المصدر. وإذا كان النص سيُستخدم داخل نموذج، فمقال تحويل HTML إلى Markdown في Python يوضح أين تضيع الدقة فعليًا.
جرّب Thunderbit لاستخراج بيانات الويب
هل ينبغي استخدام goose3؟
نعم، إذا كانت المقالات ذات بنية الفقرات مناسبة لعملك، وكان المستدعي يتعامل مع المخرجات الفارغة بوصفها فشل استخراج لا نجاحًا.
في هذه المجموعة، لم يُخرج goose3 أي رموز حشو معلَّمة عندما أجاب، وأعاد سلسلتين فارغتين. واحدة كانت صفحة شبه فارغة، والأخرى جسمًا اصطناعيًا قائمًا على القوائم فقط. هذه مفاضلة بين الدقة والاستدعاء، وليست دليلًا على مزاج المنتج عمومًا.
إذا كان الاستدعاء أهم لديك، فاختبر بديلًا احتياطيًا مع بوابة صريحة للحد الأدنى للمحتوى. Readability استعاد كل وحدة مقال في هذه الحالات الـ22؛ وnewspaper4k أظهر صفر تسرب مع وحدات الحشو المعلَّمة واستدعاء 0.9865 مع إنتاج مخرجات في 22 من 22. هذه النتائج ترتّب هذه المجموعة الاصطناعية تحت الإعدادات الافتراضية، لا تحت أعباء إنتاجية غير معروفة.
goose3 يستحق مكانه عندما تكون كلفة الكلمة الخطأ أعلى من كلفة الصفحة المفقودة.
جرّب Thunderbit لاستخراج بيانات الويب Get Started Free
الأسئلة الشائعة
هل دقة goose3 الكاملة حقيقية أم مجرد نتيجة لرفضه بعض الصفحات؟ كلا الأمرين، ويمكن الفصل بينهما. فقد احتُسب على 10 من أصل 11 حالة تحتوي على حشو، لذا غابت حالة واحدة عن المتوسط — وهذا الجزء أثرٌ لرفضه. لكنه في تلك الحالات العشر أعاد صفر رموز ملوِّثة أمام حشو مصمم ليكون معاديًا، بينما سرّبت Readability 35. الدقة حقيقية في الصفحات التي يجيب عنها؛ أما الاستدعاء فهو مكان ظهور الرفض.
لماذا يُرجع goose3 لا شيء في صفحة يكون مقالها قائمة؟
لأن محرك اختيار المرشحين يحتاج كتلًا تشبه الفقرة ليعثر على جسم المقال، والصفحة المبنية من <li> لا تحتوي مثل هذه الكتل. والإعداد الافتراضي parse_lists=True لا يغيّر هذا — لقد اختبرته صراحةً، ومعه strict=False أيضًا، وحصلت على صفر حرف في التهيئات الثلاث كلها، بينما أعادت صفحة تحكم مبنية على <p> قيمة 937 في الثلاث كلها. يقرر parse_lists فقط ما إذا كانت القوائم ستبقى داخل مقال تم العثور عليه بالفعل.
هل يجب أن أستدعي close()؟
أغلقه صراحةً باستخدام try/finally كما هو موضح أعلاه. هذا الاستعراض لم يقس ما يتراكم عند إهمال الإغلاق، لذا لا يدّعي وجود تسرب حلقي مُقاس؛ لكنه يثبت أن Goose له دورة حياة يجب على المستدعي إدارتها.
ما الذي يرسله goose3 كـ User-Agent؟
Goose/3.1.22 افتراضيًا — أي اسم المكتبة ورقمها الدقيق. وهذا ينطبق فقط عندما تتركه يجلب بنفسه، أما تمرير raw_html فيتجاوز ذلك كليًا. وإذا سمحت له بالجلب، فاضبط User-Agent عمدًا؛ لأن الافتراضي يخبر كل خادم تزوره بما ينفّذ الطلب بدقة.
ما الذي لم تختبره هذه المراجعة؟
الصفحات الواقعية تمامًا — فهذه أمثلة مضبوطة. والاستخراج متعدد اللغات، رغم أن target_language إعداد من الدرجة الأولى. كما جُمعت حقول البيانات الوصفية (العنوان، المؤلفون، التاريخ، الصورة الرئيسية) في جرد ولم تُقَس دقتها. وجلب الصور، وهو متوقف افتراضيًا ومسارات ImageMagick الخاصة به تشير إلى مدير حزم لا يملكه معظم الأجهزة. وكذلك سلوك الذاكرة تحت الحمل المتزامن أو المستمر، إضافةً إلى معدل الإنتاجية تحت الضغط؛ فجدول الذاكرة قاس عملية جديدة واحدة تعالج مستندًا واحدًا.


