Google+ Seguidores

miércoles, 10 de agosto de 2016

Web Scraping con Python y BeautifulSoup

    20

Web Scraping con Python y BeautifulSoup
Web Scraping con Python y BeautifulSoup
Hace tiempo tenía ganas de escribir sobre web scraping utilizando Python, para el que no conozca, sería lo mismo que decir "Extraer datos de paginas web utilizando Python".

Los motivos de escribir sobre el tema son muchos, pero enumero algunos:
1 - Hay muchos pedidos de trabajos en lo que respecta a la extracción de datos  web
2 - En el momento el tiempo que tengo para escribir en el blog no es mucho y me gustaría que este tema vaya quedando registrado en el "Diario".
3 - Luego de incursionar un poco en este mundo del Scraping se darán cuenta de lo mucho que se puede hacer con algunas lineas de código y un poco de imaginación.

Comparto el repositorio de GitHub: https://github.com/DiegoCaraballo/Web-Scraping-con-Python-y-BeautifulSoup.git

Un tema a tener en cuenta a la hora de meternos a extraer datos mediante scripts en una página web es leer los Términos y Condiciones de la página raspada, ya que hay muchas paginas que "no lo permiten".
También comentarles que sería apropiado tener algún conocimiento de HTML para que no resulte tedioso.

Demás esta decir que debemos tener instalado python. Las pruebas que comparto más abajo las hice en un sistema Linux, pero en otras oportunidades lo he hecho en Windows y funcionan correctamente.
1 - Como instalar Python en Linux
2 - Como instalar Python en Windows

Las herramientas
Las tareas básicas para extraer los datos de un sitio son dos:
  1. Cargar una página web
  2. Analizar el HTML de la página para localizar los datos que nos interesan
Python nos ofrece dos excelentes herramientas para las tareas antes mencionadas. Vamos a utilizar requests para cargar una pagina web y BeautifulSoup para hacer el análisis.

Para instalar estas librerías podemos utilizar pip:
  • $ pip install requests
  • $ pip install beautifulsoup4
Puedes ver también: Como instalar pip en Linux y Windows

BeautifulSoup nos proporciona algunos métodos simples y Pythonicos para navegar y buscar extraer lo que necesitamos.

Técnica de Scraping Básica
Lo primero que debemos hacer a la hora de querer extraer datos de una/s pagina web es inspeccionar manualmente la pagina para determinar como podemos localizar los datos.
Para comenzar, vamos a extraer algunos datos del blog, como por ejemplo su título y todas sus páginas internas. También puedes probar con la URL que quieras.

En los comentarios del código les explico cada línea:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Sitio: http://www.pythondiario.com
# Autor: Diego Caraballo

# Haciendo pruebas con BeautifulSoup y requests

# Importamos las librerias
from bs4 import BeautifulSoup
import requests

# Capturamos la url ingresada en la variable "url"
url = raw_input("Ingrese la URL: ")

# Capturamos el hml de la pagina web y creamos un objeto Response
r  = requests.get("http://" +url)
data = r.text
print ""

# Creamos el objeto soup y le pasamos lo capturado con request
soup = BeautifulSoup(data, 'lxml')

# Capturamos el titulo de la página y luego lo mostramos
# Lo que hace BeautifulSoup es capturar lo que esta dentro de la etiqueta title de la url
titulo = soup.title.text
print "El titulo de la pagina es: " + titulo
print ""

# Buscamos todas etiquetas HTML (a) y luego imprimirmos todo lo que viene despues de "href"
for link in soup.find_all('a'):
    print(link.get('href'))

Como dije anteriormente, esto nos devolverá los el título de la página y los enlaces de la misma.

Script que devuelve Titulo y enlaces de una pagina cualquiera
Script que devuelve Titulo y enlaces de una pagina cualquiera

Ahora veremos otro ejemplo de como utilizar BeautifulSoup.

Lo que haremos ahora será extraer la temperatura en Beijing (China), no me preguntes porque elegí china jeje, espero que los administradores de la página no se enojen ;)

Lo que hace el script es ingresar en la página, obtener los datos necesarios (temperatura y sensación térmica) y mostrarlos infinitamente cada X segundos (en mi caso puse 15seg para que se aprecie). Cada vez que la pagina actualice la temperatura, nuestro script también actualizara los datos sin tener que estar entrando en la pagina (lindo no?). ¿Se imaginan haciendo una página que se provea de información desde otros sitios haciendo scraping? Si, se puede!!!, de hecho, hay millones ;)

