Páginas

jueves, 22 de octubre de 2015

VBA Excel: Como abrir, pasar y extraer datos de una pagina web usando Macros.

Hace poco mas de un año escribí un post sobre como abrir una pagina web desde excel, pero viéndolo bien, estába un poco complicado. Así que decidí hacer una nueva publicación un poco mas didáctica y fácil de reproducir por cualquiera que desee intentarlo.

Esta macro entra al sitio web de Airbnb y extrae los precios que se despliegan en la primera página de resultados. Las técnicas que se utilizan en este ejemplo pueden servir para que cada uno las aplique a algun otro tipo de investigación para su trabajo o estudio.

Comenzamos con un archivo en el cual ingreso una ciudad, fecha de check in, fecha de salida y número de huéspedes. Las celdas de fecha tienen formato de texto para que coincida con el formato que exige la página.


 Antes de escribir el código, debemos incluir las librerías que nos permiten acceder a los controles de internet que vamos a utilizar, eso lo hacemos en el editor de visual basic, en tools/references. Allí seleccionamos las opciones que vemos a continuación (Microsoft Internet Controls y Microsoft HTML Object Library):



Ahora sí comenzamos a escribir la macro:


Sub navegar()

'las declaraciones son opcionales, pero ayudan a visualizar las opciones mientras se digita
Dim ie As InternetExplorer
Dim pagina As HTMLDocument
Dim buscar As HTMLButtonElement
Dim precios As Object
Dim precio As Object

'crea el explorador de internet
Set ie = New InternetExplorer

'hacemos visible el explorador
ie.Visible = True

'navega a la página de aribnb
ie.navigate "https://www.airbnb.com/"

'espera a que la página cargue
Do
DoEvents
Loop Until ie.readyState = READYSTATE_COMPLETE

'la página cargada la asignamos a la variable "pagina"
Set pagina = ie.document

Interrumpo el código para explicar algo: Para ir llenando los campos que pide la página, con hacer click en el boton derecho e "inspeccionar elemento" podemos identificar los nombres de cada campo:



El campo de la ciudad, que se llama "location":

El campo para la fecha de check in, se llama "checkin":

El campo de check out es "checkout":

La lista de huéspedes, tiene un id ("guests") y a su vez varias opciones dentro de si:

Y el botón de enviar, que tiene el id "submit_location":

Ahora que ya sabemos como ubicarlos, procedemos a pasarles valores los cuales tomamos del libro de excel:


'asignamos el valor de una ciudad
pagina.getElementById("location").Value = Range("B1").Value

'esperamos un segundo para que puedas visualizar los cambios que estas realizando
Application.Wait (Now + TimeValue("0:00:02"))

'pasamos a "checkin" la fecha de ingreso
pagina.getElementById("checkin").Value = Range("B2").Value

Application.Wait (Now + TimeValue("0:00:02"))

'pasamos la fecha de check out
pagina.getElementById("checkout").Value = Range("B3").Value

Application.Wait (Now + TimeValue("0:00:02"))

'pasamos el "value" que nos interesa a la lista "guests"
pagina.getElementById("guests").Value = Range("B4").Value

Application.Wait (Now + TimeValue("0:00:02"))

'seleccionamos el botón de buscar y hacemos click
pagina.getElementById("submit_location").Click

'asignamos a una variable el estado de la página
stat = pagina.readyState

'Espera a que la página cargue
Do While stat = "loading"
    Application.Wait (Now + TimeValue("0:00:01"))
    stat = pagina.readyState
Loop


En la página siguiente vemos los precios de todas las habitaciones, lo que nos interesa es el valor del elemento que contiene la suma en dólares.

Como queremos todos los precios, hay que buscar la manera de recogerlos todos. Vemos que el elemento no tiene un "id",  pero todos tienen en común un nombre de "class". Con el método getElementsByClassName, buscamos ese nombre de clase y así obtendremos una colección de todos los campos:



'creamos la lista de precios

Set precios = pagina.getElementsByClassName("h3 text-contrast price-amount")

'comenzaremos a llenar el excel en la fila 7
fila = 7

'hacemos un loop por cada elemento de la lista de precios y lo agregamos al excel:
For Each precio In precios
    Range("A" & fila).Value = precio.innerText
    fila = fila + 1
Next


End Sub

Y listo, este es el resultado final:

Para aprender un poco mas sobre como extraer información de paginas web, prueba con este otro caso: Buscar definiciones de palabras en la pagina de la RAE



Cada pagina web es diferente, si la macro no funciona como esperabas, enviame un mail y si no es muy complicado el asunto quizás pueda darte una ayuda extra.

