בכל המקרים שבהם בכלל אפשר למדוד זליגת תוכן, goose3 השיגה דיוק של 1.0000 בטוקני התוכן ואפס טוקנים מזהמים. אף מילה של ניווט, פרסומות, סרגל צד, תגובות או קידום לא נכנסה לפלט שלה. אף כלי אחר בהשוואה בין שש ספריות לא השתווה לזה.
עם זאת, זו גם הספרייה עם כיסוי המאמר הגרוע ביותר בקבוצה — 0.8243 על פני כל 22 המקרים, לעומת 1.0000 ב-Mozilla Readability — משום שבשניים מהם היא החזירה מחרוזת ריקה.
המדדים האלה קשורים לכלל הניקוד: תוצאה ריקה לא תורמת כלום לדיוק המותנה, בעוד שהריקוד של הכיסוי נרשם כפספוס.
מה זה goose3
goos3 היא ההמשכיות ב-Python 3 של שושלת שמתחילה ב-Goose של Gravity Labs ב-Scala ועוברת דרך python-goose. זהו מחלץ מאמרים עם מטא-דאטה, לא סתם מפלט טקסט: יוצרים Goose, קוראים extract(), ומקבלים אובייקט Article עם כ-28 שדות נגישים — טקסט מנוקה, כותרת, מחברים, תאריך פרסום, תמונה מובילה, תיאור מטא, תגיות, קישורים, ציוצים ועוד.
מקור רשמי: הריפוזיטורי הרשמי של goose3.

גרסה שנבדקה: 3.1.22, ברישיון Apache, 912 כוכבים ב-GitHub, עודכנה לאחרונה ב-2026-07-23 — מתוחזקת באופן פעיל בעת הבדיקה. Python 3.14.2.
ה-API הוא שני קריאות וחובה אחת:
from goose3 import Goose
g = Goose()
try:
article = g.extract(raw_html=html)
text = article.cleaned_text
finally:
g.close() # close explicitly after use
כדאי לשים לב ל-close() כי קל לשכוח אותו ואין שום אזהרה. בסקירה הזו לא הופעל בדיקת לולאה כדי למדוד סשנים, חיבורים או זיכרון שנשארים פתוחים כשמדלגים על הסגירה, לכן "דליפת משאבים" תהיה טענה חזקה יותר ממה שהראיות תומכות בו. עדיף להתייחס לסגירה מפורשת כדרישת מחזור החיים שהשימוש ב-API כאן מראה.
מהו הטרייד-אוף, לפי מדידה
שש מחלצות, סט אחד של fixtures מסומנים, ומדד אחד. כל בלוק בכל fixture מסומן כ-article או boilerplate ונושא טוקן ייחודי, כך ש"האם הוא שיחזר את היחידה הזו" נמדד לפי התאמת תת-מחרוזת מדויקת ולא לפי ציון דמיון.
| Library | Article recall (all 22) | Boilerplate leak | Content-token precision | Contaminating tokens | Produced output |
|---|---|---|---|---|---|
| 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. ה-Recall מחושב על פני כל 22 ה-fixtures; שיעור הזליגה והדיוק — על פני 11 ה-fixtures שמכילים גם יחידות מאמר וגם boilerplate.
קראו את עמודת הדיוק יחד עם העמודה האחרונה, תמיד. הדיוק כאן הוא מותנה בכך שנוצר פלט — ספרייה שמחזירה מחרוזת ריקה ב-fixture לא תורמת למונה ולא למכנה, כך שירידה היא בחינם בממוצע הזה. המונה הוא חפיפה של מולטי-סט בין טוקנים לא-Stopword שהופקו לבין טוקני המאמר המסומנים; המכנה הוא כל טוקן לא-Stopword שהופק. "טוקנים מזהמים" הוא מדד צר יותר: חפיפה עם טוקני ה-boilerplate המסומנים בלבד. טוקן נוסף שהופק ואינו תואם לא טוקן מאמר ולא טוקן boilerplate יוריד את הדיוק בלי להעלות את ספירת הזיהום הזו; גם טוקנים חוזרים מעבר למולטי-סט של המאמר יכולים לעשות זאת. לכן newspaper4k יכול להציג 0 טוקנים מזהמים ודיוק נמוך מ-1.0000. ה-1.0000 של goose3 חושב על 10 מתוך 11 ה-fixtures; Readability, trafilatura, newspaper4k ו-resiliparse חושבו על 11 מתוך 11.
ובכל זאת, ה-1.0000 עדיין שימושי בתוך הסט הסינתטי הזה. מתוך עשרת ה-fixtures שנמדדו, goose3 לא הפיקה אף אחד מטוקני ה-boilerplate המסומנים; Readability הפיקה 35 באותם דפים. אם מודל צורך את הפלט, זה אומר שלא נצרכו טוקנים על התוויות של boilerplate בעשרת ה-fixtures האלה. זה לא מוכיח אפס בזבוז בדפים אמיתיים, ותוצאה ריקה עלולה להוסיף עלות fallback או retry במקום אחר ב-pipeline.
שתי ההשתקות, ומה הן אומרות
goose3 לא החזירה כלום בדיוק בשני fixtures. אחד מהם אפשר להצדיק, והשני הוא מגבלה אמיתית.
מסמך כמעט ריק. דף עם יחידת מאמר אחת בת 32 תווים. goose3 מסרבת. גם jusText. בסט הזה, Readability הפיקה פלט בכל 22 הדפים, כך שהתוצאה שלה לא תומכת בשתיקה של goose3 כאן. האם דחייה של המסמך הזעיר הזה מקובלת תלוי בחוזה התוכן המינימלי של מי שקורא לספרייה.

