O limiar de jusText e o efeito penhasco em um conjunto de parágrafos curtos

Última atualização em August 17, 2026
O limiar de jusText e o efeito penhasco em um conjunto de parágrafos curtos
Resumo com IA
Em um documento cujo maior parágrafo tem 151 caracteres, o jusText, nas configurações padrão, retorna zero caracteres. Não é uma extração parcial — é uma string vazia. Reduza um único limiar até que exatamente um parágrafo o ultrapasse, e o mesmo documento passa a render 832 caracteres. Reduza mais e o resultado continua em 832. Neste conjunto, o comportamento é mais parecido com um penhasco do que com uma rampa. Se o padrão está do lado errado ou não depende do tamanho dos parágrafos e da distribuição de boilerplate no corpus de destino. Avalie o jusText para corpora multilíngues porque a superfície de stoplists específicas por idioma é explícita e ampla.

Em um documento cujo maior parágrafo tem 151 caracteres, o jusText, nas configurações padrão, retorna zero caracteres. Não é uma extração parcial — é uma string vazia. Reduza um único limiar até que exatamente um parágrafo o ultrapasse, e o mesmo documento passa a render 832 caracteres. Reduza mais e o resultado continua em 832.

Neste conjunto, o comportamento é mais parecido com um penhasco do que com uma rampa. Se o padrão fica do lado certo ou errado depende do tamanho dos parágrafos e da distribuição de boilerplate no corpus de destino.

O que é o jusText e por que a densidade lexical importa

Em comparação com os outros extratores deste conjunto de testes, o jusText depende de forma especialmente forte da densidade de stopwords específica do idioma. Um bloco com alta proporção de palavras funcionais — the, and, of, was — tem mais chance de ser prosa. Esse sinal lexical não é o único fator do classificador: comprimento do parágrafo, densidade de links, limites de bloco derivados do HTML, distância em relação a títulos, classes vizinhas e uma etapa sensível ao contexto também influenciam o resultado.

Referência oficial: repositório oficial do jusText.

System diagram: Two-Pass Paragraph Classification

Como o classificador usa uma lista de stopwords por idioma, o jusText vem com 100 delas. Essa superfície lexical explícita e específica por idioma é o que mais o diferencia nesta comparação, embora a qualidade em vários idiomas não tenha sido testada.

Versão testada: 3.0.2, BSD 2-Clause, 822 estrelas no GitHub. Python 3.14.2.

O penhasco, medido

Measured results chart: Characters returned as length_high changes

O classificador do jusText funciona em duas etapas. Uma passada sem contexto atribui a cada parágrafo os rótulos good, bad, short ou neargood. Depois, uma passada sensível ao contexto promove neargood para good — mas apenas quando ele fica ao lado de um bloco que já é good. E um parágrafo só recebe good por conta própria quando supera length_high, cujo padrão é 200 caracteres.

Em um documento em que nada ultrapassa 200, nada serve de semente para a promoção, e todo bloco neargood acaba degradado para boilerplate. A página inteira volta vazia.

Varri o limiar em um conjunto cujo maior parágrafo tem 151 caracteres:

length_highParágrafos classificados como goodCaracteres retornados
200 (padrão)00
1508832
1208832
1008832
808832

justext-length-threshold.json.

Neste conjunto, basta um parágrafo cruzar a linha para que todos os oito parágrafos-alvo passem a aparecer na saída; afrouxar mais o limite não adiciona nada. O traço observado é compatível com a etapa de contexto promovendo vizinhos neargood elegíveis ao redor de um bloco já marcado como good; isso não significa que todo vizinho em qualquer página seja promovido sem restrições.

Antes de atribuir a mudança a length_high, varri length_low em quatro valores combinados com max_link_density em dois: oito combinações, todas retornando zero. Alterar qualquer uma dessas configurações não recuperou saída neste conjunto.

No conjunto completo de 22 fixtures, o padrão se mantém: 2 de 22 produziram saída em length_high=200, 9 de 22 em 150, 15 de 22 em 120.

Duas coisas que isso não quer dizer. Não quer dizer que o jusText extrai mal — em uma página real em linguagem natural, nas configurações padrão, ele retornou 1.190 caracteres de texto limpo de artigo, porque um parágrafo real de notícia ultrapassa 200 caracteres logo de cara. E não quer dizer que o padrão esteja errado; quer dizer que o padrão assume parágrafos longos, e você deve verificar se o seu corpus tem esse perfil antes de rodar qualquer coisa.

O outro lado deste conjunto: mais vazamento nas configurações padrão

Neste conjunto rotulado, com as configurações padrão, o jusText apresenta o maior vazamento de boilerplate medido.

