Introducción al Web Scraping con Python

El web-scraping es una técnica importante, frecuentemente empleada en muchos contextos diferentes, especialmente en la ciencia de datos y la minería de datos. Python se considera en gran medida...

Introducción

El web-scraping es una técnica importante, frecuentemente empleada en muchos contextos diferentes, especialmente en la ciencia de datos y la minería de datos. Python se considera en gran medida el lenguaje de referencia para el raspado web, la razón es la naturaleza de Python con baterías incluidas. Con Python, puede crear un script de raspado simple en aproximadamente 15 minutos y en menos de 100 líneas de código. Entonces, independientemente del uso, el raspado web es una habilidad que todo programador de Python debe tener en su haber.

Antes de comenzar a ponernos manos a la obra, debemos dar un paso atrás y considerar qué es el web-scraping, cuándo debemos usarlo y cuándo evitarlo.

Como ya sabes, el web-scraping es una técnica empleada para extraer automáticamente datos de sitios web. Lo que es importante entender es que el web-scraping es una técnica un tanto rudimentaria para extraer datos de varias fuentes, generalmente páginas web. Si los desarrolladores de un sitio web son lo suficientemente generosos como para proporcionar una API para extraer datos, sería una forma mucho más estable y sólida de acceder a los datos. Entonces, como regla general, si un sitio web proporciona una API para recuperar sus datos mediante programación, utilícela. Si una API no está disponible, solo entonces use web-scraping.

Asegúrese también de cumplir con las reglas o restricciones con respecto al web scraping para cada sitio web que use, ya que algunos no lo permiten. Con eso claro, pasemos directamente al tutorial.

Para este tutorial, vamos a raspar http://quotes.toscrape.com/, un sitio que enumera citas famosas de autores de renombre.

El canal de raspado web

Podemos entender el web-scraping como un pipeline que contiene 3 componentes:

  1. Descargando: Descargando la página web HTML
  2. Análisis: Analizar el HTML y recuperar los datos que nos interesan
  3. Almacenamiento: Almacenar los datos recuperados en nuestra máquina local en un formato específico

Descargando HTML

Parece lógico que para extraer cualquier dato de una página web, primero tenemos que descargarlo. Hay dos maneras en que podemos hacer esto:

1. Uso de bibliotecas de automatización del navegador

Puede usar bibliotecas de automatización del navegador como Selenio para descargar el HTML de una página web. Selenium te permite abrir un navegador, digamos Chrome, y controlarlo como quieras. Puede abrir la página web en un navegador y luego obtener el código HTML de esa página, todo automatizado usando Selenium.

Sin embargo, este método tiene un gran inconveniente: es significativamente más lento. La razón es la sobrecarga de ejecutar el navegador y representar el HTML en el navegador. Este método solo debe usarse en casos excepcionales: casos en los que el contenido que queremos extraer utiliza código JavaScript en el navegador o requiere que hagamos clic en botones/enlaces para acceder a los datos, lo que Selenium puede hacer por nosotros.

2. Uso de bibliotecas HTTP

Bibliotecas HTTP, como el Módulo de solicitudes o Urllib, le permite enviar la solicitud HTTP, evitando la necesidad de abrir cualquier navegador, a diferencia del primer método. Siempre se debe preferir este método, ya que es mucho más rápido que Selenium.

Ahora déjame mostrarte cómo podemos lograr este componente de la canalización usando las bibliotecas Selenium y Requests:

Uso de solicitudes

Instale el módulo requests con lo siguiente:

1
$ pip install requests

Y ahora puedes usarlo en tu código, así:

1
2
3
4
import requests

result = requests.get('http://quotes.toscrape.com/')
page = result.text

Aquí, se realiza una solicitud HTTP GET a la URL, que es casi sinónimo de descargar la página web. Luego, podemos obtener la fuente HTML de la página accediendo al objeto de resultado devuelto por el método requests.get().

Usando selenio

Puede instalar el módulo selenium a través de pip:

1
$ pip install selenium
1
2
3
4
5
from selenium import webdriver

