Cheerio Review: Desempenho, Memória e Tratamento de HTML Quebrado

Atualizado em August 19, 2026
Cheerio Review: Desempenho, Memória e Tratamento de HTML Quebrado
Resumo com IA
Este artigo compara o cheerio com parsers Python em páginas de 1 KB a 10 MB, mostrando que ele é competitivo em tamanhos pequenos, mas fica muito mais lento em documentos grandes. Também avalia uso de memória, comportamento com HTML quebrado, prós e contras, e quando faz sentido optar por uma API gerenciada como o Thunderbit.

Em uma máquina, o cheerio no Node analisou e extraiu títulos e hrefs de um documento HTML sintético de 10 MB em 2.927,89 ms. O selectolax, rodando no CPython com um parser em C, concluiu a mesma extração de campos em 158 ms. Os títulos ordenados e os hashes dos hrefs bateram exatamente. Esta é uma comparação ponta a ponta entre stacks e runtimes, não um veredito isolado sobre o algoritmo de parsing.

Em uma página de 10 KB, a diferença é de 2× e ninguém notaria. A questão real é em que ponto as suas páginas caem nessa curva.

O que é o cheerio

O cheerio é o parser HTML com sintaxe de jQuery para Node, e por um bom motivo é a resposta padrão nesse ecossistema: 30.449 estrelas no GitHub, licença MIT e um push no repositório no dia anterior ao teste. Versão testada: 1.2.0.

Referência oficial: introdução oficial do Cheerio.

import * as cheerio from "cheerio";
const $ = cheerio.load(html);
const titles = $("h3.title").map((_, e) => $(e).text()).get();
const hrefs = $("a").map((_, e) => $(e).attr("href")).get();

Se você já usou jQuery, já conhece a API. Essa familiaridade é uma das principais razões pelas quais ele ganhou espaço no seu ecossistema.

Por trás dos panos, não é um único parser, mas uma pilha: htmlparser2 e parse5 para parsing, domhandler e domutils para a árvore, cheerio-select para seletores, além de undici, encoding-sniffer e outros — onze dependências diretas, que viram 22 pacotes de nível superior e 9,0 MiB em disco. Esses pacotes trazem recursos de parsing e codificação, mas também aumentam a pegada de dependências. Esta análise testou a saída diante de entrada malformada, mas não testou a correção de encoding nem isolou qualquer um dos backends de parser.

A medição e por que ela é confiável

A base de pesquisa já tinha um benchmark de parser: cinco tamanhos de página de 1 KB a 10 MB, 50 iterações, três execuções independentes e — o ponto mais importante — uma barreira de paridade que faz hash do conteúdo extraído, títulos ordenados mais hrefs ordenados, contra um parser de referência. Um parser que apenas “pula trabalho” não consegue marcar tempo rápido.

Adicionar o cheerio a esse conjunto exigiu duas checagens antes que qualquer número valesse.

O ponto de referência continuou no mesmo lugar? O selectolax foi rodado de novo na mesma sessão, com os mesmos fixtures. O hash do conteúdo foi reproduzido em 5 de 5 tamanhos, e seu p50 ficou entre 0,989× e 1,079× do valor publicado. Então, esta é a mesma máquina que gerou a tabela original.

O cheerio produziu os mesmos campos pontuados? O hash do conteúdo — calculado no Node com a mesma regra, SHA-256 sobre o texto dos títulos ordenados e os hrefs ordenados — coincidiu com o de referência em 5 de 5 tamanhos. Isso comprova paridade para esses campos ordenados nesses fixtures, e não para a forma do DOM, ordem do documento, atributos, normalização de texto ou recuperação de erros.

Só depois disso os tempos passam a significar alguma coisa.

Tamanho da páginaselectolaxlxmlPyQuerycheerio (Node)cheerio vs selectolax
1 KB0,0286 ms0,05080,04560,1147 ms4,0×
10 KB0,1725 ms0,18020,17280,3490 ms2,0×
100 KB1,4855 ms1,41451,40933,8399 ms2,6×
1 MB14,97 ms15,0314,9659,37 ms4,0×
10 MB158,10 ms165,25162,862.927,89 ms18,5×