BibliotecaRecall do artigo (22/22)Vazamento de boilerplatePrecisão de tokens de conteúdoTokens contaminantes
Readability1.00000.23530.910935
trafilatura0.98650.05880.94114
newspaper4k0.98650.00000.94520
resiliparse0.90540.05880.93817
jusText0.83780.47060.876074
goose30.82430.00001.00000

sixway-scores.json. Um conjunto, um avaliador, e cada unidade marcada com um sentinela único para que a recuperação seja uma correspondência exata de substring.

System diagram: Leakage and Silence Share a Boundary

47% de vazamento de boilerplate e 74 tokens contaminantes — o dobro da taxa de vazamento do Readability e mais que o dobro da contaminação nesse conjunto sintético rotulado. Este é um resultado diagnóstico nas configurações padrão, não um ranking estável para o produto como um todo.

O vazamento observado é compatível com a mesma etapa de contexto envolvida no efeito penhasco. Blocos neargood elegíveis podem ser promovidos quando as classes vizinhas e as regras de distância permitem; um bloco com aparência de prosa ou um comentário ao lado do texto do artigo pode, portanto, atravessar a fronteira. O resultado do fixture mostra quais blocos rotulados vazaram, enquanto o mecanismo simplificado continua condicionado às regras exatas de contexto do jusText.

O recall observado é 0.8378, terceiro a partir do fim, e toda a perda vem do limiar: ele não recuperou nada em um artigo único de 129 caracteres, nada em uma página com dez parágrafos curtos e nada no documento quase vazio.

O inventário de stoplists por idioma

Noventa e nove outras stoplists.

justext.get_stoplists() retorna 100 idiomas. O classificador é parametrizado por idioma por design, e não pela tradução de uma heurística em inglês; trocar de idioma é só passar outro argumento:

import justext
paragraphs = justext.justext(html, justext.get_stoplist("Czech"))
text = "\n".join(p.text for p in paragraphs if not p.is_boilerplate)

trafilatura e goose3 também expõem comportamento ligado a idioma, mas esta análise não avaliou nenhum extrator com base em verdade-terreno fora do inglês. As 100 stoplists incluídas no jusText o tornam um candidato claro para avaliação multilíngue; o inventário, por si só, não prova qualidade de extração nesses idiomas nem mostra que os concorrentes cobrem esses casos pior.

A API são duas funções e nove constantes ajustáveis — length_low 70, length_high 200, stopwords_low 0.30, stopwords_high 0.32, max_link_density 0.20, max_heading_distance 200, além do tratamento de codificação. Pequena, legível e totalmente documentada na assinatura.

Instalação e velocidade

pip install justext puxa 3 pacotes — o menor número da comparação — e ocupa 22.4 MiB, em menos de dois segundos.

Referência oficial: jusText no PyPI.

BibliotecaPacotessite-packagesImportação a frioExtração p50
resiliparse521.0 MiB0.015 s0.06 ms
jusText322.4 MiB0.777 s0.56 ms
goose31644.3 MiB2.181 s1.85 ms
newspaper4k2247.5 MiB2.812 s2.69 ms
trafilatura1769.9 MiB1.584 s0.51 ms

install-and-import.json. Cada biblioteca em seu próprio virtualenv vazio.

Três pacotes e 22.4 MiB é uma dependência pequena nesta comparação, e a mediana de 0.56 ms por extração fica perto dos 0.51 ms do trafilatura neste ambiente de teste. A medição do ambiente não separa o tamanho do pacote por tipo de arquivo, então não dá para dizer quanto do espaço em disco vem das stoplists.

A questão da manutenção, respondida com cuidado

As métricas datadas de manutenção usadas aqui são o último envio ao repositório e o último lançamento no PyPI, ambos em 2025-02-25. Isso foi dezessete meses antes dos testes. Oito releases no total, 91 forks, 9 issues abertas, não arquivado.

Os classifiers do PyPI listam suporte a Python até 3.9. Eu o executei em 3.14.2 e ele instalou, importou em 0.777 s e extraiu em 19 de 22 fixtures sem uma única exceção.

Então os metadados estão cinco versões de Python atrás da realidade, e a realidade é que ele funciona. Essa é a distinção útil: um repositório silencioso é um sinal sobre suporte, não automaticamente sobre funcionamento. Para uma biblioteca cujo algoritmo inteiro é um método publicado em 2011 somado a listas de palavras, “acabado” é um estado plausível — não há muito mais o que mudar, e as stoplists não apodrecem como uma gambiarra contra bot.

O que um repositório silencioso realmente significa: se você encontrar um bug, vai estar corrigindo sozinho ou criando um fork. Compare isso com 9 issues abertas, que não é o perfil de uma biblioteca afogada em problemas sem resposta.

Memória e o que o HTML quebrado faz com ela

Duas perguntas operacionais são medidas separadamente aqui.