driver = webdriver.Chrome()
driver.get('http://quotes.toscrape.com/')
page = driver.page_source

Aquí, primero comenzamos creando un objeto webdriver, que representa el navegador. Al hacer esto, se abrirá el navegador Chrome en la computadora que ejecuta el código. Luego, llamando al método get del objeto webdriver, podemos abrir nuestra URL. Y finalmente, obtenemos el código fuente accediendo a la propiedad page_source del objeto webdriver.

En ambos casos, la fuente HTML de la URL se almacena en la variable de página como una cadena.

Análisis de HTML y extracción de datos

Sin entrar en informática teórica, podemos definir el análisis sintáctico como el proceso de analizar una cadena para que podamos comprender su contenido y, por lo tanto, acceder fácilmente a los datos que contiene.

En Python, hay dos bibliotecas que nos pueden ayudar con Parsing HTML: HermosaSopa y Lxml. Lxml es un marco de un nivel más bajo que BeautifulSoup, y podemos usar Lxml como back-end en BeautifulSoup, por lo que, para fines de análisis de HTML simple, BeautifulSoup sería la biblioteca preferida.

Pero antes de sumergirnos en el análisis, tenemos que analizar el HTML de la página web y ver cómo se estructuran y ubican los datos que queremos extraer. Solo cuando estamos armados con esa información, podemos obtener la información que queremos del HTML analizado. Pero afortunadamente, no tendremos que abrir el código fuente en un editor y comprender y correlacionar manualmente cada elemento HTML con los datos correspondientes en la página renderizada. La mayoría de los navegadores ofrecen un inspector, como Herramientas para desarrolladores de Chrome, que nos permite ver rápidamente el código HTML de cualquier elemento con solo haciendo clic en ellos.

Para hacer esto en Chrome, abra la página web en Chrome, luego haga clic con el botón derecho en los datos que desea extraer y seleccione Inspeccionar. En Firefox, esta opción se llama Inspeccionar elemento, que es lo mismo, pero con un nombre diferente.

{.img-responsive}

Notarás un panel abierto en la parte inferior de la ventana de Chrome, que contiene el código fuente del elemento en el que hiciste clic. Examine un poco el código fuente para hacerse una idea de cómo se estructuran en el código HTML los datos que queremos extraer.

{.img-responsive}

Como puedes entender después de un poco de inspección, cada cita en http://quotes.toscrape.com/ está contenida en un div con el atributo class="quote". Dentro de ese div, el texto de la cita está en un span con class="text" y el nombre del autor está en una etiqueta pequeña con class="author". Esta información será necesaria cuando lleguemos a analizar el HTML y extraer nuestros datos.

{.img-responsive}

Ahora, comencemos a analizar la página HTML usando BeautifulSoup. Pero antes, debemos instalarlo:

1
$ pip install beautifulsoup4

Una vez instalado, puede llamarlo en su código de esta manera:

1
2
3
from bs4 import BeautifulSoup

soup = BeautifulSoup(page, 'html.parser')

En primer lugar, creamos una versión analizada de la página pasándola al constructor de la clase BeautifulSoup. Como puede ver, también pasamos un segundo argumento al constructor, html.parser. Ese es el nombre del analizador que Beautiful Soup usará para analizar la cadena que le pasaste. También podría haber usado el analizador lxml, del que hablamos anteriormente, dado que tiene instalada la biblioteca Lxml.

1
quotes = soup.find_all('div', class_='quote')

Luego, extraemos todas las etiquetas div en la página que contiene class="quote", ya que sabemos que esos son los div que contienen comillas. Para hacer esto, Beautiful Soup 4 ofrece una función find_all. Pasamos el nombre de la etiqueta y el nombre de la clase a la función find_all, y devolvió todas las etiquetas que satisfacían las condiciones, es decir, las etiquetas que contenían nuestras comillas.

Una cosa importante a tener en cuenta aquí es que estamos trabajando con estructuras de árbol aquí. La variable sopa, y también cada elemento de comillas, son árboles. En cierto modo, los elementos de quotes son partes del árbol sopa más grande. De todos modos, sin caer en una discusión diferente, sigamos.

