51
loading...
This website collects cookies to deliver better user experience
pip
es muy sencillo hacerlo:pip install selenium
conda
para administrar tus paquetes (como yo):conda install -c conda-forge selenium
PATH
del sistema o bien en el mismo directorio que nuestro script de Python, de lo contrario obtendremos un error del tipo: selenium.common.exceptions.WebDriverException: Message: ‘X’ executable needs to be in PATH
, donde X
es el driver en cuestión.PATH
, estamos listos para comenzar a construir nuestro script.webdriver
que es la clase fundamental para interactuar con Selenium;Select
que permite que Selenium trabaje eficientemente con elementos HTML de tipo <select>...</select>
;sleep
, que requeriremos por las características de la página con la que trabajaremos (más sobre esto adelante); yPath
para obtener el directorio de trabajo del script.
from selenium import webdriver
from selenium.webdriver.support.ui import Select
from time import sleep
from pathlib import Path
cwd
, y el URL de la página a la que el driver debe dirigirse en la variable url
:cwd = str(Path().resolve())
url = 'https://www.banxico.org.mx/SieInternet/consultarDirectorioInternetAction.do?sector=8&accion=consultarCuadro&idCuadro=CP194&locale=es'
cwd
):opciones = webdriver.ChromeOptions()
prefs = {'download.default_directory': cwd}
opciones.add_experimental_option('prefs', prefs)
url
:driver = webdriver.Chrome(options = opciones)
driver.get(url)
<input>...</input>
de la página. Los guardaremos en la variable inputs
. La forma de encontrarlos es mediante el método find_elements_by_tag_name()
:inputs = driver.find_elements_by_tag_name("input")
checkbox
. Para eso usamos el método get_attribute()
(pues el tipo es un atributo de la etiqueta HTML; existe un método análogo para obtener propiedades, se llama get_property()
):checkboxes = [x for x in inputs if x.get_attribute("type") == "checkbox"]
checkboxes
para asegurarnos de que todos queden sin seleccionar. Para ello usamos el método is_selected()
, que devuelve True
si el elemento está seleccionado y False
en caso contrario. En caso de que esté seleccionado, invocamos el método click()
para anular la selección:for checkbox in checkboxes:
if checkbox.is_selected():
checkbox.click()
nodo_0_1_0_SP74825
. Así, podemos usar el método find_element_by_id()
para encontrarlo y darle click:checkbox_target = driver.find_element_by_id("nodo_0_1_0_SP74825")
checkbox_target.click()
consultaSeriesCarritoToggleAcc
. Lo guardaremos en la variable botón_expandir
:boton_expandir = driver.find_element_by_id("consultaSeriesCarritoToggleAcc")
aria-expanded
. Si su valor es "true"
, quiere decir que la caja de opciones está abierta, en caso contrario es "false"
. Evidentemente en este caso está cerrada, pero por seguridad incluiremos esta verificación extra en nuestro código:if boton_expandir.get_property("aria-expanded") == "false":
boton_expandir.click()
<select>...</select>
con ID anoInicial
.<select>...</select>
con ID anoFinal
.seleccionFormato
.seleccionFormatoXLS
.<select>...</select>
usaremos la clase Select
que importamos al inicio:periodo_inicial = Select(driver.find_element_by_id("anoInicial"))
periodo_final = Select(driver.find_element_by_id("anoFinal"))
boton_formato = driver.find_element_by_id("seleccionFormato")
boton_xls = driver.find_element_by_id("seleccionFormatoXLS")
Select
es que permite buscar los elementos <option>
del tag por ID, por valor o por el texto mostrado. En nuestro caso buscaremos por texto mostrado. Para ello usamos el método select_by_visible_text()
:periodo_inicial.select_by_visible_text("Todo")
periodo_final.select_by_visible_text("Todo")
aria-expanded
:if boton_formato.get_property("aria-expanded") == "false":
boton_formato.click()
boton_xls.click()
driver.quit()
.py
y lo ejecutamos, probablemente nos encontremos con errores que nos indican que ciertos elementos (como los selectores de periodos o el botón de descargar como XLS) no están disponibles o no se encuentran. Esto es debido a una particularidad de la página del SIE: tiene animaciones. Al dar clic para expandir la caja de opciones para descargar las series, ésta no se muestra de inmediato, sino que se despliega lentamente, de arriba hacia abajo, como una persiana. Por lo tanto, como la velocidad de ejecución del script de Python es más rápida que la animación, busca los elementos dentro de la caja de opciones antes de que estén completamente cargados en el DOM de la página.sleep()
al inicio. Esta función pausa la ejecución del programa durante el número de segundos indicado, y así nos permite garantizar que al momento de avanzar, los elementos del DOM estén completamente cargados y el script no devuelva errores.sleep()
en lugares estratégicos:# Importamos las librerías necesarias
from selenium import webdriver
from selenium.webdriver.support.ui import Select
from time import sleep
from pathlib import Path
# Guardamos el directorio del script y la URL a la que queremos que se dirija el driver
cwd = str(Path().resolve())
url = 'https://www.banxico.org.mx/SieInternet/consultarDirectorioInternetAction.do?sector=8&accion=consultarCuadro&idCuadro=CP194&locale=es'
# Establecemos como directorio de descarga el mismo que el del script
opciones = webdriver.ChromeOptions()
prefs = {'download.default_directory': cwd}
opciones.add_experimental_option('prefs', prefs)
# Lanzamos el driver
driver = webdriver.Chrome(options = opciones)
driver.get(url)
# Buscamos todos los elementos <input>...
inputs = driver.find_elements_by_tag_name("input")
# ... y los filtramos para quedarnos sólo con los que son de tipo "checkbox"
checkboxes = [x for x in inputs if x.get_attribute("type") == "checkbox"]
# Nos aseguramos de que ninguno esté seleccionado
for checkbox in checkboxes:
if checkbox.is_selected():
checkbox.click()
# Elegimos el checkbox de la serie que queremos y nos aseguramos que sí esté seleccionado
checkbox_target = driver.find_element_by_id("nodo_0_1_0_SP74825")
checkbox_target.click()
# Identificamos el botón para expandir la caja de opciones de descarga de las series
boton_expandir = driver.find_element_by_id("consultaSeriesCarritoToggleAcc")
# Si la caja no está abierta, la abrimos dándole clic
if boton_expandir.get_property("aria-expanded") == "false":
boton_expandir.click()
# Aquí conviene pausar el script, pues la caja de opciones tarda en abrirse debido a la animación
sleep(2)
# Identificamos los controles a manipular dentro de la caja
periodo_inicial = Select(driver.find_element_by_id("anoInicial"))
periodo_final = Select(driver.find_element_by_id("anoFinal"))
boton_formato = driver.find_element_by_id("seleccionFormato")
boton_xls = driver.find_element_by_id("seleccionFormatoXLS")
# Elegimos los periodos inicial y final
# Ambos con la opción que dice "Todos"
periodo_inicial.select_by_visible_text("Todo")
periodo_final.select_by_visible_text("Todo")
# Desplegamos la lista de opciones de formatos de descarga
if boton_formato.get_property("aria-expanded") == "false":
boton_formato.click()
# Nuevamente pausamos un par de segundos para dar tiempo a la animación
sleep(2)
# Damos clic en el botón que corresponde a "XLS"
boton_xls.click()
# Cerramos el driver
driver.quit()
var url = 'https://www.banxico.org.mx/SieAPIRest/service/v1/series/SP74825/datos/?token=' + token;
var respuesta = UrlFetchApp(url, {'muteHtpExceptions': true});
var respuestaTexto = respuesta.getContentText();
var respuestaJson = JSON.parse(respuestaTexto);
token
es un string que contiene el token provisto por Banxico para acceder a su API. Como se puede ver, el camino es mucho más corto y al final se obtienen los mismos datos en formato JSON. Desgraciadamente, muchos sitios no cuentan con APIs o con vínculos permanentes que faciliten el acceso programado a los datos, por lo que el conocimiento de herramientas como Selenium se vuelve esencial para cualquiera que desee automatizar flujos de trabajo que involucren el acceso a recursos web.