p50 em milissegundos, mediana de três execuções. parser-bench.json. Os três parsers em Python foram executados em um processo; o cheerio rodou no Node 22, que também é uma fronteira de runtime, além de uma fronteira de biblioteca — veja abaixo.

Lendo essa tabela com honestidade

Measured results chart: Parser time across page sizes

A linha de 1 KB é ruído. Entre os três parsers em Python, a variação nesse tamanho foi de 77,6%, e as execuções individuais se sobrepuseram bastante — o selectolax variou de 0,0267 a 0,0404 ms nas três rodadas. Em 28 microssegundos, a resolução do timer e o escalonamento do sistema dominam. Eu não classificaria nada em 1 KB, incluindo o cheerio.

O meio da tabela não é nada de especial. De 2× a 4× em páginas entre 10 KB e 1 MB. Para um scraper que processa algumas centenas de páginas, isso significa 45 milissegundos por página em vez de 15, e você nem percebe.

A linha de 10 MB não é ruído. As três execuções do cheerio ficaram em 2.839, 2.928 e 2.954 ms — consistentes e claramente separadas das demais linhas. O resultado ponta a ponta em 10 MB se afasta muito do padrão observado nos tamanhos menores. Cinco pontos de tamanho não bastam para estabelecer complexidade assintótica nem para descobrir qual camada — runtime, parser, seletor, alocação ou garbage collection — provoca esse salto.

Ele cai na faixa do BeautifulSoup. O benchmark publicado mediu mais quatro parsers no mesmo fixture de 10 MB, e colocar os 2.927,89 ms do cheerio ao lado deles é a parte mais útil deste artigo:

Parser (10 MB)p50
selectolax (lexbor)159,93 ms
lxml172,93 ms
parsel231,85 ms
selectolax (modest)247,95 ms
BeautifulSoup + lxml2.261,56 ms
BeautifulSoup + html.parser2.788,75 ms
cheerio2.927,89 ms

As quatro linhas em Python são os valores publicados de bench_parse.json; o do cheerio vem desta execução. O parser de referência se reproduziu entre 0,989× e 1,079× nas duas execuções, então trate diferenças menores que cerca de 8% como parte dessa incerteza — cheerio contra o backend html.parser do BeautifulSoup (diferença de 5%) está dentro disso; cheerio contra selectolax (18×) não está.

O BeautifulSoup é a biblioteca a que as pessoas recorrem quando querem praticidade e aceitam conscientemente que ela seja lenta — é a que toda discussão de performance em Python recomenda substituir. Em um documento de 10 MB, o cheerio fica na base dessa mesma faixa, e não na faixa dos parsers com backend em C com os quais costuma ser comparado.

A questão da substituição do lado do Node continua em aberto neste artigo. Alternativas mais novas para Node não foram testadas, então este resultado não pode dizer que trocar de biblioteca seja impossível nem descartá-las como menos consolidadas. Ele só mostra o caminho medido do cheerio em comparação com as stacks Python listadas.

Esta também é uma comparação de runtime, não só de biblioteca. Os milissegundos do cheerio vêm do JIT e do garbage collector do Node; os demais vêm do CPython chamando parsers com backend em C. O hash do conteúdo prova que o mesmo trabalho foi feito, e ambos os números são o que um desenvolvedor realmente sente ao escolher uma stack — mas ninguém deveria ler isso como “o algoritmo do cheerio é 18× pior que o do selectolax”. É o que aconteceu, nesta máquina, em cada runtime nativo de cada biblioteca.

A realidade da configuração

BibliotecaPacotesDiscoLicençaEstrelasÚltimo push
cheerio22 (npm)9,0 MiBMIT30.4492026-08-11
PyQuery3 (pip)20,1 MiBBSD2.3802026-07-27

Referência oficial: documentação de configuração do Cheerio.

metadata-snapshot.json, coletado no dia da redação.

npm install cheerio levou menos de dois segundos e baixou 9,0 MiB. A importação a frio mediu 0,056 s em uma execução separada de conversão na mesma máquina.

