A extração de dados da internet costuma ser associada ao Python ou a serviços especializados. Mas, se os dados devem terminar direto em uma tabela, ser calculados com fórmulas e apresentados aos colegas, o Excel com VBA continua sendo um dos caminhos mais rápidos para chegar ao resultado. Não é preciso instalar um interpretador, configurar um ambiente nem explicar à contabilidade o que é pip install. Abra a pasta de trabalho, aperte um botão — e os dados estão na planilha.
Neste artigo destrinchamos como funciona o scraping com VBA: que objetos usar para as requisições HTTP, como parsear HTML e JSON, como despejar o resultado nas células e como não esbarrar em um bloqueio. Os exemplos são funcionais: você pode copiá-los no editor de VBA e executá-los.
Quando Excel e VBA são uma boa escolha
Vale a pena recorrer ao VBA quando:
- o resultado vai viver de qualquer forma no Excel (um relatório, um painel, um registro de cotações);
- o volume de dados é pequeno ou médio — dezenas ou milhares de linhas, não milhões;
- é preciso uma automação «de um botão» para pessoas sem conhecimentos de programação;
- a fonte entrega os dados por meio de uma requisição HTTP simples ou de uma API aberta.
Se o que está em jogo é escala séria, contornar proteções complexas de JavaScript ou disparar requisições em paralelo, é melhor olhar para o Python (requests, BeautifulSoup, Playwright). Nesse tipo de tarefa, o VBA bate no teto rapidamente.
As ferramentas dentro do VBA
Para fazer scraping em VBA existem alguns «motores» principais:
| Objeto | Função | Quando aplicar |
|---|---|---|
MSXML2.XMLHTTP / ServerXMLHTTP |
Requisições HTTP | O caminho principal para obter a resposta do servidor |
WinHttp.WinHttpRequest.5.1 |
Requisições HTTP | Alternativa com timeouts configuráveis |
HTMLDocument (MSHTML) |
Parsing de HTML | Quando é preciso extrair elementos por tags/classes |
RegExp (VBScript) |
Expressões regulares | Extração pontual dentro do texto |
Split / InStr / Mid |
Funções de string | Parsing simples de JSON e de texto sem bibliotecas |
QueryTables / Power Query |
Tabelas já montadas | Quando a página entrega uma tabela HTML limpa |
A maioria desses objetos é instanciada «na hora» com CreateObject, ou seja, não exige adicionar referências ao projeto manualmente. É uma comodidade: a pasta de trabalho funciona em qualquer máquina com Excel.
A requisição HTTP básica
O scraper mais simples se limita a obter o texto de uma página. Esta função faz uma requisição GET e retorna o HTML ou o JSON como string:
Function GetResponse(ByVal url As String) As String
Dim http As Object
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET", url, False
' Fingimos ser um navegador comum: muitos sites cortam requisições sem User-Agent
http.setRequestHeader "User-Agent", _
"Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
http.send
If http.Status = 200 Then
GetResponse = http.responseText
Else
GetResponse = "ERROR: " & http.Status & " " & http.statusText
End If
Set http = Nothing
End FunctionO terceiro argumento de Open — False — indica uma requisição síncrona: o código espera a resposta. Para a maioria das tarefas é suficiente. O cabeçalho User-Agent é crítico: sem ele, uma parte dos servidores retorna um 403 ou um captcha.
Parsing de JSON sem bibliotecas
O VBA não sabe parsear JSON «de fábrica», mas para respostas simples bastam as funções de string. Suponhamos que a API retornou:
{"price": 152.34, "currency": "USD", "symbol": "AAPL"}O valor de um campo pode ser extraído com uma pequena função:
Function ExtractJsonValue(ByVal json As String, ByVal key As String) As String
Dim pattern As String
Dim startPos As Long, endPos As Long
pattern = """" & key & """:"
startPos = InStr(json, pattern)
If startPos = 0 Then Exit Function
startPos = startPos + Len(pattern)
' Pulamos as aspas se o valor for uma string
If Mid(json, startPos, 1) = """" Then startPos = startPos + 1
' O fim do valor é uma vírgula, uma chave de fechamento ou aspas
endPos = startPos
Do While endPos <= Len(json)
Dim ch As String
ch = Mid(json, endPos, 1)
If ch = "," Or ch = "}" Or ch = """" Then Exit Do
endPos = endPos + 1
Loop
ExtractJsonValue = Trim(Mid(json, startPos, endPos - startPos))
End FunctionEssa abordagem funciona com objetos planos. Se a estrutura for aninhada e complexa, é melhor incorporar um parser de JSON pronto para VBA (por exemplo, o módulo aberto VBA-JSON, de Tim Hall) — ele converte a resposta em Dictionary e Collection, com os quais se trabalha com muito mais comodidade.
A cadeia «requisição HTTP → parsing do JSON → escrita na célula» é o padrão básico sobre o qual se constrói o scraping de taxas de câmbio. A maioria dos serviços dos bancos centrais — incluída a API pública de cotações PTAX do Banco Central do Brasil — e das APIs de moedas retorna justamente JSON ou XML, e a função de extração de valores descrita acima cobre 80% dos casos. A análise detalhada de uma solução completa com atualização automática por temporizador está no artigo «Scraping de taxas de câmbio».
Parsing de HTML com MSHTML
Quando os dados não estão em uma API, e sim diretamente na marcação da página, o objeto HTMLDocument cai bem. Ele permite buscar elementos igual ao navegador — por id, tags e classes.
Function ParseHtmlElement(ByVal url As String, ByVal elementId As String) As String
Dim http As Object, htmlDoc As Object
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET", url, False
http.setRequestHeader "User-Agent", "Mozilla/5.0"
http.send
Set htmlDoc = CreateObject("htmlfile")
htmlDoc.body.innerHTML = http.responseText
Dim el As Object
Set el = htmlDoc.getElementById(elementId)
If Not el Is Nothing Then
ParseHtmlElement = Trim(el.innerText)
End If
Set http = Nothing
Set htmlDoc = Nothing
End FunctionSe for preciso extrair vários elementos por classe ou tag, convém percorrer a coleção:
Sub ParseAllRows(ByVal url As String)
Dim http As Object, htmlDoc As Object
Set http = CreateObject("MSXML2.XMLHTTP")
http.Open "GET", url, False
http.setRequestHeader "User-Agent", "Mozilla/5.0"
http.send
Set htmlDoc = CreateObject("htmlfile")
htmlDoc.body.innerHTML = http.responseText
Dim rows As Object, i As Long
Set rows = htmlDoc.getElementsByTagName("tr")
For i = 0 To rows.Length - 1
' Gravamos o texto de cada linha da tabela na planilha, a partir da linha 2
Cells(i + 2, 1).Value = Trim(rows.Item(i).innerText)
Next i
Set http = Nothing
Set htmlDoc = Nothing
End SubExpressões regulares
Às vezes o valor buscado está incrustado no texto sem um invólucro cômodo. Nesse caso, o RegExp quebra o galho:
Function ExtractByRegex(ByVal text As String, ByVal pattern As String) As String
Dim re As Object
Set re = CreateObject("VBScript.RegExp")
re.Global = False
re.IgnoreCase = True
re.pattern = pattern
Dim matches As Object
Set matches = re.Execute(text)
If matches.Count > 0 Then
' Retornamos o primeiro grupo de captura
ExtractByRegex = matches(0).SubMatches(0)
End If
Set re = Nothing
End Function
' Exemplo: extrair o número de uma string como "Preço: 152.34 BRL"
' value = ExtractByRegex(s, "Preço:\s*([\d\.]+)")Escrita do resultado na planilha
Escrever os dados célula por célula é lento. Se as linhas forem muitas, acumule-as em um array e despeje-as com uma única atribuição:
Sub WriteArrayFast(data() As Variant)
Dim n As Long
n = UBound(data) - LBound(data) + 1
' Despejamos a coluna inteira em uma única operação
Range("A1").Resize(n, 1).Value = Application.Transpose(data)
End SubEsse despejo é dezenas de vezes mais rápido que um loop que escreve em cada célula, sobretudo com a atualização de tela desativada:
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
' ... scraping e gravação ...
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = TrueExemplo prático: uma tabela de cotações
Vamos montar um pequeno scraper que percorre uma lista de tickers, solicita o preço a uma API fictícia e despeja o resultado na planilha.
Sub ParseQuotes()
Dim tickers As Variant
tickers = Array("AAPL", "MSFT", "GOOGL", "TSLA")
Dim i As Long, url As String, response As String, price As String
' Cabeçalhos da tabela
Cells(1, 1).Value = "Ticker"
Cells(1, 2).Value = "Preço"
Cells(1, 3).Value = "Hora"
Application.ScreenUpdating = False
For i = LBound(tickers) To UBound(tickers)
url = "https://example-api.com/quote?symbol=" & tickers(i)
response = GetResponse(url) ' a função da seção anterior
price = ExtractJsonValue(response, "price")
Cells(i + 2, 1).Value = tickers(i)
Cells(i + 2, 2).Value = Val(price)
Cells(i + 2, 3).Value = Now
' Pausa entre requisições para não sobrecarregar o servidor nem ganhar um bloqueio
Application.Wait Now + TimeValue("0:00:01")
Next i
Application.ScreenUpdating = True
MsgBox "Pronto: foram carregadas " & (UBound(tickers) + 1) & " cotações", vbInformation
End SubÉ um esqueleto simplificado. Na prática, para a extração de cotações da bolsa somam-se o parsing do volume negociado, da variação percentual e dos históricos, além do tratamento dos fins de semana e dos horários de fechamento do pregão. A implementação completa, com atualização automática e formatação condicional, está no artigo «Extração de cotações da bolsa».
Tratamento de erros e robustez
As requisições de rede falham: o servidor não responde, o timeout estoura, chega um formato inesperado. O scraper tem que sobreviver a tudo isso, não morrer no primeiro erro.
Function SafeGet(ByVal url As String, Optional retries As Long = 3) As String
Dim attempt As Long
For attempt = 1 To retries
On Error Resume Next
Dim http As Object
Set http = CreateObject("WinHttp.WinHttpRequest.5.1")
http.SetTimeouts 5000, 5000, 10000, 10000 ' resolve, connect, send, receive
http.Open "GET", url, False
http.setRequestHeader "User-Agent", "Mozilla/5.0"
http.send
If Err.Number = 0 And http.Status = 200 Then
SafeGet = http.responseText
On Error GoTo 0
Exit Function
End If
On Error GoTo 0
' A pausa antes da próxima tentativa cresce a cada vez
Application.Wait Now + TimeValue("0:00:0" & attempt)
Next attempt
SafeGet = "" ' todas as tentativas se esgotaram
End FunctionO objeto WinHttpRequest é aqui mais cômodo que o XMLHTTP justamente pelo método SetTimeouts: ele permite fixar de forma explícita os limites de espera e não ficar travado para sempre.
Ética e limitações
Algumas regras que economizam nervos e reputação:
- Leia o
robots.txte os termos de uso. Nem todos os sites permitem a coleta automatizada de dados. - Faça pausas entre as requisições. Dezenas de requisições por segundo parecem um ataque e levam ao banimento do IP.
- Prefira as APIs oficiais. Se a fonte tem API, use-a: é mais estável e legal.
- Não extraia dados pessoais sem base legal nem consentimento.
- Cacheie o resultado. Se a taxa de câmbio é atualizada uma vez por dia, não é preciso castigar o servidor a cada minuto.
A alternativa sem código: Power Query
Convém lembrar que, para muitas tarefas, o VBA nem é necessário. O Power Query integrado ao Excel (Dados → Obter Dados → Da Web) sabe carregar tabelas HTML e respostas JSON pela interface, com atualização automática programada. Se a fonte entrega uma tabela limpa ou uma API REST sem autenticação enrolada, o Power Query resolve a tarefa mais rápido e sem uma única linha de código. O VBA fica para os casos em que são necessários lógica, ramificações, loops sobre uma lista e um parsing fora do padrão.
Conclusão
O scraping com VBA se constrói com poucos tijolos: a requisição HTTP (XMLHTTP ou WinHttp), o parsing da resposta (funções de string, RegExp ou HTMLDocument), a escrita nas células e o tratamento de erros. Uma vez dominado esse conjunto, dá para automatizar a coleta de quase qualquer dado tabular sem sair da pasta de trabalho de sempre.
Dois cenários clássicos com os quais é cômodo praticar:
- Scraping de taxas de câmbio — uma fonte JSON/XML simples, ideal para o primeiro scraper.
- Extração de cotações da bolsa — um pouco mais complexa: lista de tickers, atualizações frequentes, formatação.
Ambos estão desenvolvidos em artigos à parte — comece pelo que mais se parecer com a sua tarefa; as funções descritas aqui (GetResponse, ExtractJsonValue, SafeGet) serão o alicerce comum dos dois.