En los comentarios del código explico lo que hace. Para obtener los datos deseados debemos hacer lo siguiente:

Las pruebas las hice con el navegador Mozilla, pero también las he hecho en Chrome

  1. Ingresar por el navegador a la url deseada, en nuestro caso: http://www.timeanddate.com/weather/china/beijing
  2. Dentro de la página, buscamos el dato a extraer. Mostraré el ejemplo de la temperatura, pero para la sensación térmica es igual.
Temperatura en Beijing
Temperatura en Beijing
    3. Ahora hacemos clic con el botón secundario en el 27 y elegimos "Inspeccionar elemento", veremos algo como lo siguiente:

Etiquetas que contienen la temperatura
Etiquetas que contienen la temperatura

    4. Lo que necesitamos nosotros para obtener la temperatura, es sacar lo que está dentro de la etiqueta "div" (class - h2), la temperatura. Esto lo capturamos con BeautifulSoup y lo devolvemos como texto.

    5. En un principio quizá nos resulte complicado, pero la practica ayuda mucho. También comentarles que cada página es un mundo a parte, debemos inspeccionarla y buscarle la vuelta para extraer los datos.

Les dejo el código:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# Sitio: http://www.pythondiario.com
# Autor: Diego Caraballo

# Haciendo pruebas con BeautifulSoup y requests

# Importamos las librerias
from bs4 import BeautifulSoup
import requests
import time
import os

# Creamos el Bucle infinito
while True:

 # Capturamos la url 
 url = "http://www.timeanddate.com/weather/china/beijing"

 # Capturamos el hml de la pagina web y creamos un objeto Response
 r  = requests.get(url)
 data = r.text

 # Creamos el objeto soup y le pasamos lo capturado con request
 soup = BeautifulSoup(data, 'lxml')

 # Buscamos el div para sacar los grados
 temp = soup.find_all('div', class_="h2")

 # Buscamos el div para sacar la sensacion termica
 sTerm = soup.find_all('div', class_="clear")
        
        # Con [0] saco el primer elemento y con [1] el segundo
 print "La temperatura en Beijing: " + temp[0].text
 print "La sesacion termica: " + sTerm[1].text
 
 # Tiempo en segundos para ejecutarse nuevamente
 time.sleep(15)
 
 # Boramos los datos viejos, para Windows es "cls"
 os.system("clear")

Script que devuelve temperatura
Script que devuelve temperatura

Solo resta decir que tengo más por compartirles, pero lo veremos en futuras entradas. Pueden seguir investigando por su cuenta y cualquier aporte o comentario siempre es bienvenido. Saludos, Diego.

