I de testfall där ett läckage ens går att definiera levererade goose3 1,0000 precision för innehållstokens och noll förorenande tokens. Inte ett enda ord från navigation, annonser, sidofält, kommentarer eller kampanjer smög sig in i resultatet. Ingen annan av de sex jämförda biblioteken kom i närheten.
Samtidigt har det lägst article recall i hela jämförelsen — 0,8243 över alla 22 testfall, mot 1,0000 för Mozilla Readability — eftersom det i två av dem returnerade en tom sträng.
De här måtten hänger ihop genom poängregeln: ett tomt resultat bidrar inte till den villkorade precisionen, medan recall registrerar misslyckandet.
Vad goose3 är
goose3 är Python 3-fortsättningen på en kedja som börjar med Gravity Labs' Goose i Scala och fortsätter via python-goose. Det är en artikelutdragare med metadata, inte en ren textdumpare: skapa en Goose, anropa extract(), och du får tillbaka ett Article-objekt med omkring tjugoåtta åtkomliga fält — rensad text, titel, författare, publiceringsdatum, toppbild, meta description, taggar, länkar, tweets och mer.
Officiell referens: goose3:s officiella repo.

Testad version: 3.1.22, Apache-licensierad, 912 GitHub-stjärnor, senast pushad 2026-07-23 — aktivt underhållen vid testtillfället. Python 3.14.2.
API:t är två anrop och en skyldighet:
from goose3 import Goose
g = Goose()
try:
article = g.extract(raw_html=html)
text = article.cleaned_text
finally:
g.close() # close explicitly after use
Den där close() är värd att nämna eftersom den är lätt att glömma och ingenting varnar dig. Den här genomgången körde ingen loop-probe för att kvantifiera kvarhållna sessioner, anslutningar eller minne när stängning hoppas över, så "resursläcka" skulle vara starkare än bevisningen. Betrakta därför explicit stängning som livscykelkravet som visas av API-användningen här.
Avvägningen, mätt
Sex extraktorer, en annoterad uppsättning testfall, en scorer. Varje block i varje testfall är märkt article eller boilerplate och bär en unik sentinel-token, så "tog den här enheten" avgörs med exakt delsträngsmatchning snarare än ett likhetsmått.
| 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 avser alla 22 testfall; läckagerate och precision de 11 som innehåller både article- och boilerplate-enheter.
Läs precision-kolumnen tillsammans med sista kolumnen, alltid. Precision här är villkorad på att resultat faktiskt produceras — ett bibliotek som returnerar en tom sträng i ett testfall bidrar inte till täljaren och inte heller till nämnaren, så att avstå är gratis i det här genomsnittet. Täljaren är multiset-överlappet mellan extraherade icke-stopword-tokens och märkta artikel-tokens; nämnaren är varje extraherad icke-stopword-token. "Contaminating tokens" är snävare: överlapp med enbart de märkta boilerplate-tokenen. En extra extraherad token som matchar varken artikel- eller boilerplate-märkningen sänker precisionen utan att öka just det föroreningsmåttet; upprepade tokens utöver artikelns multiset kan göra samma sak. Därför kan newspaper4k visa 0 förorenande tokens och ändå ligga under 1,0000 i precision. goose3:s 1,0000 beräknades på 10 av de 11 testfallen; Readability, trafilatura, newspaper4k och resiliparse poängsattes på 11 av 11.
Ändå är 1,0000 värdefullt inom den här syntetiska uppsättningen. Över de tio poängsatta testfallen släppte goose3 inte igenom någon av de märkta boilerplate-tokenen; Readability släppte igenom 35 på samma sidor. Om en modell konsumerar resultatet betyder det ingen tokenförbrukning på de boilerplate-märkningar som registrerades i de tio testfallen. Det bevisar inte noll spill på riktiga sidor, och ett tomt resultat kan dessutom skapa fallback- eller retry-kostnad längre fram i pipelinen.
De två tystnaderna, och vad de betyder
goose3 returnerade inget på exakt två testfall. Det ena kan försvaras, det andra är en verklig begränsning.
Det nästan tomma dokumentet. En sida med en enda artikel-enhet på 32 tecken. goose3 avstår. Det gör även jusText. I den här testuppsättningen producerade Readability output på alla 22 sidor, så dess resultat stöder inte goose3:s tystnad här. Om det är acceptabelt att avstå från det här pyttelilla dokumentet beror på anroparens minimiinnehållskrav.