Onze dependências diretas é bastante coisa para um parser, e vale a pena saber disso se você audita sua árvore: htmlparser2, parse5, parse5-htmlparser2-tree-adapter, parse5-parser-stream, domhandler, domutils, dom-serializer, cheerio-select, encoding-sniffer, undici e whatwg-mimetype. Duas implementações completas de parser vêm incluídas aí, porque o cheerio pode usar qualquer uma delas dependendo do que você pedir.

Trinta mil estrelas e um push no dia anterior ao teste são sinais de manutenção tão saudáveis quanto se pode esperar nessa categoria.

Memória e o que HTML quebrado faz com ela

A pegada de memória e o comportamento diante de HTML malformado afetam implantação e tratamento de falhas, então ambos são medidos separadamente aqui.

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

Memória residente de pico, via /usr/bin/time -l, com 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 em 226 KBPico em 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. As linhas de base de Python e Node não são comparáveis entre si; o interpretador faz parte de ambos.

O cheerio tem o maior piso de importação nesta tabela mista em 66,8 MiB, incluindo o runtime Node e as dependências. Seu processo atingiu 398,5 MiB no fixture de 10 MB. As outras linhas incluem parsers, conversores e extratores de artigo fazendo trabalhos primários diferentes, então use-as como contexto de pegada de processo, e não como rankings de desempenho entre pares. A linha do turndown no mesmo runtime chegou a um pico bem maior, mas ele faz conversão, não o contrato de seleção de títulos e hrefs medido para o cheerio.

HTML quebrado. Doze documentos, cada um quebrando exatamente uma coisa — tags não fechadas, elementos inline mal encaixados, 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> sem fechamento, uma declaração de charset mentirosa, um comentário contendo markup e 600 níveis de aninhamento — além de dois controles bem formados em tamanhos equivalentes, porque “não retornou nada” só diz algo sobre malformação se a biblioteca também não ficar em silêncio em um documento limpo do mesmo tamanho.

O cheerio lançou exceção em 0 de 14 e não retornou nada em 0, recuperando 11/22 sentinelas pontuadas nos fixtures malformados (malformed-results.json). Para parsers, o avaliador verifica sentinelas de heading e link em onze documentos malformados pontuáveis; ele não pontua a sentinela de parágrafo, e o fixture com <script> sem fechamento é excluído. Sem uma linha de base com o mesmo contrato nesta seção, 11/22 não é um ranking de qualidade. A conclusão suportada é que o cheerio retornou saída não vazia sem lançar exceção em todas as quatorze entradas malformadas e de controle, recuperando metade dos marcadores pontuados.

Prós e contras

A favor. Sintaxe familiar de jQuery. MIT. Um sinal de manutenção com timestamp de 30.449 estrelas e atividade no repositório no dia anterior ao teste. Dois backends de parser e pacotes relacionados a codificação estão presentes, embora a recuperação entre backends e a precisão de encoding não tenham sido isoladas aqui. O hash de títulos mais hrefs ordenados coincidiu com a referência em todos os tamanhos de fixture.

Contra. 18,5× mais lento que o selectolax em um documento de 10 MB, e 4× em 1 MB. Onze dependências diretas, incluindo duas implementações completas de parser. Apenas Node. E nada na documentação sugere um tamanho a partir do qual ele deixe de ser a escolha óbvia.

Quem deve usar e quem não deve

Use o cheerio se você está em Node, a API no estilo jQuery é valiosa e as páginas representativas se aproximam dos tamanhos testados até 1 MB. Um megabyte é o maior ponto testado antes do salto acentuado em 10 MB; este artigo não estabelece o limite entre eles nem afirma quanto da web fica abaixo dele.

Faça benchmark antes de usar para documentos HTML muito grandes, como relatórios gerados, dumps de catálogo ou páginas longas de listagem. O comportamento com XML sitemap não foi testado. No fixture HTML de 10 MB, 2,9 segundos por documento é um custo relevante que se acumula.

Se você está em Python, esta comparação diz outra coisa: selectolax, lxml e PyQuery ficam efetivamente empatados de 10 KB para cima (dentro de 0,5% a 5,4%, com intervalos de execução sobrepostos), então escolha pela API, não pela velocidade. A diferença do cheerio para os três é o número interessante, não as diferenças entre eles.

Onde entra uma API gerenciada

