Formatos e fontes de dados 9 min de leitura

Web scraping com Excel e VBA

Web scraping com Excel e VBA: requisições HTTP a páginas web, parsing de HTML e JSON e atualização automática das tabelas sem programas externos.

EW
Equipe Web-Scraping.biz
Coleta de dados para as demandas do negócio
Publicado: 4 março 2025

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:

vba
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 Function

O terceiro argumento de OpenFalse — 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:

json
{"price": 152.34, "currency": "USD", "symbol": "AAPL"}

O valor de um campo pode ser extraído com uma pequena função:

vba
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 Function

Essa 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.

vba
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 Function

Se for preciso extrair vários elementos por classe ou tag, convém percorrer a coleção:

vba
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 Sub

Expressões regulares

Às vezes o valor buscado está incrustado no texto sem um invólucro cômodo. Nesse caso, o RegExp quebra o galho:

vba
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:

vba
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 Sub

Esse despejo é dezenas de vezes mais rápido que um loop que escreve em cada célula, sobretudo com a atualização de tela desativada:

vba
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
' ... scraping e gravação ...
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True

Exemplo 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.

vba
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.

vba
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 Function

O 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.txt e 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.