🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA web scraping en Excel — extraer datos de una web sin Internet Explorer

|

VBA web scraping en Excel — extraer datos de una web sin Internet Explorer

TL;DR — Una macro de scraping recibe el HTML que envió el servidor, no la página que ves. Tu navegador ejecuta JavaScript después de que llegue la página y muchas veces es entonces cuando construye la tabla que quieres, así que esa tabla nunca aparece en lo que descarga VBA. Compruébalo primero: abre Ver código fuente de la página (Ctrl+U) y busca un valor que necesites. Si está ahí, descarga la página con XMLHTTP y léela con un documento htmlfile. Si no está, la página carga sus datos desde una petición JSON, y llamar directamente a esa petición es más fácil y más estable que cualquier scraping. Automatizar Internet Explorer ya no es una opción.

Dim http As Object, doc As Object
Set http = CreateObject("MSXML2.XMLHTTP.6.0")
http.Open "GET", "https://example.com/prices", False
http.send
Set doc = CreateObject("htmlfile")
doc.body.innerHTML = http.responseText
Debug.Print doc.getElementsByTagName("table").Length & " tables found"

Este es el tercer artículo de una serie sobre cómo traer datos de la web a Excel: VBA HTTP request trata la petición, VBA JSON la respuesta estructurada, y este, las páginas escritas para personas y no para programas. La idea de la serie es que una petición web te entrega texto, no datos. Entre el servidor y tus celdas hay tres traducciones que son responsabilidad tuya: de bytes a texto, de texto a estructura y de estructura a cuadrícula. El scraping es la versión en la que la estructura nunca se pensó para ti.

Lo que aprenderás

  • El modelo mental: el HTML que envió el servidor
  • La prueba de diez segundos: Ver código fuente de la página
  • Cuando los datos no están en el código fuente: busca el JSON
  • Por qué no Internet Explorer ni Selenium
  • Leer una tabla HTML con htmlfile
  • Los números extraídos son texto
  • Texto ilegible por un meta charset
  • Power Query y un scraping respetuoso

El modelo mental: el HTML que envió el servidor

Un navegador hace dos cosas con una página. Descarga el HTML y después ejecuta el JavaScript de la página, que a menudo pide más datos y construye en pantalla tablas, precios y listas. Lo que ves es el resultado de los dos pasos. Lo que VBA descarga con una petición HTTP es solo el primer paso: el HTML tal como lo envió el servidor.

Por eso la queja más habitual sobre scraping es «mi código no encuentra ninguna tabla, pero yo la veo». Las dos afirmaciones son ciertas. La tabla existe en la página viva del navegador y no en el HTML que envió el servidor. Ningún selector, espera o reintento lo arregla, porque los datos nunca estuvieron en lo que descargaste.

La prueba de diez segundos: Ver código fuente de la página

Antes de escribir código, abre la página en un navegador y pulsa Ctrl+U (Ver código fuente de la página). Esto muestra el HTML tal como lo envió el servidor, lo mismo que recibirá VBA. Busca en él (Ctrl+F) un valor que veas en la página, como un precio o un nombre.

  • Encontrado: los datos están en el HTML del servidor. Extráelos con XMLHTTP y htmlfile, como se explica más abajo.
  • No encontrado: los carga JavaScript. Pasa a la siguiente sección.

No uses Inspeccionar (F12, Elementos) para esta prueba. Inspeccionar muestra la página viva después de que se haya ejecutado JavaScript, así que muestra los datos en los dos casos.

Cuando los datos no están en el código fuente: busca el JSON

Una página que construye su tabla con JavaScript tiene que sacar los datos de algún sitio, casi siempre de una petición JSON al mismo sitio web. Encuéntrala:

  1. Abre las herramientas para desarrolladores del navegador (F12) y ve a la pestaña Red.
  2. Filtra por Fetch/XHR y vuelve a cargar la página.
  3. Haz clic en las peticiones y mira su Respuesta. Una de ellas contiene tus datos en JSON.
  4. Copia su URL y llámala desde VBA como se muestra en VBA HTTP request, y después analízala con VBA JSON.

Este camino es mejor que el scraping incluso cuando el scraping funcionaría. El JSON tiene nombres de campo en lugar de posiciones en una tabla, números sin símbolos de moneda, y cambia con menos frecuencia que el diseño de la página. Revisa las condiciones de uso del sitio antes de construir sobre él; un endpoint no documentado también puede cambiar sin previo aviso.

Por qué no Internet Explorer ni Selenium

Los tutoriales antiguos controlan un navegador desde VBA con CreateObject("InternetExplorer.Application"). Internet Explorer se retiró en junio de 2022; no tiene soporte, y cada vez más sitios web modernos no funcionan en él. No empieces trabajos nuevos con él, y planifica sustituir las macros que dependen de él.

Selenium Basic, el sustituto habitual en VBA, no publica una versión nueva desde 2016 y necesita un controlador de navegador que coincida con la versión instalada de Chrome o Edge; cada actualización del navegador puede romper la macro en el equipo del usuario. Todavía puede ser la herramienta adecuada para una página que solo funciona con JavaScript y no tiene una petición de datos a la que puedas llamar, pero trátala como último recurso, no como opción por defecto.

Leer una tabla HTML con htmlfile

Para datos que están en el HTML del servidor no necesitas ningún navegador. Descarga la página y cárgala en un objeto htmlfile, que te da un documento en el que puedes buscar como en una página web:

Sub ScrapeFirstTable(ByVal url As String, ByVal target As Range)
    Dim http As Object, doc As Object, tbl As Object
    Dim out() As Variant, r As Long, c As Long, nCols As Long

    Set http = CreateObject("MSXML2.XMLHTTP.6.0")
    http.Open "GET", url, False
    http.setRequestHeader "User-Agent", "Mozilla/5.0"
    http.send
    If http.Status <> 200 Then Err.Raise vbObjectError + 514, , "HTTP " & http.Status

    Set doc = CreateObject("htmlfile")
    doc.body.innerHTML = http.responseText
    If doc.getElementsByTagName("table").Length = 0 Then Err.Raise vbObjectError + 515, , "No table"
    Set tbl = doc.getElementsByTagName("table")(0)

    nCols = 0
    For r = 0 To tbl.Rows.Length - 1
        If tbl.Rows(r).Cells.Length > nCols Then nCols = tbl.Rows(r).Cells.Length
    Next r
    ReDim out(1 To tbl.Rows.Length, 1 To nCols)
    For r = 0 To tbl.Rows.Length - 1
        For c = 0 To tbl.Rows(r).Cells.Length - 1
            out(r + 1, c + 1) = Trim$(tbl.Rows(r).Cells(c).innerText)
        Next c
    Next r
    target.Resize(UBound(out, 1), nCols).Value = out
End Sub

Hay tres detalles importantes. Las colecciones del documento HTML (Rows, Cells, getElementsByTagName) empiezan en 0, a diferencia de casi todo en Excel. Las filas pueden tener distinto número de celdas, así que dimensiona el array según la fila más ancha. Y la tabla entera se escribe en la hoja de una sola vez.

Para encontrar un elemento concreto, apóyate en getElementById y getElementsByTagName. Según la versión de Windows y de Office, un documento htmlfile con enlace tardío puede ejecutarse en un modo de compatibilidad antiguo en el que faltan métodos más recientes como querySelector y getElementsByClassName, así que el código que depende de ellos funciona en un equipo y en otro no. Para filtrar por clase, recorre las etiquetas y comprueba .className.

Seleccionar «la primera tabla» es el punto más débil de cualquier scraper. Un rediseño del sitio añade una tabla encima de la tuya y la macro lee la equivocada sin avisar. Si la tabla tiene un id, úsalo; si no, comprueba el texto de una celda de encabezado antes de fiarte de la tabla.

Los números extraídos son texto

Todo lo que sacas de una página con innerText es una cadena, con el formato pensado para quienes leen ese sitio: 1.234,56 € en un sitio español o alemán, 1 234,56 € en uno francés, $1,234.56 en uno estadounidense. Escrito en una celda como texto, no suma. Convertido con CDbl o Val, da un número equivocado o un error, según la configuración regional del usuario.

Convierte usando el formato del sitio, no el del usuario. Quita la moneda y el separador de miles, después convierte el separador decimal en un punto y usa Val:

Function ParseScraped(ByVal s As String, ByVal thousandsSep As String, ByVal decimalSep As String) As Variant
    s = Replace(s, ChrW(160), "")          ' espacio de no separacion
    s = Replace(s, ChrW(8239), "")         ' espacio estrecho de no separacion
    s = Replace(s, " ", "")
    s = Replace(s, ChrW(8364), ""): s = Replace(s, "$", "")   ' signo del euro
    If thousandsSep <> "" Then s = Replace(s, thousandsSep, "")
    s = Replace(s, decimalSep, ".")
    If s Like "*[!0-9.-]*" Or s = "" Then ParseScraped = CVErr(xlErrValue) Else ParseScraped = Val(s)
End Function

v = ParseScraped(cellText, ".", ",")   ' "1.234,56" de un sitio espanol -> 1234.56

Los dos espacios de no separación son la trampa escondida. Los sitios franceses y de otros países europeos los usan a menudo para separar los miles, se ven exactamente igual que un espacio y Trim no los elimina. Consulta VBA Trim para el mismo carácter en datos pegados.

Texto ilegible por un meta charset

responseText decodifica la página con el juego de caracteres del encabezado HTTP del servidor. Muchos sitios antiguos declaran su codificación solo dentro del HTML, con una etiqueta <meta charset>, y XMLHTTP no lee esa etiqueta. La página se ve bien en el navegador y llega a VBA con é en lugar de é, o con recuadros en lugar de texto japonés.

Si el código fuente tiene una etiqueta <meta charset="windows-1252"> o <meta charset="shift_jis"> y el texto sale ilegible, decodifica http.responseBody con ese juego de caracteres, usando la función con ADODB.Stream de VBA HTTP request, y pasa el resultado a doc.body.innerHTML.

Power Query y un scraping respetuoso

Para una tabla HTML estática que quieres actualizar, Excel ya tiene un scraper: Datos > De la web (Power Query) muestra las tablas de una página, carga la que elijas y la actualiza con un clic, sin VBA. Tiene el mismo límite, porque también lee el HTML del servidor, pero cuando funciona es menos código que mantener. Usa VBA cuando necesites lógica: una lista de URL, un inicio de sesión o combinar páginas.

Y haz scraping con educación. Una petición por página, una pausa entre páginas (consulta VBA Wait), no volver a descargar lo que ya tienes, y un vistazo previo a las condiciones del sitio y a su robots.txt. Una macro que lanza cien peticiones por segundo consigue que bloqueen la dirección IP de tu oficina, y entonces ya no funciona la macro de nadie.

La decisión de criterio: el scraping es un contrato que nadie firmó

Una API es una promesa: el proveedor la documenta e intenta no romperla. Una página web no promete nada. El diseñador puede añadir una tabla, cambiar el nombre de una clase o mover los precios a JavaScript mañana mismo, y tu macro se rompe sin dar ningún error o, peor aún, lee la columna equivocada.

Así que elige la fuente más estable que tengas: primero una API oficial, después la petición JSON que hay detrás de la página, después Power Query sobre una tabla estática, después XMLHTTP con htmlfile y, en último lugar, la automatización del navegador. Elijas lo que elijas, haz que el scraper compruebe lo que ha encontrado (el texto de un encabezado, un número de filas) antes de escribir, para que un rediseño produzca un error en lugar de números equivocados.

Cómo ayuda ExcelMaster

Los scrapers se rompen en silencio: el diseño cambia, los números vuelven con el formato de otro país, el texto llega ilegible.

ExcelMaster comprueba lo que devuelve de verdad el servidor antes de escribir el código, busca la petición de datos que hay detrás de las páginas con JavaScript y convierte los números extraídos según el formato del sitio para que lleguen a tu hoja como números de verdad.

Preguntas frecuentes

¿Cómo extraigo datos de una web a Excel con VBA?

Descarga la página con MSXML2.XMLHTTP.6.0, carga responseText en CreateObject("htmlfile"), localiza la tabla con getElementsByTagName("table"), lee el innerText de cada celda en un array y escribe el array en la hoja.

¿Por qué mi scraper de VBA no encuentra datos que veo en la página?

La página construye esos datos con JavaScript después de cargarse, así que no están en el HTML que descarga VBA. Busca la petición JSON en la pestaña Red del navegador y llámala directamente.

¿Todavía puedo usar Internet Explorer para hacer web scraping con VBA?

No es recomendable. Internet Explorer se retiró en junio de 2022 y no tiene soporte. Usa XMLHTTP con htmlfile para las páginas estáticas y la petición JSON de la página para las dinámicas.

¿Por qué los números extraídos no son números en Excel?

innerText siempre devuelve texto, con el formato del país del sitio. Quita los símbolos de moneda y los separadores de miles, incluidos los espacios de no separación, cambia el separador decimal por un punto y convierte con Val.

¿Es mejor Power Query que VBA para hacer web scraping?

Para una tabla estática que quieres actualizar, sí: Datos > De la web no necesita código. Usa VBA cuando tengas que recorrer muchas páginas, iniciar sesión o aplicar lógica entre peticiones.

Probado en

Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación el 05/10/2026.

Guías relacionadas: VBA HTTP request · VBA JSON · VBA Trim · VBA Wait · Arrays 2D en VBA · VBA Replace · VBA Like · VBA CreateObject