O contexto mais amplo do teste de estresse está na comparação de memória e HTML malformado entre dez bibliotecas.

Pico de memória residente, via /usr/bin/time -l, um processo novo por célula — o piso de importação é o custo da biblioteca carregada e ociosa; os picos incluem o documento.

BibliotecaRuntimePiso de importaçãoPico 226 KBPico 10 MB
html2textpython3.1418.719.971.2
pyquerypython3.1430.333.9172.5
resiliparsepython3.1420.525.1225.1
markdownifypython3.1423.928.9278.5
goose3python3.1444.152.4398.5
cheerionode2266.876.5398.5
justextpython3.1430.336.6431.2
newspaper4kpython3.1452.661.8668.5
trafilaturapython3.1452.564.8927.1
turndownnode2247.868.42947.1

memory-results.json. Baselines de Python e Node não são comparáveis entre si; o interpretador está dentro de ambos.

O piso do jusText é 30.3 MiB e o pico neste fixture de 10 MB é 431.2 MiB, cerca de 14.2 vezes o piso de importação e 43.1 vezes o tamanho da entrada em RSS absoluto. Um fixture e um processo não estabelecem uma curva geral de escalabilidade; os baselines de Python e Node também seguem sem comparação direta.

HTML quebrado. Doze documentos quebrando exatamente uma coisa cada — tags não fechadas, elementos inline mal aninhados, atributos sem aspas com espaços, fechamentos soltos, ausência total de <html>, atributos duplicados, um documento truncado no meio de uma tag, entidades inválidas, um <script> não fechado, uma declaração de charset mentirosa, um comentário contendo marcação e 600 níveis de aninhamento — mais dois controles bem formados com tamanhos equivalentes, porque “não retornou nada” só diz algo sobre malformação se a biblioteca também permanecer em silêncio em um documento limpo do mesmo tamanho.

O justext gerou exceção em 0 de 14 e não retornou nada em 13, recuperando 0/33 sentinelas pontuadas nos fixtures quebrados (malformed-results.json). O controle curto bem formado também retornou 0 caracteres; o controle longo bem formado foi o único resultado não vazio, com 1.333 caracteres. Os doze fixtures malformados permaneceram vazios, e o caso com <script> não fechado é excluído da pontuação de sobrevivência das sentinelas. Assim, esse lote mostra tolerância do parser — nenhuma exceção —, mas não permite atribuir o silêncio à malformação em vez do limiar de tamanho já medido.

Prós e contras

A favor. 100 stoplists por idioma, e um classificador realmente construído em torno delas, em vez de apenas traduzido para elas. O menor número de dependências da comparação, com 3 pacotes. 0.56 ms de extração mediana. Nove constantes de ajuste documentadas e legíveis. BSD 2-Clause. Roda limpo em Python 3.14 apesar dos classifiers pararem em 3.9.

Contra. O maior vazamento de boilerplate neste teste sintético nas configurações padrão: 47%, com 74 tokens contaminantes. O conjunto de parágrafos curtos retornou uma string vazia quando nenhum parágrafo ultrapassou length_high. O recall foi 0.8378 neste conjunto. O último push no repositório e o último release datam de dezessete meses antes dos testes, então a questão de manutenção precisa ser considerada.

Quem deve usar e quem não deve

Avalie o jusText para corpora multilíngues, porque a superfície de stoplists específicas por idioma é explícita e ampla. Este teste inventariou 100 stoplists, mas não mediu qualidade multilíngue. Ele também é candidato quando uma dependência de três pacotes e controles explícitos de limiar se encaixam no seu deployment.

Evite-o se você alimenta um modelo por token, porque 74 tokens contaminantes, contra zero no goose3 e no newspaper4k, viram custo direto. Evite-o em páginas com parágrafos curtos — textos promocionais, listagens, changelogs, FAQs — a menos que você tenha ajustado length_high de propósito. E evite-o se precisar de uma dependência ativamente mantida por exigência de compliance ou procurement, o que é uma restrição real mesmo quando o código funciona.

Se for usar, ajuste length_high com base em uma amostra de validação rotulada, em vez de copiar o padrão ou usar uma regra de percentil. Varra limiares plausíveis e meça tanto o recall do artigo quanto a precisão de boilerplate; baixar a barra pode recuperar prosa curta, mas também promover blocos vizinhos indesejados.

Onde uma API gerenciada faz sentido

O jusText trabalha com o HTML que você já tem, como tudo nesta comparação. Nenhuma dessas bibliotecas busca uma página, renderiza JavaScript ou lida com uma camada anti-bot.

Para os mesmos fixtures em todos os seis extratores, veja a comparação de extração entre seis bibliotecas.

