inteligencia-artificial

Escrito por Rafael Nogales en Planeta Chatbot.

Tabla de contenidos

Introducción (puedes saltártela)

Muchas veces nos encontramos con información que va cambiando en algunas webs de las que nos gustaría recibir notificaciones personalizadas.
Por ejemplo, nos gustaría recibir una alerta si una cierta cotización de una acción alcanza un precio determinado, o si un producto en Amazon tiene una rebaja…

La mayoría de estos casos son previsibles y las empresas proveedoras de la información nos activan estos “recordatorios” con el fin de que entremos de nuevo en su web.

¿Pero qué pasa cuando queremos algo más personalizado o directamente queremos ofrecer nosotros esta característica mediante un bot? Generalmente hay dos alternativas para conseguir esto, la fácil y la difícil como suele pasar…

  • La fácil: Existe una API que el proveedor original de los datos nos ofrece, por ejemplo, queremos consultar el tiempo en nuestra ciudad y que nos avise cuando llueva o algo así, en ese caso no tenemos más que buscar OpenWeatherMap y registrarnos en su API y ya podemos conectar nuestro bot a OpenWeatherMap con poquísimo esfuerzo, basta buscar un poquito en Google ya que ese ejemplo está muy visto y es bastante típico en tutoriales de nivel medio.
  • La difícil: No hay API (o si la hay no nos la dan) en este caso tenemos que extraer la información utilizando la web en sí, simulando que nuestro bot es un humano que accede a la web, lo que se conoce como “web scraping”.

¿Qué es un scraper?

Es un programa que accede de forma automática a una página web y puede leer la información que hay en ella así como hacer clicks en los botones, rellenar formularios y navegar como lo haría un humano.

Si la web es pequeña lo más probable es que no cuente con mecanismos anti-scraping, los típicos CAPTCHA (que cómo curiosidad son las siglas de Completely Automated Public Turing test to tell Computers and Humans Apart)

En el caso de que haya CAPTCHA tenemos dos alternativas, de nuevo la fácil y la difícil.

La fácil es rotar la IP, de forma que nuestro sistema accede al servicio cada vez con una IP distinta y por tanto siempre recibe los datos.

La difícil es resolver el CAPTCHA, habitualmente esto es posible utilizando algún sistema de inteligencia artificial basado en redes neuronales convolucionales, ya que la mayoría de CAPTCHAS consisten en clasificar imágenes.

Si hay un CAPTCHA lo más probable es que “no debas” hacer scraping en esa web y lo mejor es pedir acceso a la API, te quitarás de muchos problemas técnicos y probablemente no estés incumpliendo los términos y condiciones del servicio.

Al hacer scraping debemos tener en cuenta que la intención es simular el comportamiento de un humano, así que no debemos hacer 300 request por segundo, ya que no hay mucha gente que pueda clicar a esa velocidad con el ratón, y por tanto lo más probable es que nos baneen.

Al hacer un número inusualmente grande de peticiones por minuto además estamos perjudicando al propietario de la web ya que estamos sobrecargando el servidor y podría considerarse como un DOS (Ataque de Denegación de Servicio)

Dicho esto podemos ponernos al lío, sabiendo cuales son las limitaciones técnicas y las repercusiones que pueden causar nuestras acciones al proveedor del servicio.

En este ejemplo vamos a extraer las ofertas del día de amazon.com y poder consultarlas usando un bot de Telegram.

La web de ofertas del día es esta: https://www.amazon.es/gp/goldbox?tag=wasubi0a-21

El parámetro tag no es necesario, pero al utilizarlo puedes conseguir una parte de las comisiones de las ventas que se produzcan usando el enlace

Si analizamos el código JavaScript de esa página descubriremos que la web se genera dinámicamente, por lo que si utilizamos un módulo de Python básico como Beautiful Soup para scrapear la web no obtendremos nada útil, ya que no podemos construir el HTML final sin un motor de JavaScript.

Eso es precisamente lo que hace el navegador, descarga el HTML inicial de la dirección URL, si hay código JavaScript lo interpreta y genera el DOM, que es la estructura que representará la página web de forma abstracta en nuestro navegador internamente.