מאמר שמורכב כולו מאלמנטים מסוג <li>. שש יחידות מאמר, ואף אחת מהן לא בתוך תגית <p>. goose3 מחזירה מחרוזת ריקה.
החלק השני הפתיע אותי, כי ברירת המחדל של goose3 עצמה כוללת parse_lists=True. לכן בדקתי את זה — שלוש תצורות מול בקר עובד, כי הרצה אחת לא מועילה אינה מסקנה לגבי ספרייה:
| Configuration | List-only page | <p> control |
|---|---|---|
| defaults | 0 chars | 937 chars |
strict=False | 0 chars | 937 chars |
parse_lists=True (explicit) | 0 chars | 937 chars |
אפס בכל שלוש התצורות, בעוד שהבקר מחזיר 937 תווים בכל אחת מהן. כלומר parse_lists=True קובע האם רשימות יישמרו בתוך מאמר שכבר נמצא — הוא לא מאפשר למנגנון הדירוג להתייחס לרשימה כאל המאמר עצמו. מנגנון הניקוד של הצמתים ב-goose3 זקוק לבלוקים בצורת פסקאות כדי למצוא את גוף הטקסט בכלל, ודף שגופו רשימה פשוט לא מכיל כאלה.
המסקנה הנתמכת היא צרה יותר: גוף שנראה כמו ה-fixture הסינתטי הזה — שש יחידות מאמר, כולן <li>, בלי מועמד לפסקה — החזיר מחרוזת ריקה. יומני שינויים, תיעוד API, מתכונים, דפי FAQ ופוסטים השוואתיים הם דוגמאות סבירות לסיכון בבדיקה על דפים אמיתיים, כי הם נוטים להיות מבוססי רשימות, אבל ה-fixture הזה לבדו לא מוכיח שקטגוריות הדפים האלה נכשלות בדרך כלל.
מחרוזת ריקה ניתנת לזיהוי אוטומטי רק אם הקורא בודק שהפלט אינו ריק. קל יותר לחסום אותה מאשר טקסט שנראה סביר אבל אינו כולל את המאמר, אבל היא עדיין כישלון שקט במעקב שמבוסס רק על חריגות. צרכן פרודקשן צריך בדיקת מינימום-פלט ו-fallback או רישום מפורש של דף שנכשל.
מציאות ההתקנה
pip install goose3 מושך 16 חבילות ו-44.3 MiB בכ-6 עד 9 שניות. מדידת cold import בתהליך משנה טרי: 2.181 שניות.
מקור רשמי: goose3 ב-PyPI.
| Library | Packages | site-packages | Cold import | Extraction p50 |
|---|---|---|---|---|
| resiliparse | 5 | 21.0 MiB | 0.015 s | 0.06 ms |
| jusText | 3 | 22.4 MiB | 0.777 s | 0.56 ms |
| goose3 | 16 | 44.3 MiB | 2.181 s | 1.85 ms |
| newspaper4k | 22 | 47.5 MiB | 2.812 s | 2.69 ms |
| trafilatura | 17 | 69.9 MiB | 1.584 s | 0.51 ms |
install-and-import.json. כל ספרייה בתוך virtualenv ריק משלה, כך שאין טביעת רגל שמגיעה מיריבה שכנה.
אמצע הטבלה מבחינת משקל, ואמצע גם במהירות. ההתקנה והייבוא עברו בצורה תקינה ב-Python 3.14.2, וזה לא מובן מאליו בקטגוריה הזו.
שלוש ברירות מחדל שכדאי להכיר לפני פריסה