Um serviço hospedado de busca/renderização/extração, incluindo o nosso Thunderbit, cobre uma fronteira de responsabilidade diferente. O Thunderbit não foi benchmarkado aqui. A distinção é entre classificar prosa a partir de HTML fornecido e um serviço que obtém e processa uma URL; este artigo não faz comparação de qualidade usando as mesmas métricas.

O enquadramento honesto: as stoplists multilíngues do jusText são uma capacidade real e gratuita. Se o seu problema é buscar páginas em vários idiomas, e não classificar a prosa dentro delas, isso é outra decisão de compra.

Para o panorama mais amplo, nosso resumo de APIs de web scraping cobre opções hospedadas, e o guia principal de scrapers open source cobre as alternativas self-hosted. Se a saída vai para um modelo, converter HTML em Markdown em Python é onde mais fidelidade se perde.

Experimente o Thunderbit para extração de dados da web

Você deve usar jusText?

Ele é um candidato se o corpus for multilíngue ou se a distribuição de comprimento dos parágrafos se beneficiar de ajuste explícito de limiar. Valide ambas as propriedades antes de colocar em produção.

As 100 stoplists incluídas são um recurso real de design, mas a precisão multilíngue não foi testada. O efeito penhasco do limiar é ajustável; se um valor menor é aceitável depende do recall e da precisão de boilerplate medidos em uma amostra rotulada.

Neste conjunto sintético em inglês, com as configurações padrão, o newspaper4k vazou zero unidades rotuladas de boilerplate e recuperou 0.9865 das unidades de artigo. Isso o torna um candidato de comparação para essa carga de trabalho, e não uma recomendação universal de substituição.

Experimente o Thunderbit para extração de dados da web Get Started Free

Perguntas frequentes

Por que o jusText retorna uma string vazia em vez de uma extração parcial? O classificador tem duas etapas. Um parágrafo só ganha a classe good por conta própria acima de length_high (padrão de 200 caracteres); a segunda etapa então promove blocos vizinhos neargood. Sem nenhum parágrafo acima do limiar, não há semente, então todos os candidatos viram boilerplate e o resultado fica vazio. É tudo ou nada por construção, não uma falha em encontrar uma resposta parcial.

O jusText está abandonado? O último push no repositório e o último release no PyPI foram ambos em 2025-02-25 — dezessete meses antes dos testes — e os classifiers do PyPI param no Python 3.9. Mas ele instalou e rodou em Python 3.14.2 sem exceção, e 9 issues abertas não configuram uma fila enorme. Leia essas datas como risco de manutenção, não como prova de comportamento quebrado; o risco prático é precisar corrigir seus próprios bugs.

Por que ele vaza mais boilerplate do que o Readability? Neste conjunto de fixtures, blocos vizinhos com aparência de prosa atravessaram a fronteira de saída sob as regras de contexto padrão. A promoção depende da classe do bloco, da distância e do contexto, e não acontece automaticamente para todo vizinho. O resultado medido foi 47% de vazamento de unidades de boilerplate e 74 tokens contaminantes nas configurações padrão.

Como uso isso para outro idioma? justext.justext(html, justext.get_stoplist("German")). get_stoplists() retorna todas as 100 disponíveis. A stoplist é a entrada lexical específica do idioma para um classificador que também usa comprimento do parágrafo, densidade de links, segmentação derivada do HTML, distância até títulos e contexto dos blocos vizinhos. Isso muda a entrada de idioma; por si só, não valida a qualidade de extração em alemão.

O que não foi testado aqui? Páginas reais, de forma alguma — estes são fixtures controlados com unidades rotuladas. A capacidade multilíngue, que é o principal diferencial da biblioteca, foi inventariada em 100 stoplists, mas não pontuada em texto fora do inglês. Casos-limite de codificação, apesar de o jusText expor os parâmetros encoding, default_encoding e enc_errors. E max_heading_distance e os dois limiares de proporção de stopwords foram mantidos nos padrões durante todo o teste.

Ke
Ke
CTO na Thunderbit | Cientista de Dados Sênior e Especialista em ML Com quase uma década de experiência em machine learning e data science, Ke Shen é ex-aluno da Columbia University e foi Cientista de Dados Sênior na Walmart Labs. Com profunda experiência, reconhecida pelos pares, em Python, R, Java e Estatística, ele compartilha insights testados em batalha sobre como levar algoritmos complexos de IA da teoria à arquitetura pronta para produção.
Sumário
Thunderbit · Agente de dados web com IA

Extraia dados de qualquer página em 1 clique

Aprovado por mais de 250.000 usuários
plano gratuito disponível
Da página web para a planilha
Descreva o que você precisa — o Agente de IA da Thunderbit extrai e exporta para Excel, Google Sheets, Airtable ou Notion. Comece grátis.
Chrome Store Rating
PRODUCT HUNT#1 Product of the Week