Artikeln som enbart består av <li>-element. Sex artikel-enheter, inga av dem i ett <p>-tagg. goose3 returnerar en tom sträng.
Det andra fallet förbryllade mig, eftersom goose3:s egen standardkonfiguration anger parse_lists=True. Så jag testade det — tre konfigurationer mot ett fungerande kontrollfall, eftersom ett enda resultatlöst körningstillfälle inte är ett fynd om ett bibliotek:
| 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 |
Noll i alla tre, medan kontrollen ger 937 tecken i alla tre. Alltså styr parse_lists=True om listor ska behållas i en artikel som goose3 redan har hittat — det gör inte att kandidatens poängsättning kan behandla en lista som artikeln. goose3:s nodpoängsättning behöver paragraf-liknande block för att alls hitta brödtexten, och en sida vars kropp är en lista har inga sådana.
Det stödda resultatet är snävare: en kropp formad som det här syntetiska testfallet — sex artikel-enheter, alla <li>, utan någon paragrafkandidat — returnerade en tom sträng. Changelogs, API-referenser, recept, FAQ-sidor och jämförelselister är rimliga riskkategorier för en verklig sidreplikering eftersom de kan vara listtunga, men just det här testfallet bevisar inte att de sidtyperna generellt misslyckas.
Den tomma strängen går att upptäcka maskinellt endast om anroparen validerar att resultatet inte är tomt. Det är lättare att stoppa än plausibelt text som inte innehåller något av artikeln, men det är fortfarande ett tyst misslyckande om man bara övervakar undantag. En produktionsanropare behöver en kontroll för minsta output och en fallback eller en explicit logg för misslyckad sida.
Verkligheten kring installation
pip install goose3 hämtar 16 paket och 44,3 MiB på ungefär 6 till 9 sekunder. Kall import mätt i en färsk subprocess: 2,181 s.
Officiell referens: goose3 på 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. Varje bibliotek ligger i en egen tom virtuell miljö, så inget arv från syskon påverkar footprinten.
Mitten av fältet i vikt, mitten i hastighet. Det installerade och importerades utan problem på Python 3.14.2, vilket inte är självklart i den här kategorin.
Tre standardinställningar värda att känna till innan du driftsätter

När man läser det levererade Configuration-objektet i stället för dokumentationen dyker nitton inställningar upp. Tre av dem kommer att överraska någon.
Den presenterar sig själv. browser_user_agent har standardvärdet Goose/3.1.22. Om du låter goose3 hämta själv loggar varje server du träffar bibliotekets namn och exakta version. Det är ärligt, men också ett fingeravtryck. Sätt det medvetet eller hämta HTML själv och skicka in raw_html.
Den pekar på en MacPorts-binär. imagemagick_convert_path har standardvärdet /opt/local/bin/convert och imagemagick_identify_path är /opt/local/bin/identify. På min maskin finns ingen av dem — /opt/local är MacPorts, som de flesta inte har; Homebrew lägger binärer i /opt/homebrew. Standardvärdet gör ingen skada om du inte slår på bildhämtning (enable_image_fetching är standardmässigt False, vilket är rimligt), men om du gör det i tron att toppbildsutvinningen ska fungera, är det här det tyst inte gör det.
Den antar engelska. target_language har standardvärdet en med use_meta_language=True, så den följer sidans egen deklaration när en sådan finns och faller tillbaka till engelska annars. Helt okej för engelskspråkigt material, men värt att sätta explicit för annat.
Resten är rimliga: parser_class är lxml, http_timeout 30 sekunder, strict på, log_level ERROR, parse_headers och keep_footnotes på, images_min_bytes 4 000.
Minne, och vad trasig HTML gör med det
Två saker som varje review i den här serien listade som otestade, nu uppmätta.
Det bredare stresstest-sammanhanget finns i jämförelsen av minne och felaktig HTML för tio bibliotek.
Maximalt resident minne, via /usr/bin/time -l, en färsk process per cell — importgolvet är vad biblioteket kostar laddat och vilande, topparna inkluderar dokumentet.
| 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- och Node-baslinjer går inte att jämföra direkt med varandra; tolken finns inuti båda.
goose3:s golv är 44,1 MiB och det toppar på 398,5 MiB på ett dokument på 10 MB. Dess importgolv är det tredje högsta bland Python-biblioteken som visas, vilket är värt att känna till i en distribution där kallstart spelar roll.
Trasig HTML. Tolv dokument där exakt en sak bryts vardera — icke-stängda taggar, felnästade inline-element, oquotade attribut med mellanslag, ensamma avslutare, ingen <html> alls, dubblettattribut, ett dokument avklippt mitt i en tagg, trasiga entiteter, ett oavslutat <script>, en lögnaktig charset-deklaration, en kommentar som innehåller markup och 600 nivåer av nästning — plus två välformade kontrollfall i matchande storlek, eftersom "det returnerade inget" bara säger något om trasighet om biblioteket inte också är tyst på ett rent dokument av samma storlek.
goose3 kastade inget undantag i 0 av 14 och returnerade inget i 10, samt återhämtade 2/33 sentinel-tokens över de trasiga testfallen (malformed-results.json). Ett testfall undantas från den siffran: enligt HTML5 är allt efter ett oavslutat <script> fortfarande scriptinnehåll, så att förlora det där är korrekt och att återställa det är avvikelsen.
För- och nackdelar
Fördelar. Noll märkta boilerplate-tokens över de tio testfallen för innehållstrohet där det faktiskt producerade output. Omkring tjugoåtta artikel-fält finns tillgängliga, även om deras korrekthet inventerades snarare än poängsattes. Rimligt standardval för bildhämtning (av). Ren installation på Python 3.14. Aktivt underhållet. Apache-2.0. Ett tomt resultat är lätt att stoppa när anroparen kontrollerar det explicit.
Nackdelar. Lägsta article recall i uppsättningen på 0,8243, helt drivet av att returnera ingenting alls snarare än att returnera fel sak. En sida vars artikel är en lista ger en tom sträng oavsett konfiguration. 44,3 MiB och 2,2 sekunders kall import är tungt jämfört med resiliparse:s 21,0 MiB och 15 ms. Kräver close(). Två standardvärden pekar på saker som är fel på de flesta maskiner.
Vem bör använda det, och vem bör inte
Använd goose3 som kandidat när den extraherade texten ska in i en modell eller databas där märkta boilerplate-delar är kostsamma och sidorna är konventionella artiklar med stycken. I den här testuppsättningen släppte det inte igenom några märkta boilerplate-tokens när det svarade. Metadataytan finns, men är inte validerad här; titel, författare, datum och bildkvalitet behöver separata ground-truth-testfall innan de blir ett urvalsskäl.
Skippa det om din korpus är listtung — du kommer att få tomma strängar utan förklaring. Skippa det om kallstarts-kostnaden spelar roll, där resiliparse importerar 145× snabbare. Och skippa det om du behöver svar på varje sida, eftersom "inget svar" är ett verkligt utfall här: två av 22 testfall, och båda tysta, i den meningen att en tom sträng inte är ett undantag.
En kombination värd att testa: goose3 som primärt val med en fallback när cleaned_text är tom eller understiger din minimi-regel för innehåll. Readability återhämtade varje artikel-enhet i den här uppsättningen med 22 testfall, inklusive båda goose3:s tomma fall. Det syntetiska resultatet stöder arkitekturmönstret, inte ett löfte om att fallback-alternativet aldrig missar på riktiga sidor.
Var en managed API passar in
Det här testet granskade goose3:s raw_html-väg: HTML hade redan hämtats innan goose3 såg den. goose3 har också sin egen nätverkshämtningsväg, vilket User-Agent-inställningen avslöjar, men den vägen testades inte här. JavaScript-rendering och anti-bot-beteende testades inte heller.
För samma testfall över alla sex extraktorer, se jämförelsen mellan sex bibliotek för extraktion.
En managed fetch/render/extraction-tjänst, inklusive vår egen Thunderbit, täcker ett annat ansvarsskikt. Thunderbit benchmarkades inte i det här testet. Den relevanta distinktionen är levererad HTML-artikelextraktion kontra en hostad tjänst som hämtar och bearbetar en URL; den här artikeln ger ingen jämförelse av prestanda eller kvalitet på samma mått.
Den rättvisa jämförelsen: goose3:s fältuppsättning är fast och artikel-formad, vilket är precis rätt när dina sidor är artiklar och fel när de är produktlistor. Om du redan har HTML:en och dina sidor är artiklar är goose3 gratis och väldigt ren.
För den hostade delen ger vår översikt över webbskrapnings-API:er en bredare bild; för självhämtade alternativ, öppen källkod-pelaren för scrapers. Om texten ska in i en modell täcker att konvertera HTML till Markdown i Python var kvalitet faktiskt går förlorad.
Testa Thunderbit för utvinning av webdata
Bör du använda goose3?
Ja, om artiklar formade som stycken matchar arbetslasten och anroparen behandlar tom output som ett misslyckat extraheringsförsök snarare än som ett lyckat resultat.
I den här testuppsättningen släppte goose3 inte igenom några märkta boilerplate-tokens när det svarade och returnerade två tomma strängar. Den ena var en nästan tom sida och den andra den syntetiska kroppen med enbart listor. Det är en avvägning mellan precision och täckning, inte bevis på en generell produktmentalitet.
Om recall är viktigare, testa en fallback med en explicit minimi-output-vakt. Readability återhämtade varje artikel-enhet i dessa 22 testfall; newspaper4k visade noll läckage av märkta boilerplate-enheter och 0,9865 i recall medan det producerade output på alla 22. De resultaten rangordnar den här syntetiska uppsättningen vid standardinställningar, inte okända produktionsarbetslaster.
goose3 förtjänar sin plats när kostnaden för ett fel ord är högre än kostnaden för en saknad sida.
Testa Thunderbit för utvinning av webdata Get Started Free
FAQ
Är goose3:s perfekta precision verklig, eller bara en effekt av att den avstod? Både och, och de två går att skilja åt. Det poängsattes på 10 av de 11 testfall som innehåller boilerplate, så ett testfall saknas i genomsnittet — det är delen som beror på att det avstod. Men på de tio returnerade det noll förorenande tokens trots medvetet adversarial boilerplate, där Readability läckte 35. Precisionen är verklig för sidor den svarar på; recall-kolumnen visar när avståendet inträffar.
Varför returnerar goose3 inget på en sida där artikeln består av en lista?
Dess kandidatpoängsättning behöver paragraf-liknande block för att hitta artikelkroppen, och en sida byggd av <li> har inga sådana. Standardinställningen parse_lists=True ändrar inte detta — jag testade den uttryckligen, plus strict=False, och fick noll tecken i alla tre konfigurationer medan en kontroll baserad på <p> gav 937 i alla tre. parse_lists avgör om listor behålls i en artikel som redan har hittats.
Måste jag anropa close()?
Stäng den explicit med try/finally, som visas ovan. Den här genomgången mätte inte vad som byggs upp när stängning utelämnas, så den påstår inte en kvantifierad loop-läcka; den fastslår däremot att Goose har en livscykel som anroparen måste hantera.
Vad skickar goose3 som User-Agent?
Goose/3.1.22 som standard — bibliotekets namn och exakta version. Det gäller bara när du låter det hämta själv, och att skicka raw_html kringgår det helt. Om du låter det hämta, sätt User-Agent medvetet; standardvärdet berättar exakt för varje server du träffar vad som anropar.
Vad testade den här genomgången inte?
Verkliga sidor alls — det här är kontrollerade testfall. Flerspråkig extraktion, trots att target_language är en förstklassig inställning. Metadatafälten (titel, författare, datum, toppbild) inventerades men poängsattes inte för korrekthet. Bildhämtning, som är av som standard och vars ImageMagick-sökvägar pekar på en pakethanterare som de flesta maskiner inte har. Samtidigt eller långvarigt minnesbeteende, plus throughput under belastning; minnestabellen mätte en färsk process som hanterade ett dokument.