O cheerio analisa HTML que você já possui. Ele não busca a página, não renderiza JavaScript e não lida com camadas anti-bot — e, em muitos alvos reais, essa é a metade mais difícil do trabalho.

Um serviço gerenciado de fetch/render/extraction, incluindo o nosso Thunderbit, fica em uma fronteira de responsabilidade diferente. O Thunderbit não foi benchmarkado aqui. A distinção relevante é entre analisar HTML fornecido com seletores e terceirizar aquisição, renderização e extração; este artigo não oferece comparação de qualidade, latência ou custo na mesma métrica.

A leitura justa é: se você já tem o HTML e conhece seus seletores, o cheerio é gratuito e agradável de usar. Se você está buscando páginas em escala, ou prefere descrever os dados em vez do DOM, isso é outra compra.

Para uma visão mais ampla, nosso resumo de APIs de web scraping cobre opções hospedadas e o pilar de scrapers open source cobre as opções auto-hospedadas. Se a saída analisada vai para um modelo, converter HTML para Markdown em Python mostra onde a fidelidade se perde.

Experimente o Thunderbit para Extração de Dados da Web

Vale a pena usar cheerio?

Sim, em Node, quando a compatibilidade da API importa e os documentos representativos ficam próximos da faixa pequena até 1 MB testada.

A familiaridade da API e os sinais atuais de manutenção são critérios legítimos de seleção. O benchmark não prova que exista uma resposta de suporte específica nem que a distribuição de tamanhos das páginas testadas corresponda a um corpus de produção.

O número que vale guardar é o de 10 MB. Em algum ponto entre 1 MB e 10 MB, o custo do cheerio deixa de acompanhar os outros e passa a multiplicar — 4× vira 18,5×. Se o seu corpus inclui documentos desse porte, faça benchmark antes de se comprometer, porque nada na biblioteca vai avisar você.

Experimente o Thunderbit para Extração de Dados da Web Get Started Free

Perguntas frequentes

Comparar cheerio com parsers Python é justo? É uma comparação de stacks, não de algoritmo. Os quatro produziram exatamente o mesmo texto de título ordenado e hrefs sob a regra de hash em 5 de 5 tamanhos de página. Isso não prova equivalência total entre parsers. Os tempos do cheerio incluem o comportamento do runtime Node, enquanto os outros incluem o CPython chamando parsers com backend em C; a comparação descreve essas escolhas ponta a ponta.

Por que a linha de 1 KB não é classificada? Porque, em 28 microssegundos, a medição é dominada por ruído. Nas três execuções, os parsers em Python variaram 77,6%, com sobreposição entre as execuções individuais. Qualquer ordenação nesse tamanho seria um artefato. A partir de 10 KB a leitura já fica estável o bastante.

O que causa o salto em 10 MB? Este teste não diz. O que ele estabelece é que o salto é real e não ruído: as três execuções do cheerio ficaram em 2.839, 2.928 e 2.954 ms, bem separadas de todo o resto, enquanto a diferença em 1 MB era de 4×. Isolar a causa exigiria perfilar separadamente os backends do parser do cheerio, o que ficou fora do escopo aqui.

Quantas dependências ele realmente tem? Onze diretas, 22 pacotes de nível superior após resolução e 9,0 MiB em disco. Duas delas são implementações completas de parser — htmlparser2 e parse5 — porque o cheerio pode usar qualquer uma. Esse é o preço de dar suporte tanto ao parsing tolerante quanto ao parsing alinhado à especificação, e vale a pena saber disso ao auditar árvores de dependência.

O que não foi testado aqui? Os testes cobriram o pico de memória do processo em um documento de 226 KB e outro de 10 MB, além de um conjunto de 14 entradas malformadas e de controle em que o cheerio não lançou exceção, retornou saída não vazia em todas e recuperou 11/22 sentinelas pontuadas. Não foram cobertos streaming via parse5-parser-stream, correção de encoding, recuperação específica de backend, a localização do salto de performance entre 1 e 10 MB, parsing de XML ou alternativas mais novas para Node.

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.
Topics
Web Scraping ToolsAI Web Scraper
Índice
Thunderbit · Agente de dados web com IA

Extraia dados de qualquer página em 1 clique

Confiado por mais de 250.000 usuários
plano grátis 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