Como montar um screener da B3 com dados do Fundamentus (duas URLs e uma tabela HTML)
Quem faz análise fundamentalista na B3 vive dentro de screener de terceiros. E na
hora de levar o dado cru para a sua planilha, o seu backtest ou o seu modelo,
esbarra sempre no mesmo trio: export limitado, filtro atrás de assinatura, ou
copiar-colar célula por célula. O dado em si — indicador fundamentalista de empresa
listada — é público na origem. O que falta é um jeito programático de pegá-lo.
Existe um, e é mais simples do que parece. O Fundamentus, um dos sites mais antigos
de análise fundamentalista do Brasil, publica o mercado inteiro em duas páginas HTML
— uma tabela cada, sem login, sem paginação e sem anti-bot:
https://www.fundamentus.com.br/resultado.php ← todas as ações
https://www.fundamentus.com.br/fii_resultado.php ← todos os FIIs
Um GET em cada e você tem, na contagem de hoje, 987 ações e 552 FIIs com os
principais indicadores por linha. Este artigo mostra como transformar essas duas
tabelas num screener de verdade — incluindo as três pegadinhas de parsing que fazem
a maioria dos scripts falhar na primeira tentativa — e o que dá (e o que não dá)
para fazer com esse dado.
O que vem em cada tabela
Ações (resultado.php) — por papel: cotação, P/L, P/VP, PSR, dividend
yield, P/Ativo, P/Capital de Giro, P/EBIT, P/Ativo Circulante Líquido, EV/EBIT,
EV/EBITDA, margens (bruta, EBIT, líquida), liquidez corrente, ROIC, ROE,
liquidez em bolsa (2 meses), patrimônio líquido, dívida bruta/patrimônio e
crescimento de receita em 5 anos.
FIIs (fii_resultado.php) — por fundo: segmento, cotação, FFO yield, dividend
yield, P/VP, valor de mercado, liquidez, quantidade de imóveis, preço do m²,
aluguel por m², cap rate e vacância média. Esse bloco imobiliário (cap rate,
vacância, m²) é o tipo de coluna que raramente aparece de graça numa tabela única em
outro lugar.
As três pegadinhas de parsing
Se você fizer um fetch ingênuo, vai tropeçar em três coisas — todas contornáveis
em uma linha cada:
1. O encoding é ISO-8859-1, não UTF-8. O Fundamentus é um site antigo e serve
Latin-1. Se você decodificar como UTF-8, todo acento vira lixo (Consticssãoo).
Em shell, resolve com iconv; em Node, decodifique o buffer com latin1:
curl -s -H "User-Agent: Mozilla/5.0" \
"https://www.fundamentus.com.br/resultado.php" \
| iconv -f ISO-8859-1 -t UTF-8 > acoes.html
2. Os números vêm em formato pt-BR. 1.234.567,89 usa ponto de milhar e vírgula
decimal; percentuais vêm como 12,34%; valor ausente é -. A normalização é:
remover % e espaços, remover os pontos, trocar vírgula por ponto, e tratar -
como nulo. Sem isso, Number("2,90") vira NaN e seu filtro de P/L silenciosamente
descarta o mercado inteiro.
3. Mande um User-Agent de navegador. Requisição sem UA (ou com UA de script) tem
chance de voltar bloqueada. Um UA de Chrome comum resolve — está no exemplo acima.
Um quarto detalhe que economiza dor de cabeça: não mapeie as colunas pelo texto do
cabeçalho (que tem acento e sofre com o encoding); mapeie por posição. E para
separar linha de dado de linha de cabeçalho/rodapé, o padrão do ticker é um filtro
excelente: a primeira célula de toda linha válida casa com ^[A-Z]{4}\d{1,2}$
(PETR4, MXRF11, TAEE11). Tudo que não casa, descarta.
O que dá pra filtrar (exemplos, não recomendações)
Com o mercado inteiro numa estrutura de dados, screening vira uma expressão booleana.
Três exemplos clássicos, citados aqui como fórmulas conhecidas da literatura — não
como recomendação de investimento:
- Corte de liquidez primeiro.
liquidez_2meses > 200000elimina papel que não
negocia — sem esse corte, todo screener devolve uma lista de micos ilíquidos com
indicadores lindos e spread impraticável. - Estilo Graham:
p_l > 0 AND p_vp > 0 AND p_l * p_vp <= 22.5(o clássico
"número de Graham" combinando preço/lucro e preço/patrimônio). - Renda com FIIs, estilo Bazin:
dividend_yield >= 6 AND p_vp <= 1.05 AND vacancia_media < 10 AND liquidez > 100000— yield com teto de preço sobre
patrimônio e vacância controlada.
Rodando isso numa planilha, num script ou num notebook, você tem em segundos o que
levaria uma tarde de cliques — e com a régua sua, documentada, reproduzível.
O que esse dado NÃO é (leia antes de usar)
- Não é tempo real. A cotação do Fundamentus vem com atraso — serve para
screening e estudo, não para decisão intradiária. - Fundamento reflete o último balanço. P/L, ROE, margens etc. são calculados
sobre os últimos demonstrativos publicados pela empresa — entre um trimestre e
outro, o indicador não se move com a notícia de ontem. - É um site de terceiro, não uma API oficial da B3. A tabela é HTML e pode mudar
de layout sem aviso. O contrato não é garantido — é estável há anos, mas trate
como scraping, com validação no parse. - Indicador calculado tem metodologia. O número que aparece é o cálculo do
Fundamentus. Para decisão séria, confira o dado na fonte primária (release/CVM). - Nada aqui é recomendação de investimento. É encanamento de dados.
Se você não quiser escrever o parser
Empacotei exatamente esse fluxo — fetch com UA correto, decode Latin-1, parse por
posição com o regex de ticker, normalização pt-BR → número JS — num Apify Actor:
brazil-b3-screener. Você
escolhe stocks, fiis ou both (e opcionalmente uma lista de tickers), e ele
devolve o mercado como JSON/CSV/Excel, com API e MCP para chamar de um agente de IA,
e agendamento para rodar todo dia antes do pregão. Custa $0.002 por ativo
retornado e run que não retorna nada custa zero.
Mas as duas URLs são públicas e o parsing está descrito acima inteiro — se você só
precisava saber que elas existem, boa planilha. Esse era o ponto do artigo.