Scraping de webs dinámicas con Selenium y Python (empieza aquí si sabes qué es un scraper)

Selenium es una herramienta para hacer tests automáticos en webs, generalmente es una herramienta muy útil para quienes se dedican al front-end y para quienes hacen QA.

Pero podemos utilizarla en webs que no son la nuestra y navegar por esa web de forma automática. Eso es justo lo que vamos a hacer con Amazon.

Paso 1: Instalar Selenium

Yo voy a utilizar Chrome para el scraper, aunque podría usar Firefox también, uso chrome porque hay más documentación aunque realmente es una decisión personal.

Selenium necesita que tengamos el navegador instalado así que si no tienes Google Chrome debes instalarlo.

Debes ver cuál es tu versión de Chrome chrome://settings/help

Descargamos el ChromeDriver que sea compatible con nuestra versión de Google Chrome:

Downloads – ChromeDriver – WebDriver for Chrome

WebDriver for Chrome

WebDriver for Chromesites.google.com

Ahora debemos abrir la consola para instalar selenium en nuestro entorno de Python.

$ pip install selenium

Código básico

Esta es la plantilla de código de la que podéis partir

from selenium import webdriver  from selenium.common.exceptions import NoSuchElementException, WebDriverException  from selenium.webdriver.chrome.options import Options  import osCHROMEDRIVER_PATH = os.environ.get('CHROMEDRIVER_PATH', '/usr/local/bin/chromedriver')  GOOGLE_CHROME_BIN = os.environ.get('GOOGLE_CHROME_BIN', '/usr/bin/google-chrome')  options = Options()  options.binary_location = GOOGLE_CHROME_BIN  options.add_argument('--disable-gpu')  options.add_argument('--no-sandbox')  options.headless = Truedriver = webdriver.Chrome(executable_path=CHROMEDRIVER_PATH, chrome_options=options)# Scraping  url = 'https://www.amazon.es/dp/B006CZ0LGA'driver.get(url)el = driver.find_element_by_id('priceblock_ourprice')print(el.text)

Probablemente hayas instalado Selenium correctamente pero aun así tengas este error:

FileNotFoundError: [Errno 2] No such file or directory: '/usr/local/bin/chromedriver': '/usr/local/bin/chromedriver'selenium.common.exceptions.WebDriverException: Message: 'chromedriver' executable needs to be in PATH. Please see https://sites.google.com/a/chromium.org/chromedriver/home

Eso es porque no tienes un driver para tu navegador chrome en esa ruta, si lo descargaste y no lo moviste de sitio debe estar en la carpeta de descargas, muevelo a /usr/local/bin/chromedriver

También puedes modificar la ruta el en código para que busque el driver en otra carpeta, incluso en Descargas, pero es una solución menos limpia.

Análisis del código

En el código lo que se hace es construir el driver, es decir el navegador que vamos a utilizar para scrapear amazon, las opciones se han elegido convenientemente para que funcionen en un servidor sin interfaz gráfica, sin GPU y con lo mínimo, como es el caso de los dynos de Heroku.

La forma de cargar el chromedriver y google-chrome en sí es mediante unas variables de entorno que nos permiten hacer pruebas tanto en local como en Heroku cuando lo despleguemos.

Una vez tenemos el driver construido vamos a usarlo para extraer información de una web en concreto vamos a la web de un producto de Amazon y extraemos su precio

Esa sería la URL y lo que vemos con Chrome.

Si hacemos clic derecho sobre el precio y le damos a “Inspeccionar Elemento” podremos ver cual es su ID y buscar el elemento en el DOM con Selenium después.

Por eso buscamos así el elemento donde está el precio:

el = driver.find_element_by_id('priceblock_ourprice')

Aquí os dejo una pregunta en StackOverflow que puede clarificar las cosas:

En la siguiente parte veremos como desplegar el Scraper en Heroku y como conectarlo a Telegram.

Aquí puedes ver mi código fuente original.

Si quieres ponerte en contacto conmigo, puedes hacerlo por Telegram o por LinkedIn y podemos discutir sobre tu proyecto.

Segunda parte aquí https://planetachatbot.com/scraping-dinamico-con-selenium-heroku-telegram-bot-parte-2-f657ac030fb5

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *