Mozilla's Readability é a versão JavaScript independente do extrator que alimenta o Reader View do Firefox. Publicado como pacote Apache-2.0 @mozilla/readability, ele seleciona o conteúdo do artigo a partir de um DOM em tempo real. No Node, portanto, ele precisa de uma implementação de DOM, como o jsdom. Ele não busca páginas, não executa JavaScript e não faz extração de esquema.
A versão testada foi a latest do npm em 0.6.0, publicada em 3 de março de 2025, com 11.361 estrelas no repositório quando consultei em 27 de julho de 2026 (último push em 9 de julho de 2026, então main está bem à frente do pacote publicado). Rodei o teste com jsdom 29.1.1 no Node v22.22.3, macOS arm64, contra 22 fixtures HTML rotuladas criadas para esse fim, e todas as medições aqui vêm dessa configuração. Na prática, é a ferramenta menos exigente desta categoria: dois minutos para instalar, sem binários, sem navegador preso em cache, e com saída idêntica em cada nova execução. O que a torna interessante não é operá-la — é que suas falhas são previsíveis a partir de algumas constantes no código, e uma dessas constantes decide mais do que a documentação deixa claro.
Em 22 fixtures sintéticas controladas, o Readability recuperou todos os 74 blocos de artigo rotulados. Esse resultado delimitado não significa que ele nunca perca texto de artigo: o benchmark público em páginas reais registra recall de 0,982, e certos formatos de falha conhecidos não apareceram aqui. A falha mais visível nas fixtures foi conteúdo extra de “irmãos” aceito por uma regra de densidade de links no código-fonte, fixada em 0,25. A gravidade aparente disso muda conforme o ambiente de teste.
O que o readability.js realmente é — e três coisas que ele não é
Readability é uma passagem de pontuação baseada em regras sobre um DOM. Ele percorre elementos candidatos, atribui a cada um uma pontuação de conteúdo, propaga essas pontuações para os ancestrais, escolhe a subárvore com maior pontuação e depois faz limpezas para remover o que parece ser a estrutura da página. Essa é toda a estratégia de extração de artigos — sem modelo, sem dados de treino, sem regras por site. Esse design é o motivo de funcionar em páginas que nunca viu — e também do fato de suas falhas serem previsíveis a partir do código-fonte, que é justamente a parte interessante.
Ele não é três coisas, e as três costumam confundir as pessoas:
- Não é um buscador de páginas. Ele recebe um
document, não uma URL. Busca, tentativas, anti-bot e cabeçalhos ficam por sua conta. - Não é um renderizador. Não executa JavaScript. O que estiver no DOM que você passar é o que ele enxerga.
- Não é um extrator estruturado. Você recebe
title,byline,excerpt,content(HTML),textContent,length,siteName. Nada de esquema, nada de linhas tipadas, nada de{name, price}.
Quatro constantes fazem a maior parte do trabalho

Ler Readability.js em node_modules conta mais sobre o comportamento do que qualquer página de documentação. Quatro peças de mecânica explicam a maior parte do que a biblioteca faz:
- Pontuação por parágrafo pontuado:
1 + (commaCount + 1) + min(floor(len / 100), 3). Parágrafos com menos de 25 caracteres nem entram na conta. As pontuações são propagadas aos ancestrais com divisores — o pai recebe a pontuação total, o avô metade, e ancestrais mais profundos recebemlevel · 3. DEFAULT_CHAR_THRESHOLD = 500— o comprimento mínimo do artigo para uma análise “bem-sucedida”. Abaixo disso, um filtro de remoção de flags refaz a captura com menos passagens de limpeza.- A regex de
unlikelyCandidates— casa trechos de class e id comocomment,footer,menu,related,sidebar,social,sponsor. Nós correspondentes são descartados antes da pontuação. - A regra de anexar irmãos em
grabArticle— depois que o melhor candidato é escolhido, seus irmãos são considerados para inclusão. Um irmão entra se sua própria pontuação ultrapassar o limite, ounodeLength > 80 && linkDensity < 0.25, ounodeLength < 80 && nodeLength > 0 && linkDensity === 0 && ele contém um ponto final.
A densidade de links é Σ(linkText.length · coef) / textLength, com coef = 0,3 para hrefs vazios # e 1 no restante. Essa regra explica os vazamentos de irmãos medidos aqui; ela não é o algoritmo completo de extração.
Configuração — e a dependência que não aparece no discurso
npm install @mozilla/readability jsdom e pronto, você já está rodando. Dois minutos, sem binários, sem download pós-instalação, sem navegador mantido em cache. No eixo da instalação, isso é quase ideal.
Mas “zero dependências” é uma afirmação sobre o algoritmo, não sobre o runtime. Readability opera sobre um document vivo e, no Node, isso significa que você mesmo fornece a implementação de DOM — aqui, jsdom 29.1.1. O jsdom não é pequeno e, na maioria dos fluxos, ele é o custo dominante do ciclo, não a extração. Planeje isso.
Mais uma armadilha que me custou uma nova execução: Readability.parse() modifica o DOM que recebe. Se você analisar o mesmo documento do jsdom duas vezes, a segunda chamada verá um documento que a primeira já desmontou. Cada parse no meu harness cria um jsdom novo. Se você estiver processando páginas em loop e reutilizando um objeto de documento para economizar tempo, esse é o bug que você está prestes a abrir.
Como eu testei
Eu não apontei isso para sites de notícias ao vivo. Páginas reais dão uma pontuação sem mostrar por que — e, em heurística, o “porquê” é justamente o valor central. Em vez disso, gerei 22 fixtures HTML contendo 91 blocos rotulados (74 de artigo, 17 de boilerplate), onde cada palavra de um bloco é prefixada pela string sentinela exclusiva daquele bloco. Os vocabulários entre blocos são disjuntos, então qualquer token extraído mapeia para exatamente um bloco, e “recuperado” ou “vazado” vira um teste exato de pertencimento, não uma correspondência aproximada.
A etapa de extração e a etapa de pontuação foram propositalmente separadas. O runner em Node emite apenas o texto bruto extraído, os booleanos de isProbablyReaderable e as densidades de link medidas. Toda a precisão e o recall são calculados depois, a partir desse texto bruto, contra os rótulos, por um script separado. Nenhuma constante de métrica foi escrita manualmente em qualquer parte do harness, que é a única forma de eu confiar nos próprios números.
Depois, alimentei os mesmos bytes no trafilatura 2.1.0 para um contraste no mesmo ambiente de teste. Cada fixture foi analisada três vezes; todas as 22 retornaram texto idêntico em bytes em cada execução.
Você pode inspecionar cada etapa em vez de confiar na tabela-resumo. tests/build_fixtures.mjs cria o HTML anotado e a verdade de referência; tests/run_readability.mjs registra a extração e a saída do preditor; e tests/metrics.py pontua esses registros depois do fato. A saída bruta do Readability, as métricas calculadas e a comparação com a mesma entrada estão preservadas em artifacts/raw/. Essa separação importa quando o resultado parece suspeito: você consegue dizer se o parser devolveu texto inesperado, se o conjunto de rótulos estava errado, ou se o código de pontuação classificou algo de forma equivocada. Reproduzir esse pacote valida as afirmações feitas aqui, mas continua sendo uma checagem do harness — não uma evidência de que um conjunto real de páginas em produção tenha a mesma distribuição de falhas.
A limitação de escopo é real e central: estas são páginas sintéticas controladas, não um corpus do mundo real. Os números autoritativos de páginas reais vêm do benchmark público article-extraction-benchmark, que avalia readability_js 0.6.0 — a mesma versão testada aqui — em word-F1 0,947 ± 0,005 (precision 0,914 ± 0,008, recall 0,982 ± 0,003) em cerca de 181 páginas reais. Eu cito isso; não reproduzi esse resultado.
Usaram-se aqui linhas do benchmark da versão atual; linhas históricas substituídas foram excluídas. As fixtures controladas acrescentam uma decomposição por bloco mostrando qual formato de conteúdo dispara qual regra, em vez de substituir o corpus público de páginas reais.
O recall foi perfeito no pacote sintético de fixtures
74 de 74. Em todas as 22 fixtures, o Readability não deixou escapar um único bloco de artigo rotulado — e, nas onze fixtures sintéticas limpas que misturavam artigo e boilerplate, o recall micro-averaged por token ficou em 1,000. Nenhuma frase de artigo sumiu.
Dois alertas se aplicam aqui:
Estas são páginas sintéticas limpas, de coluna única. Artigos reais costumam ter profundidade maior, anúncios intercalados no corpo e, às vezes, perdem o parágrafo de abertura por causa de um artefato de pontuação — essa classe de erro aparece no tracker (#437, #901, e perdas de conteúdo antes de tabelas em #922). Minhas fixtures não dispararam nenhum desses casos, então não estou dizendo que foram corrigidos — estou dizendo que meu teste não chegou até eles. Em páginas reais, o recall do benchmark para esta versão é 0,982, não 1,000.
Ainda assim, a direção do resultado é a parte útil. O problema do Readability não é jogar fora o artigo. É o que ele traz junto.
O número de precisão, e por que ele precisa de três rótulos

Um número é fácil de citar e difícil de defender. Nas onze fixtures mistas, o Readability manteve 5 de 17 blocos de boilerplate — uma taxa de vazamento de 0,294.
Isso não é uma taxa de vazamento do mundo real. Três configurações diferentes medem três coisas diferentes, e apenas uma delas descreve páginas comuns:
| O que o número está medindo | Resultado |
|---|---|
| Conjunto de fixtures ponderado de forma adversarial — 6 das 11 páginas mistas foram criadas para derrotar a regra dos irmãos | 5 de 17 blocos de boilerplate mantidos (0,294) |
A única página realista — corpo de <article> cercado por nav, banner de anúncio, sidebar, comentários, footer e mais uma promoção com classe neutra | 5 de 6 blocos de chrome removidos; 1 mantido |
| ~181 páginas reais, benchmark público (não é a minha execução) | precision 0,914, recall 0,982, word-F1 0,947 — readability_js 0.6.0 |
Leia a primeira linha como teste de estresse, não como previsão. O Readability não vaza 29% de boilerplate no uso real. Na página realista, tudo que carregava uma classe correspondente à regex de unlikelyCandidates — nav-menu, ad-banner, sidebar, comments, site-footer — foi removido corretamente, todos os cinco blocos. O único sobrevivente foi o bloco que eu projetei para driblar essa regex.
A barreira de 0,25: onde a remoção de boilerplate para
A regra de anexar irmãos está documentada no código-fonte. O que ninguém tinha medido, até onde encontrei, era exatamente onde ela vira. Então eu montei um gradiente: um <p class="teaser-block"> com classe neutra fora do <article>, um artigo decisivo de quatro parágrafos garantido como melhor candidato, e nada variando além do comprimento e da densidade de links da promoção. As densidades são calculadas com a própria fórmula do Readability, medidas em tempo de execução em vez de presumidas:
| Bloco promocional | Comprimento do texto interno | Acima de 80 caracteres | Densidade de links medida | Resultado |
|---|---|---|---|---|
| Sem links | 126 | sim | 0,000 | mantido |
| Um link curto | 126 | sim | 0,143 | mantido |
| Um link mais longo | 126 | sim | 0,278 | removido |
| Metade do texto com link | 126 | sim | 0,476 | removido |
| Uma frase única, terminando com ponto final | 60 | não | 0,000 | mantido |
| Mesmo texto, sem ponto final | 59 | não | 0,000 | removido |
A condição no código usa um limite de 0,25; as amostras medidas o enquadraram, com 0,143 mantido e 0,278 removido. Um ramo separado manteve uma frase de 60 caracteres terminada em ponto final e removeu a versão de 59 caracteres sem o ponto. O recall do artigo permaneceu 4/4 em cada braço, então essas amostras isolam um efeito de precisão.
Fora de um harness de teste, essa regra diz, na prática: prosa longa, neutra e com poucos links ao lado do artigo é artigo. Isso descreve muita coisa que não é o artigo — um texto de “leitura relacionada” escrito em forma de parágrafo, uma chamada de newsletter, uma nota do editor, um teaser patrocinado que uma equipe de marketing escreveu em frases completas com o link removido por motivos de rastreamento.
Em um índice de RAG, um parágrafo promocional com poucos links pode virar um chunk extraído e criar o risco de que a recuperação ou a geração o tratem como conteúdo do artigo. A regra do código torna esse modo de falha plausível; esta análise não executou uma avaliação completa de recuperação ou de citação por modelo.
Para um filtro rígido específico de site, faça pré-filtro de contêineres conhecidos no DOM de origem, preserve a ancestralidade do nó de origem para comparação antes da serialização, ou aplique depois uma filtragem de padrões de texto cuidadosamente validada. O HTML retornado sozinho talvez já não preserve se um nó originalmente estava fora do contêiner principal. A regra dos irmãos não pode ser ajustada pelas opções públicas.
Três pressupostos que as fixtures contrariaram
As fixtures contrariaram três pressupostos: que charThreshold rejeita artigos curtos, que tags semânticas são obrigatórias, e que conteúdo curto não em formato de prosa é removido. A evidência abaixo é a parte relevante; não é preciso nenhuma alegação de pré-registro.
charThreshold = 500 não é um abismo
A leitura popular é que um artigo com menos de 500 caracteres retorna null. Não retorna. Varri o comprimento do corpo de 120 a 1500 caracteres contra valores de charThreshold de 200, 500 e 1000:
| Comprimento do corpo | Parse bem-sucedido em todos os limites | Comprimento extraído |
|---|---|---|
| 120 | sim | 161 |
| 300 | sim | 342 |
| 460 | sim | 509 |
| 520 | sim | 569 |
| 800 | sim | 841 |
| 1500 | sim | 1555 |
Plano. Comprimento extraído idêntico nas três configurações de limite, em todos os tamanhos de corpo. O limite não bloqueia o valor de retorno — ele decide se a captura será refeita com flags de limpeza removidas e, numa página limpa, não há o que remover, então a peneira devolve o mesmo conteúdo de qualquer forma. O verdadeiro limite para null é “nenhum texto extraível”.
E isso produz a falha real aqui, e é pior do que um falso null. Dei a ele uma página quase vazia — uma barra de navegação e um resumo de quatro palavras. Ele retornou com sucesso, e o “artigo” devolvido incluía a navegação. Sem um artigo real, o Readability entrega boilerplate rotulado como artigo. Se você estiver rastreando em escala e tratando um resultado não nulo como “esta página tinha conteúdo”, essa suposição está errada.
Tags semânticas não fazem o trabalho sozinhas
Eu esperava queda de recall quando removi a estrutura. Mesmo texto de artigo, duas aparências: uma com <main><article><h1> e nomes de classe descritivos, outra com <div class="x1"> e parágrafos como <div> simples. Resultado: 4 de 4 blocos de artigo recuperados em ambas, zero boilerplate vazado em ambas. Quando o artigo é claramente o bloco de texto mais denso da página, a pontuação por comprimento e vírgulas o encontra sem ajuda semântica nenhuma. “Readability precisa de tags <article>” é folclore.
O limite honesto dessa afirmação: minha página tinha um bloco de conteúdo óbvio. Onde a semântica plausivelmente faria diferença é numa página com duas subárvores densas competindo entre si, e eu não testei esse desempate.
Conteúdo não em prosa sobrevive intacto
A regra de que “parágrafos com menos de 25 caracteres não entram na contagem” me fez esperar perdas em tabelas e legendas. Errado de novo — essa regra afeta a pontuação do candidato, não a retenção. Uma vez que o contêiner vence, tudo o que está dentro dele vem junto:
| Tipo de conteúdo dentro do artigo | Readability | trafilatura |
|---|---|---|
| Parágrafos em prosa (×2) | mantido | mantido |
| Células de tabela de dados (×2) | mantido | mantido |
Bloco de código <pre> | mantido | mantido |
| Parágrafo de uma linha com menos de 25 caracteres (×2) | mantido | mantido |
<figcaption> | mantido | removido |
| Total | 8/8 | 7/8 |
Esse é um eixo em que o limpador mais agressivo perde. Se suas páginas são documentação, tutoriais ou qualquer coisa com blocos de código e figuras legendadas, o comportamento do Readability de manter a subárvore vencedora inteira é uma vantagem.
isProbablyReaderable diz não quando parse() diz sim

O README sugere chamar isProbablyReaderable(doc) como uma verificação barata antes de investir num parse completo. Nos meus testes, essa barreira rejeitou três formatos de página que o parse() depois tratou sem problema:
| Formato da página | Veredito do preditor | parse() | Qual ajuste resolve |
|---|---|---|---|
Conteúdo apenas em elementos <li> | false | succeeds | nenhum — falso em todo minScore de 1–80 e em todo minContentLength de 40–200 |
| Dez parágrafos, todos com menos de 140 caracteres | false | succeeds | minContentLength ≤ 100 (minScore não faz nada) |
| Um parágrafo de 408 caracteres | false | succeeds | minScore ≤ 10 (a pontuação é ≈16,4) |
| Artigo normal (controle) | true | succeeds | — |
As três falhas têm três causas diferentes, e só duas são ajustáveis. O caso com <li> é estrutural: o preditor pontua apenas nós p, pre e article (mais pais de div > br), então uma página cujo conteúdo vive em itens de lista não corresponde a nada, recebe pontuação zero, e nenhum ajuste de limite recupera isso — um formato já relatado na issue #662. O caso de muitos textos curtos é uma barreira de minContentLength que ignora cada parágrafo antes da pontuação, então dez parágrafos substanciais somam zero; reduzir esse valor resolve, e ajustar minScore não resolve. O caso de um único parágrafo é aritmética: a pontuação é sqrt(408 − 140) ≈ 16,4, abaixo do minScore padrão de 20 — um parágrafo isolado precisa de 140 + 20² = 540 caracteres para passar sozinho.
O README de fato avisa que o preditor gera falsos negativos. O que eu acrescentaria é a regra prática: não use isso como único porteiro. Se uma página importa, faça o parse e verifique o tamanho do resultado. O parse não é tão caro em relação ao custo do jsdom que você já pagou.
Mesmos bytes, dois extratores
Rodar o trafilatura 2.1.0 sobre as mesmas fixtures dá uma leitura mais limpa do que alinhar dois números medidos em ambientes diferentes, porque a entrada é exatamente a mesma em bytes:
| Medida (11 fixtures mistas) | @mozilla/readability | trafilatura |
|---|---|---|
| Recall de blocos de artigo | 1,000 | 1,000 |
| Blocos de boilerplate mantidos | 5/17 (0,294) | 1/17 (0,059) |
| Token F1 (micro) | 0,948 | 0,969 |
| Recall de conteúdo não em prosa | 8/8 | 7/8 |
| Artigo muito curto (120 caracteres), token F1 | 0,800 | 0,571 |
Nenhuma das duas domina essas fixtures. O trafilatura reteve menos blocos irmãos, enquanto o Readability preservou mais conteúdo curto e não em prosa. A precisão absoluta por token das duas ferramentas é reduzida por texto de títulos não rotulado, então a contagem de vazamentos em nível de bloco é o sinal direto mais limpo. O benchmark público em páginas reais acaba ordenando o word-F1 de forma parecida, mas os corpora e métricas são diferentes, e isso não é validação cruzada entre ambientes.
Robustez, em resumo: rodei um gêmeo propositalmente malformado da página canônica (tag <p> sem fechamento, <b>/<i> aninhados de forma incorreta, um </div> sobrando) e o recall foi 3/3 com zero vazamentos, igual à versão bem formada. O crédito aí é do jsdom, cujo construtor de árvore HTML5 corrige a bagunça antes que o Readability a veja. Nenhuma fixture derrubou o parser.
Prós e contras
Prós
- O recall de artigo é o ponto forte: 74/74 blocos rotulados recuperados em 22 fixtures sintéticas, recall de token 1,000 no conjunto misto.
- A remoção de elementos de página classificados por regex funciona de forma confiável — nav, banner de anúncio, sidebar, comentários e footer desapareceram na página realista (5 de 6).
- Conteúdo não em prosa é totalmente retido: tabelas, código em
<pre>, legendas de figura e linhas com menos de 25 caracteres sobreviveram (8/8), enquanto o trafilatura removeu uma legenda. - Não depende de marcação semântica — um artigo neutralizado em
<div>teve a mesma pontuação que a versão com<article>/<main>. - Artigos curtos não são rejeitados incorretamente: conteúdo limpo recuperado até 120 caracteres, com resultado idêntico em
charThreshold200/500/1000. - Totalmente determinístico: todas as 22 fixtures retornaram texto idêntico em três execuções.
- Instalação em dois minutos, Apache-2.0, e a versão no npm é a mesma que testei (0.6.0), então nada aqui está desatualizado.
Contras
- A regra de anexar irmãos é explorável: prosa promocional longa, com poucos links e classe neutra, é indistinguível de texto de artigo e entra junto em
linkDensity < 0,25. - Em páginas com pouco conteúdo, ele retorna boilerplate como artigo em vez de
null— a fixture quase vazia voltou com a barra de navegação como corpo. isProbablyReaderableproduz falsos negativos em três formatos de página, e um deles não pode ser corrigido por ajuste nenhum.- Precisa de um DOM completo em runtime — a narrativa de “sem dependências” esconde o custo do jsdom, que domina o ciclo.
parse()modifica o documento de entrada, então você precisa reconstruir o DOM por página.- Sem busca, sem renderização de JavaScript, sem saída estruturada. É uma etapa de pipeline, não o pipeline.
- Perdas em páginas reais relatadas no tracker (parágrafo inicial e casos antes de tabela) não se reproduziram nas minhas fixtures, então não posso dizer se são raras ou se minhas páginas simplesmente nunca chegaram até elas.
Quem deve usar — e quem deve evitar
Vale usar Readability se você já tem o HTML em mãos e quer extrair o artigo em JavaScript puro, dentro de um serviço Node em que adicionar uma dependência Python seria incômodo. (Não coletei tempo como distribuição adequada, então não vou fazer nenhuma afirmação de velocidade além de “o build do jsdom domina o ciclo, não a extração”.) Recursos de modo leitura, arquivamento offline de artigos, newsletters por e-mail, botões de “clean view”, extensões de navegador, pipelines de documentação com blocos de código e legendas — esse é o território dele, e os números de recall mostram que é um bom território. O comportamento dele também pode ser lido diretamente no código-fonte, o que vale mais do que parece quando você precisa explicar para um colega por que um bloco específico passou.
Evite-o se a métrica principal for precisão na remoção de boilerplate, e especialmente se você estiver alimentando um índice para LLM onde um parágrafo promocional vira um chunk recuperável. Evite-o se suas páginas renderizam conteúdo no cliente, porque ele lê o DOM que você entregar e não executa JavaScript. Evite-o se o que você precisa é {title, price, sku} em vez de prosa — nenhuma configuração transforma um extrator de conteúdo em um extrator orientado a esquema. E se você estiver processando páginas em que “esta página tinha um artigo?” é uma pergunta real, não confie em um retorno não nulo como resposta.
Alternativas e onde entra a stack da Thunderbit
Nada aqui é uma crítica a uma biblioteca gratuita Apache-2.0 mantida pela Mozilla — Readability é infraestrutura, roda dentro do Firefox há anos e, para extração em modo leitura, é a implementação de referência por um motivo. Se você quiser o panorama mais amplo, mantenho uma comparação contínua no resumo de scrapers open source e uma visão mais abrangente em as melhores ferramentas de web scraping.
Para as mesmas fixtures em todos os seis extratores, veja a comparação de extração entre seis bibliotecas.
Nota do autor: Thunderbit é a nossa opção gerenciada para renderização e extração a partir de URL. Ela não foi executada nessas fixtures, então nenhuma equivalência de qualidade é sugerida. A fronteira relevante é: você já tem um DOM e quer extração local de artigo, ou quer busca/renderização e saída estruturada operadas como serviço? Auto-hospedar evita uma tarifa de uso de fornecedor, mas ainda traz custos de infraestrutura e manutenção.
O trade-off honesto: o Readability é gratuito, transparente e fica com você para executar — você pode ler a regra exata que decidiu sua saída, o que uma API gerenciada não entrega. Uma stack gerenciada custa dinheiro e oculta o mecanismo, mas cobre as etapas de busca, renderização e estruturação que você precisaria montar sozinho. Se quiser o lado assistido por IA desse espectro, escrevi sobre raspar qualquer site com IA e sobre crawlers de IA em outros textos. Escolha de acordo com as etapas que você realmente quer manter sob seu controle.
Experimente a Thunderbit para extração de dados da web
Veredito
Readability é uma boa opção quando você já tem um DOM, usa JavaScript/Node e prefere algum conteúdo extra de irmãos a omissões agressivas. Neste pacote de fixtures, ele recuperou todos os 74 blocos de artigo rotulados e reteve tabelas, código e legendas. Esse resultado é limitado por páginas sintéticas de coluna única; o recall real em páginas públicas é 0,982, certas perdas conhecidas em parágrafos iniciais/antes de tabela não foram reproduzidas, e páginas com pouco conteúdo podem devolver boilerplate como artigo.
Só dimensione corretamente a fraqueza. A principal superfície de falha nestas fixtures é a precisão, e ela está em uma linha específica e documentada do código-fonte: um irmão com mais de 80 caracteres e densidade de links abaixo de 0,25 é anexado ao artigo, quer faça parte dele ou não. Eu vi isso alternar entre 0,143 e 0,278 com o mesmo texto. O benchmark em páginas reais relata precision 0,914 e recall 0,982. Se você estiver jogando texto extraído em um índice que um modelo depois vai citar, inspecione tanto o boilerplate retido quanto o corpo omitido, em vez de assumir que qualquer uma dessas classes de erro está ausente.
Experimente a Thunderbit para extração de dados da web Get Started Free
FAQs
O Mozilla Readability remove todo o boilerplate?
Não, e o número depende muito do que você está medindo. No benchmark público de páginas reais, readability_js 0.6.0 marca precision 0,914 — então cerca de 8,6% do que retorna não é conteúdo do corpo. Em uma página realista do meu teste, ele removeu 5 de 6 blocos de chrome (nav, anúncio, sidebar, comentários e footer sumiram), mantendo apenas um parágrafo promocional com classe neutra. Em um conjunto de fixtures ponderado de propósito com blocos criados para derrotar a heurística, ele manteve 5 de 17 — esse último número é um teste de estresse, não uma taxa real.
Preciso de jsdom para usar readability.js no Node?
Sim, ou alguma outra implementação de DOM. O Readability é JavaScript puro, mas opera sobre um objeto document vivo, então no Node você fornece o DOM por conta própria — no meu setup, jsdom 29.1.1. A descrição “sem dependências” se refere ao algoritmo, não ao runtime. Observe também que parse() modifica o documento recebido, então construa um DOM novo para cada página, em vez de reutilizar um só.
O que a opção charThreshold realmente faz?
Não é o que a maioria imagina. Ela não faz artigos curtos voltarem null — eu recuperei artigos limpos até 120 caracteres, com comprimento extraído idêntico em charThreshold de 200, 500 e 1000. O limite controla se o parser refaz a captura com flags de limpeza removidas; numa página limpa não há nada a remover, então a saída é a mesma de qualquer jeito. O verdadeiro caso de null é uma página sem texto extraível, e até uma página só com navegação voltou não nula, devolvendo a navegação como artigo.
Devo chamar isProbablyReaderable antes de parse()?
Use como indício, não como porta de entrada obrigatória. Ele retornou false em três formatos de página que o parse() depois processou com sucesso: conteúdo apenas em elementos <li>, dez parágrafos com menos de 140 caracteres cada, e um único parágrafo de 408 caracteres. O caso com <li> não pode ser corrigido por ajuste, porque o preditor só pontua nós p, pre e article; o caso de muitos textos curtos precisa de um minContentLength menor; o caso de um único texto longo precisa de um minScore menor, já que um parágrafo isolado precisa chegar a 540 caracteres para passar do padrão. Se a página importa, faça o parse e verifique o resultado.
Readability ou trafilatura para extração de artigos?
Em bytes idênticos de fixtures, o trafilatura manteve menos boilerplate (1/17 blocos contra 5/17), enquanto o Readability recuperou mais conteúdo curto e preservou um <figcaption> que o trafilatura removeu. Escolha de acordo com tolerância a erro e runtime. O benchmark público é um contexto separado, não validação deste resultado de fixtures.