1
2
3
4
5
scraped = []
for quote in quotes:
    text = quote.find('span', class_='text').text
    author = quote.find('small', class_='author').text
    scraped.append([text, author])

Sabemos que el texto de la cita está en una etiqueta span con class="text" y el autor está en una etiqueta pequeña con class="author". Para extraerlos de los elementos de la cita, nuevamente empleamos una función similar, buscar. La función find toma los mismos argumentos que la función find_all. La única diferencia es que devuelve la primera etiqueta que cumple las condiciones, mientras que find_all devuelve una lista de etiquetas. Además, queremos acceder a la propiedad texto del objeto devuelto, que contiene el texto encerrado dentro de esa etiqueta.

Entonces, como puede ver en el código, recorremos todos los elementos de la lista quotes y extraemos el texto de la cita y el nombre del autor, almacenándolos como una lista de listas con el nombre raspado. La lista raspada, cuando se imprime en la consola, se ve así:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
[['“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”',
  'Albert Einstein'],
 ['“It is our choices, Harry, that show what we truly are, far more than our abilities.”',
  'J.K. Rowling'],
 ['“There are only two ways to live your life. One is as though nothing is a miracle. The other is as though everything is a miracle.”',
  'Albert Einstein'],
 ['“The person, be it gentleman or lady, who has not pleasure in a good novel, must be intolerably stupid.”',
  'Jane Austen'],
 ["“Imperfection is beauty, madness is genius and it's better to be absolutely ridiculous than absolutely boring.”",
  'Marilyn Monroe'],
 ['“Try not to become a man of success. Rather become a man of value.”',
  'Albert Einstein'],
 ['“It is better to be hated for what you are than to be loved for what you are not.”',
  'André Gide'],
 ["“I have not failed. I've just found 10,000 ways that won't work.”",
  'Thomas A. Edison'],
 ["“A woman is like a tea bag; you never know how strong it is until it's in hot water.”",
  'Eleanor Roosevelt'],
 ['“A day without sunshine is like, you know, night.”',
  'Steve Martin']]

Almacenamiento de los datos recuperados

Una vez que hemos adquirido los datos, podemos almacenarlos en el formato que queramos, por ejemplo, un archivo CSV, una base de datos SQL o una base de datos NoSQL. Para ser estrictos, este paso no debería contar como parte del proceso de raspado, pero aún así, lo cubriré brevemente para que esté completo.

Diría que la forma más popular de almacenar datos raspados es almacenarlos como hojas de cálculo CSV, así que le mostraré cómo hacerlo, muy brevemente. No entraré en detalles, para eso debes consultar la documentación oficial de Python. Entonces, sin más preámbulos, pasemos al código.

1
2
3
4
5
6
import csv

with open('quotes.csv', 'w') as csv_file:
    writer = csv.writer(csv_file, delimiter=',')
    for quote in scraped:
        writer.writerow(quote)

Como podemos ver, el código es bastante autoexplicativo. Estamos creando un objeto CSV writer a partir del archivo quotes.csv abierto, y luego escribiendo las comillas una por una usando la función writerow. Como es evidente, la función writerow acepta una lista como entrada y luego la escribe en el CSV como una fila.

Conclusión y próximos pasos

Este tutorial debería ayudarlo a comprender de qué se trata básicamente el raspado mientras aprende a implementar un raspador simple usted mismo. Este tipo de raspador debería ser suficiente para la automatización simple o la recuperación de datos a pequeña escala. Pero si desea extraer grandes cantidades de datos de manera eficiente, debe buscar marcos de scraping, especialmente [raspado] (https://scrapy.org/). Te ayudará a escribir raspadores muy rápidos y eficientes usando unas pocas líneas de código. Independientemente del marco que utilice, debajo de esa superficie brillante, ese marco también utiliza estos principios básicos de raspado, por lo que comprender este tutorial debería ayudarlo a desarrollar el conocimiento fundamental para sus aventuras de desguace.