36 comentarios:

  1. Hola que tal yo solo quiero hacer una macro que busque en google lo que ingrese en una determinada celda de excel, como le puedo hacer? te puedo dejar mi correo? daniel.thewalkingdead@hotmail.com

    espero puedas ayudarme

    ResponderEliminar
  2. Es sencillo:

    Sub navegar()

    Dim ie As InternetExplorer
    Dim pagina As HTMLDocument
    Dim buscar As HTMLButtonElement

    Set ie = New InternetExplorer

    ie.Visible = True

    ie.navigate "https://www.google.com"


    Do
    DoEvents
    Loop Until ie.readyState = READYSTATE_COMPLETE

    Set pagina = ie.document

    Set campo_buscar = pagina.getelementbyid("q")
    Set formulario_buscar = pagina.getelementbyid("tsf")

    'aqui toma el valor de la celda A1
    campo_buscar.Value = ThisWorkbook.Sheets(1).Range("A1").Value
    formulario_buscar.submit


    End Sub

    ResponderEliminar
  3. INCREIBLE! Eres un genio, muchas gracias!!!

    ResponderEliminar
  4. Hola!

    Te propongo mi problema, me gustaría una Macro VBA que abriera una página web y abriera (no descargar) todos los archivos Excel que hay en ella.
    Tengo el código para abrir la pagina web y el código para abrir los archivos .xls pero no sé cómo hacer la unión entre ellos.

    Gracias de antemano si pudieras echarme una mano!

    Saludos

    ResponderEliminar
  5. Hola!

    Te propongo mi problema, me gustaría una Macro VBA que abriera una página web y abriera (no descargar) todos los archivos Excel que hay en ella.
    Tengo el código para abrir la pagina web y el código para abrir los archivos .xls pero no sé cómo hacer la unión entre ellos.

    Gracias de antemano si pudieras echarme una mano!

    Saludos

    ResponderEliminar
  6. Buenas,

    Tengo problemas al momento de activar eventos como onChange en un combobox, mas especifico en combobox dependientes, donde si eligen en uno en el otro se carga la lista. Ejemplo, en uno eliges el país, y en el otro se cargan las ciudades, con el codigo que sugieres si elijo en el primero pero el segundo no carga pues no se activa el evento onChange. Me podrías ayudar de alguna manera a activar ese evento desde vba?

    gracias

    ResponderEliminar
  7. Hola!!
    como puedo abrir con un botón Clic, una página web e ingresar mi usuario y contraseña. la pagina es http://www.netelip.com/es/log-in-accede-a-tu-cuenta-netelip. le he dado vueltas a lo publicado y no se por donde empezar. Gracias por atenderme.

    ResponderEliminar
  8. (Gracias por adelantado)
    hola!!mi pagina es netelip
    ya me funciona pero no soy capaz de cliquear el botón de activar
    input type="submit" name="btn-submit" id="btn-submit" class="boton_servicio" value="ACCEDE"

    ResponderEliminar
    Respuestas
    1. Intenta buscar el id del "form", obtenlo y luego haz form.submit

      Eliminar
  9. Hola Buena tarde, disculpa la intromission, estoy hacienda una macro que llena una pagina de mi trabajo y consulta los datos que estan en esa hoja de excel, empieza por un numero de ticket, y luego meteria info, logro acceder a la pagina, pero cuando abre me manda el siguiente error

    object variable or with block variable not set

    este es mi codigo


    Sub navegar()

    Dim ie As InternetExplorer
    Dim pagina As HTMLDocument
    Dim buscar As HTMLButtonElement
    Dim direccion As String



    Set ie = New InternetExplorer

    ie.Visible = True

    ie.navigate "http://app.huawei.com/icarenext/#!msr/uwq/cseMySrList.html?para=CseMyHandlingSR"


    Do
    DoEvents
    Loop Until ie.readyState = READYSTATE_COMPLETE

    Set pagina = ie.document

    Set campo_buscar = pagina.getElementById("srSrc-input")
    Set formulario_buscar = pagina.getElementById("srSrc-btn")

    'aqui toma el valor de la celda A1
    campo_buscar.Value = ThisWorkbook.Sheets(1).Range("A1").Value
    formulario_buscar.submit


    End Sub

    me podrias orientar acerca de que podria ser

    ResponderEliminar
    Respuestas
    1. Veo que el link primero apunta al Uniportal, pudiste hacer login?

      Eliminar
  10. Hola,
    Quiero hacer click sobre un botón "Buscar", que tiene el siguiente código html:
    buttton class="intervals_search find" type="submit">
    Buscar < / buttton>

    Lo he intentado con esto pero no funciona:
    ie.document.getElementsByClassName("intervals_search find").Click

    ¿Alguna idea?

    ResponderEliminar
    Respuestas
    1. Lo que pasa es que el método getElementsByClassName te devuelve una colección de elementos y no puedes hacer click sobre la colección. Primero tendrías que seleccionar un elemento de esa colección para luego hacerle click.
      Intenta esto: ie.document.getElementsByClassName("intervals_search_find")(0).Click
      Al poner el (0) estas seleccionando el primer elemento de la colección, ahí sí puedes hacer click. Avísame si te sirvió.

      Eliminar
    2. Gracias Ruben eres un fenomeno, le e dado vueltas y ya me vale.
      explorador.document.getElementsByClassName("boton_servicio")(0).Click

      Eliminar
    3. Funciona de la misma manera el método getElementsByTagName, es para el mimo caso de dar clic a un boton, saludos.

      Eliminar
  11. hola Ruben

    espero puedas ayudarme, realice la macro para entrar a la pagina de telcel http://www.r6.telcel.com/Act/ puedo logearme sin ningun problema, el detalle viene cuando me abre una segunda pagina, ya en el main http://www.r6.telcel.com/Act/main y ya no puedo acceder a los txt ni a los botones, intente ponerle tiempo a que cargue y me tira el error que necesita un objeto mi codigo es este:

    Private Sub CommandButton2_Click()
    Dim ie As InternetExplorer
    Dim pagina As HTMLDocument

    Set ie = New InternetExplorer
    ie.Visible = True

    ie.Navigate "http://www.r6.telcel.com/Act/"
    Do
    DoEvents
    Loop Until ie.ReadyState = READYSTATE_COMPLETE
    Set pagina = ie.Document
    pagina.All("txtusuario").Value = "ddddd"
    Application.Wait (Now + TimeValue("0:00:02"))
    pagina.All("txtpassword").Value = "22222222"
    Application.Wait (Now + TimeValue("0:00:02"))
    pagina.All("Ingresar").Click

    stat = pagina.ReadyState
    Do While stat = "loading"
    Application.Wait (Now + TimeValue("0:00:01"))
    stat = pagina.ReadyState
    Loop
    pagina.All("txtclave").Value = "22222222"
    pagina.All("Aceptar").Click


    End Sub

    mi pregunta es como accedo a los datos de esta segunda pagina emergente, y seguir refrescando la pagina para obtener otros datos, desde ya te agradezco

    ResponderEliminar
  12. Hola!
    estoy tratando de buscar el nombre de textbox donde dice CURP*: osea la casilla donde se llena la curp, pero no encuentro el nombre de esa casilla. https://rfc.siat.sat.gob.mx/PTSC/RFC/menu/index.jsp?opcion=2

    ResponderEliminar
  13. Hola Ruben! Estamos tratando de generar un macro que en base a un No. de referencia, en distintas páginas web, nos devuelva el precio que le corresponde de cada página consultada. Crees poder ayudarnos con la macro? Te dejo mi correo en caso de que lo podamos revisar: carol.hdzmtz@gmail.com.
    Mil gracias!!

    ResponderEliminar
  14. Hola! muy bueno tu post
    una pregunta, cómo hago click en INGRESAR
    https://auth.afip.gob.ar/contribuyente_/login.xhtml

    Gracias. un saludo

    ResponderEliminar
  15. Buenas, Gracias por darme estos conocimientos para progresar en esto de la programación. Por favor ayudenme a sacar la latitud y longitud de esta pagina:
    http://arduexcelweb.net23.net/mapa2.html
    tengo que seleccionar un punto y que me bote esos dos datos a excel continuamente, si cambio el punto me debe cambiar el valor de las celdas asignadas
    sus id son "loglat" y "loglong"
    Estoy seguro que profesionales como ustedes podran hacerlo
    Gracias nuevamente de antemano

    ResponderEliminar
  16. Mi codigo va algo asi:
    Sub navegar()

    'las declaraciones son opcionales, pero ayudan a visualizar las opciones mientras se digita
    Dim ie As InternetExplorer
    Dim pagina As HTMLDocument
    Dim Latitud As Object
    'crea el explorador de internet
    Set ie = New InternetExplorer

    'hacemos visible el explorador
    ie.Visible = True

    'navega a la página de aribnb
    ie.navigate "http://arduexcelweb.net23.net/mapa2.html"

    'espera a que la página cargue
    Do While stat = "loading"
    Application.Wait (Now + TimeValue("0:00:10"))
    stat = pagina.readyState
    Loop
    'la página cargada la asignamos a la variable "pagina"
    Set pagina = ie.document

    Set Latitud = pagina.getElementById("loglat")
    Latitud.Value = ThisWorkbook.Sheets(1).Range("M2").Value
    Set Longitud = pagina.getElementsById("loglong")
    Longitud.Value = ThisWorkbook.Sheets(1).Range("M3").Value
    End Sub

    ResponderEliminar
  17. Amigo, es posible que en vez de manejar IE desde VBA, pueda hacer lo mismo pero con Chrome?

    ResponderEliminar
    Respuestas
    1. Internet Explorer está integrado con VBA, sorry, no conozco como hacerlo con Chrome.
      Te comento que esa fue una de las razones por las que dejé de usar VBA para procesar mis excels, ahora uso Python.

      Eliminar
  18. Hola, Muchas gracias por el post, me ha sido de gran ayuda

    Tengo un inconveniente, necesito seleccionar dos valores para realizar una busqueda, pero cuando selecciono uno, se borra el otro, cómo selecciono ambos?

    pagina.getElementById("aig_work_teams_advanced").Value = "ea45cdce-0b19-7c04-c575-56313c217492"

    pagina.getElementById("aig_work_teams_advanced").Value = "c6c7e679-0678-84a4-2be1-56314334ce98"

    Necesito que ambos valores permanezcan asignados, cómo lo hago?

    Muchas gracias por tu ayuda

    ResponderEliminar
  19. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  20. Hola, muchas gracias por el post. he usado el codigo para meter la informacón de usuario y contraseña de una pagina. el problema es que no puedo darle al boton de enviar usando tu codigo. creo que el problema radica es que es un formulario y no se cual es el id correcto del boton de validar la información. no se si me puedes ayudar. gracias

    ResponderEliminar
  21. Muy Buen post si señor,
    Pero me gustaría crear una macro que recorriera todas las páginas de booking.com y me sacara el nombre de los hoteles el numero de estrellas y su ubicación.

    Muchas Gracias

    ResponderEliminar
  22. muy buen post .. agrego este detalle, si los codigos no dejan el valor requerido en el textbox (en mi caso los textbox eran igual a cero), entonces el código:

    documento.getElementById("var").Value = Range("A1").Value

    es ineficiente, ya que no rellena la casilla con el valor requerido, si no solo cambia el valor de la casilla internamente, en fin, la solución fue la siguiente (después de 4 días buscando)

    For Each abc In IE.Document.getElementsByTagName("input")
    If abc.ID = "var" Then
    abc.Value = "100"

    ResponderEliminar
    Respuestas
    1. Hola Cristóbal, me puedes decir un poco más de como funciona el método getElementsByTagName, lo que pasa es que tengo una pagina en la cual quiero hacer clic en un boton, ya lo intente con getElementsByClassName pero resulta que más arriba en la pagina hay un boton que tiene exactamente la misma clase.

      Saludos.

      Eliminar
  23. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  24. Hola a todos,

    Tengo un boton en cual quiero hacer clic y ya lo intente con getElementsByClassName, pero resulta que hay otro boton con la misma clase, entonces hace clic en ese boton y no en el que yo quiero, les dejo el codigo del boton abajo, espero que me puedan ayudar, saludos.

    <"input" type="submit" value="Request Price" class="button" onmouseover="checkState()" onclick="event.returnValue=false;(helpState)? getHelp(event,'hlp_601'):event.returnValue=true" style="cursor: help;">

    ResponderEliminar
    Respuestas
    1. Cambia el índice del elemento. El primero es 0, el segundo 1 y así hasta que encuentres el tuyo.

      Set botón = página.getElementsByClassName("button")(1)

      botón.click()

      Eliminar
  25. Hola Rubén, muy interesante tu web. Te quería hacer una consulta a ver si podés darme una mano con una macro. Adonde te puedo escribir? Desde ya, muchas gracias. Rodrigo.

    ResponderEliminar
  26. buenas tardes, como puedo hacer click sobre una imagen o como puedo mediante tabulador seleccionar la misma para dar enter.

    ResponderEliminar
    Respuestas
    1. Hola, una vez que hayas asignado el elemento del botón a una variable, ejecutas el método .Click

      Eliminar
  27. Hola Ruben, ando estrujándome los sesos con una web que muestra una tabla con diferentes tabs y quiero activar una de ellas.
    Cada tab esta definida con su propia class así que estaba intentando usar lo que proponías en otros post con los botones de busqueda
    pagina.getElementsByClassName("ifmenu-odds li3")(0).Click
    pero no funciona =(
    alguna idea

    ResponderEliminar