קריאת אובייקט Configuration שמגיע עם הספרייה, במקום להסתמך על התיעוד, חושפת 19 הגדרות. שלוש מהן עשויות להפתיע.
היא מצהירה על עצמה. 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 הוא 30 שניות, strict פעיל, log_level על ERROR, ו-parse_headers ו-keep_footnotes מופעלים, images_min_bytes הוא 4,000.
זיכרון, ומה HTML שבור עושה לו
שני דברים שכל סקירה בסבב הזה סימנה כלא נבדקו — עכשיו נמדדו.
הקשר רחב יותר של מבחן העומס נמצא ב-השוואת הזיכרון וה-HTML השבור בין עשר ספריות.
שיא זיכרון resident, דרך /usr/bin/time -l, תהליך חדש לכל תא — רצפת הייבוא היא העלות של הספרייה כשהיא טעונה ומחכה, והשיאים כוללים את המסמך.
| Library | Runtime | Import floor | 226 KB peak | 10 MB peak |
|---|---|---|---|---|
| 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 שמופיעות כאן, וזה חשוב בפריסה רגישה ל-cold start.
HTML שבור. שנים-עשר מסמכים, כל אחד מהם שובר בדיוק דבר אחד — תגיות לא סגורות, אלמנטים inline מקוננים לא נכון, מאפיינים בלי מרכאות עם רווחים, סוגרי תגיות מיותרים, בלי <html> בכלל, מאפיינים כפולים, מסמך שנחתך באמצע תגית, ישויות שבורות, <script> לא סגור, הצהרת charset שקרית, תגובה שמכילה markup, ו-600 רמות קינון — ועוד שני controls תקינים בגודל תואם, כי "הוא לא החזיר כלום" אומר משהו על malformedness רק אם הספרייה לא שותקת גם על מסמך נקי באותו גודל.
goose3 זרקה חריגה ב-0 מתוך 14 והחזירה כלום ב-10, ושיחזרה 2/33 טוקנים מסמנים בכל ה-fixtures השבורים (malformed-results.json). Fixture אחד לא נספר: לפי HTML5, כל מה שאחרי <script> לא סגור הוא תוכן script, לכן אובדן שם הוא התנהגות נכונה, ושחזורו הוא הסטייה.
יתרונות וחסרונות
לטובת goose3. אפס טוקני boilerplate מסומנים בעשרת ה-fixtures של דיוק-התוכן שבהם היא הפיקה פלט. בערך 28 שדות מאמר זמינים, אף שהדיוק שלהם נספר ולא נמדד. ברירת מחדל סבירה לאחזור תמונות (כבוי). התקנה נקייה על Python 3.14. מתוחזקת באופן פעיל. Apache-2.0. תוצאה ריקה קלה לסינון כאשר הקורא בודק זאת במפורש.
נגד goose3. ה-Recall הנמוך ביותר בקבוצה — 0.8243 — שנגרם כולו מכך שלא הוחזר דבר כלל, ולא מכך שהוחזר דבר שגוי. דף שהמאמר שלו הוא רשימה מחזיר מחרוזת ריקה בלי קשר להגדרות. 44.3 MiB וייבוא קר של 2.2 שניות כבדים לעומת 21.0 MiB ו-15ms של resiliparse. דורשת close(). שתי ברירות מחדל מצביעות על דברים שאינם נכונים ברוב המכונות.
מי צריך להשתמש בה, ומי לא
כדאי להשתמש ב-goose3 כמועמדת כאשר טקסט מחולץ נכנס למודל או למסד נתונים שבו boilerplate מסומן יקר, והעמודים הם מאמרים קונבנציונליים עם פסקאות. בסט הזה היא לא הפיקה טוקנים מסומנים של boilerplate כשהיא ענתה. שכבת המטא-דאטה זמינה, אבל כאן לא נבדקה; דיוק של כותרת, מחבר, תאריך ותמונה דורש fixtures עם אמת-מבחן נפרדת לפני שזה יהפוך ליתרון בבחירה.
עדיף לדלג עליה אם הקורפוס שלכם מבוסס רשימות — תקבלו מחרוזות ריקות בלי הסבר. דלגו עליה גם אם עלות cold start חשובה, כי resiliparse נטענת 145× מהר יותר. ודלגו גם אם אתם צריכים תשובה בכל דף, כי "אין תשובה" היא תוצאה אמיתית כאן: שניים מתוך 22 fixtures, ובשקט, במובן שמחרוזת ריקה אינה חריגה.
צימוד שכדאי לבדוק: goose3 כראשית עם fallback כאשר cleaned_text ריק או קצר מהמינימום שהגדרתם. Readability שיחזרה כל יחידת מאמר בסט של 22 fixtures, כולל שני המקרים הריקים של goose3. התוצאה הסינתטית הזו תומכת בתבנית הארכיטקטורה, לא בהבטחה שה-fallback אף פעם לא מפספס בדפים אמיתיים.
איפה API מנוהל משתלב
המדד הזה בדק את נתיב החילוץ של raw_html ב-goose3: ה-HTML כבר נשלף לפני ש-goose3 ראתה אותו. ל-goose3 יש גם נתיב משלה להבאת תוכן מהרשת, כפי שרואים מהגדרת User-Agent שלה, אבל הנתיב הזה לא נבדק כאן. גם רינדור JavaScript והתנהגות אנטי-בוט לא נבדקו.
לאותה קבוצת fixtures בכל שש המחלצות, ראו את השוואת החילוץ בין שש הספריות.
שירות מנוהל של fetch/render/extraction, כולל Thunderbit שלנו, מייצג גבול אחר של אחריות. Thunderbit לא נכללה במדד הזה. ההבדל הרלוונטי הוא חילוץ מאמר מ-HTML שסופק מראש לעומת שירות מתארח שאוסף ומעבד URL; המאמר הזה לא מספק השוואת ביצועים או איכות באותם מדדים.
ההשוואה ההוגנת: סט השדות של goose3 קבוע ובנוי סביב מאמרים, וזה בדיוק נכון כשהעמודים הם מאמרים, ולא נכון כשהם דפי מוצרים. אם כבר יש לכם את ה-HTML והעמודים הם מאמרים, goose3 חינמית ונקייה מאוד.
לשכבה המתארחת, הסקירה שלנו של ממשקי API ל-web scraping נותנת את התמונה הרחבה; לחלופות self-hosted, עמוד-האב של open-source scrapers. אם הטקסט מיועד למודל, המרת HTML ל-Markdown ב-Python מסבירה איפה באמת הולך לאיבוד הדיוק.
נסו את Thunderbit לחילוץ נתונים מהאינטרנט
אז האם כדאי להשתמש ב-goose3?
כן, אם מאמרים בפורמט של פסקאות תואמים לעומס העבודה ואם הקורא מתייחס לפלט ריק כאל כישלון חילוץ ולא כהצלחה.
בסט הזה goose3 לא הפיקה טוקנים מסומנים של boilerplate כשהיא ענתה, והחזירה שתי מחרוזות ריקות. אחת הייתה דף כמעט ריק, והשנייה גוף סינתטי שמורכב רק מרשימות. זה trade-off בין דיוק לכיסוי, לא הוכחה לאופי מוצרי כללי.
אם הכיסוי חשוב יותר, בדקו fallback עם guard מפורש למינימום פלט. Readability שיחזרה כל יחידת מאמר ב-22 fixtures האלה; newspaper4k הציגה זליגה אפסית של יחידות boilerplate מסומנות ו-0.9865 Recall, תוך יצירת פלט בכל 22 הדפים. התוצאות האלה מדרגות את הסט הסינתטי הזה, לא עומסי עבודה אמיתיים לא ידועים.
goose3 מרוויחה את מקומה כשהמחיר של מילה שגויה גבוה מהמחיר של דף חסר.
נסו את Thunderbit לחילוץ נתונים מהאינטרנט Get Started Free
שאלות נפוצות
האם הדיוק המושלם של goose3 אמיתי, או תוצר של זה שהיא פשוט מסרבת? גם וגם, וניתן להפריד ביניהם. היא נמדדה על 10 מתוך 11 fixtures שמכילים boilerplate, כך ש-fixture אחד חסר מהממוצע — החלק הזה הוא תוצר של סירוב. אבל בעשרת אלה היא לא החזירה אף טוקן מזהם מול boilerplate שנבנה בכוונה להיות אגרסיבי, בעוד Readability זלגה 35. הדיוק אמיתי עבור דפים שהיא עונה עליהם; עמודת ה-Recall היא המקום שבו הסירוב מתבטא.
למה goose3 מחזירה כלום בדף שהמאמר שלו הוא רשימה?
ניקוד המועמדים שלה צריך בלוקים בצורת פסקאות כדי לאתר את גוף המאמר, ודף שמורכב מ-<li> פשוט לא מספק כאלה. ברירת המחדל parse_lists=True לא משנה זאת — בדקתי זאת במפורש, יחד עם strict=False, וקיבלתי 0 תווים בכל שלוש התצורות, בעוד שבקר מבוסס <p> החזיר 937 בכל שלוש. parse_lists קובע רק האם רשימות נשמרות בתוך מאמר שכבר נמצא.
האם חייבים לקרוא ל-close()?
כן, כדאי לסגור במפורש באמצעות try/finally, כפי שמוצג למעלה. הסקירה הזו לא מדדה מה מצטבר כשמדלגים על הסגירה, כך שהיא לא טוענת לדליפת לולאה כמותית; אבל היא כן מראה של-Goose יש מחזור חיים שהקורא חייב לנהל.
איזה User-Agent goose3 שולחת?
Goose/3.1.22 כברירת מחדל — שם הספרייה והגרסה המדויקת. זה חל רק כשנותנים לה להביא את הדף בעצמה, בעוד שמעבר ל-raw_html עוקף זאת לגמרי. אם כן נותנים לה להביא את הדף, כדאי להגדיר User-Agent במכוון; ברירת המחדל אומרת לכל שרת בדיוק מי פונה אליו.
מה לא נבדק בסקירה הזו?
דפים אמיתיים, בכלל — אלה fixtures מבוקרים. חילוץ רב-לשוני, למרות ש-target_language הוא הגדרה מרכזית. שדות המטא-דאטה (כותרת, מחברים, תאריך, תמונה מובילה) נרשמו אבל לא נבדקו לדיוק. אחזור תמונות, שהוא כבוי כברירת מחדל ושנתיבי ImageMagick שלו מצביעים על מנהל חבילות שרוב המחשבים לא משתמשים בו. התנהגות זיכרון תחת עומס מתמשך או מקבילי, וגם תפוקה תחת עומס; טבלת הזיכרון מדדה תהליך חדש אחד שטיפל במסמך אחד.