20 comentarios:
Write comentarios
  1. Buenísimo, no tenia idea del Web Scraping. Ya hice una prueba con el clima de mi ciudad del sitio web del SMN.

    ResponderEliminar
    Respuestas
    1. Gracias por el aporte. Saludos. :)

      Eliminar
    2. Excelente Emanuel, lo de extraer el clima fue un ejemplo sencillo, pero metiendo mano puedes hacer mucha cosa. Cuando tenga algo nuevo armado lo compartiré. Saludos y gracias por visitar el blog ;)

      Eliminar
  2. Hola. Utilizo Qpython y he conseguido meter la librería requests pero no se que librería habría que meter para el BeautifulSoup me da error el bs4

    ResponderEliminar
    Respuestas
    1. Hola, he utilizado QPython solo un par de veces, no sabría decirte como instalarle librerías, pero por lo que veo te falta la librería "bs4" que contiene BeautifulSoup. Saludos y gracias por visitar el blog.

      Eliminar
  3. Gracias Diego. He bajado bs4 y he metido la carpeta en el mismo directorio que metí requests pero me sigue dando error. Seguiré investigando. Estoy muy interesado en el Scraping.

    ResponderEliminar
    Respuestas
    1. Recién busque en google "install library qpython", hay varios documentos que quizá te sean de ayuda. Saludos

      Eliminar
  4. Gracias por tu paciencia Diego. La verdad es que estoy aprendiendo mucho con las dificultados. no me rindo. He conseguido bajar pip, con el, meter requests y beautifulsoup, tanto en la tablet como en windows, pero... en ambos sitios al utilizar el beautifulsoup (data, 'lxml') me da el siguiente error:
    Traceback (most recent call last):
    File "C:/Python27/url.py", line 7, in
    soup=BeautifulSoup(data, 'lxml')
    File "C:\Python27\lib\site-packages\bs4\__init__.py", line 165, in __init__
    % ",".join(features))
    FeatureNotFound: Couldn't find a tree builder with the features you requested: lxml. Do you need to install a parser library?
    Alguna idea? Saludos.

    ResponderEliminar
    Respuestas
    1. Hola Federico. Te está faltando el paquete "lxml"
      Para android no tengo mucha idea, te dejo el enlace de GitHub --> https://github.com/qpython-android

      Con PIP puedes instalarlo - pip install lxml

      Saludos

      Eliminar
  5. Ya me rindo. He intentado instalar el lxml en android, en windows, para python 2.7 y 3.6 y nada. En el 2.7 para windows me pedia algo de visual c y lo he instalado, pero despues al volver a instalar lxml me daba errores de que faltaban carpetas. En el 3.6 me pide que instale el visual c++ y ya me he cansado. En casa tengo una maquina con linux, lo intentare alli. Gracias por tu ayuda y perdona el c...Saludos.

    ResponderEliminar
    Respuestas
    1. Federico en Windows debes instalar lxml desde el MS Windows Installer packages descargalo de aquí https://pypi.python.org/pypi/lxml/3.3.5#downloads

      Eliminar
    2. Excelente aporte Brian. Saludos!!!

      Eliminar
  6. Hola a todos.

    Quiero dejarles una duda que tengo:

    " a href="?contID=XXXX" class="button lime">Leer m�s →</a "

    De la linea anterior, me interesaría sacar el dato que está dentro de href entre colmillada. Al hacer la prueba, obtuve el dato "Leer más" y no es lo que quiero, sino "?contID=XXXX". Es parte de la URL de un articulo. ¿Es posible?

    Espero que se entienda mi planteo.

    Muchas gracias a todos por su tiempo. Saludos.-

    ResponderEliminar
    Respuestas
    1. Hola Emanuel, como estas?
      Es una url específica? o son varias?

      from bs4 import BeautifulSoup

      html = # your HTML

      soup = BeautifulSoup(html)

      for item in soup.find_all(attrs={'class': 'nombre de clase'}):
      ----for link in item.find_all('a'):
      --------print link.get('href')

      Ahi te va a mostrar las url enteras de la clase seleccionada. Puedes capturar las URL como string en una lista y extraer la que tu necesitas. Luego crear alguna simple función que te devuelva parte de la URL.

      Es lo que se me ocurre ahora, pero calculo BeautifulSoup tiene algo más sencillo.

      Saludos, Diego.

      Eliminar
    2. Muchas gracias por tu pronta respuesta, me ayudo mucho.

      Del sitio que quiero extraer los datos, cada articulo tiene la url a "medias".

      Lo que me sirvió fue "print link.get('href')" obviamente que use otra variable en lugar de link y no necesite el ciclo for.

      Luego tengo que hacer lo siguiente:

      d = web[0]
      RN = "http://rionegro.gov.ar/"
      temp = d.get('href')

      print RN + temp

      y el resultado sería el siguiente: http://rionegro.gov.ar/?contID=31632

      Si yo hago "print web[0]" lo que obtengo es:

      " a class="button lime" href="?contID=31632">Leer más →</a "

      No se si se entiende mi explicación, pero básicamente logré lo que necesitaba y muchas gracias por tu ayuda nuevamente. Saludos.-

      Eliminar
    3. Me alegro que solucionaras. Saludos!!!

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

    ResponderEliminar
  8. Muy buen ejemplo, hace poco que estoy usando estas tecnicas.

    ResponderEliminar
  9. Hola amigo, estoy utilizando windows 10 me da el siguiente problema

    Traceback (most recent call last):
    File "MostrarEnlaces.py", line 21, in
    soup = BeautifulSoup(data, 'lxml')
    File "C:\Python27\lib\site-packages\bs4\__init__.py", line 165, in __init__
    % ",".join(features))
    bs4.FeatureNotFound: Couldn't find a tree builder with the features you requested: lxml. Do you need to install a parser library?

    ResponderEliminar
    Respuestas
    1. Hola Edudardo, gracias por visitar el blog. Prueba sacar la linea 'lxml'. O si no prueba instalar el módulo lxml

      Luego me cuentas!!!

      Saludos

      Eliminar

Tu comentario es importante y nos motiva a seguir escribiendo...

Entradas más recientes

© 2014 Mi diario Python. Designed by Bloggertheme9 | Distributed By Gooyaabi Templates
Powered by Blogger.