Web Scraping

Iniciado por MagoAstral, Diciembre 03, 2015, 02:14:45 PM

Tema anterior - Siguiente tema

0 Miembros y 1 Visitante están viendo este tema.

Hola a tod@s, soy MagoAstral y en esta ocasión aprenderemos los conceptos básicos del web scraping en python. Obviamente para los que no sepan que es o en que consiste esta técnica del web scraping haremos uso de nuestra querida e inmejorable wikipedia.
Web scraping es una técnica utilizada mediante programas de software para extraer información de sitios web. Usualmente, estos programas simulan la navegación de un humano en la World Wide Web ya sea utilizando el protocolo HTTP manualmente, o incrustando un navegador en una aplicación.
Ahora que tenemos clara la definición la siguiente cuestión que podría formularse sería ¿qué tipo de información puedo extraer? y la cual es respondida de forma simple, depende absolutamente de tu imaginación, nosotros para este aporte nos centraremos en obtener los títulos y direcciones URL de la biblioteca de nuestro foro, lo cual puede parecer algo tedioso pero veremos como en no mas de 5 líneas podemos realizar dicha tarea.
Como se ha mencionado anteriormente utilizaremos python para llevar a cabo nuestro web scraping y para hacer el proceso aún más sencillo haremos uso de dos librerías:
Las cuales nos ayudaran principalmente en el parseo de los datos HTML y en las peticiones para obtener dichos datos, obviamente deberéis instalarlas para poder hacer uso de las mismas (se supondrá que se saben instalar librerias, aun así es sencillo simplemente extraer la carpeta en la ruta de instalación de nuestro python), una vez instaladas se procederá con el proceso de web scraping.
Nuestro algoritmo sería algo como:

  • Obtener página en HTML
  • Parsear el contenido HTML
  • Sacar por pantalla de manera estructurada el resultado
Procedamos pues a familiarizarnos con la obtención del contenido de la página web, como mencionamos anteriormente haremos uso de la libreria "Requests", para eso debemos importarla, luego realizar la petición a la página web y mostrar el contenido de dicha petición cuya sintaxis sería:
Código: python
import requests
peticion = requests.get("http://biblioteca.underc0de.org")
print peticion.content

El cual nos devolvería correctamente el código fuente de la página una manera de verificar que estamos realizando correctamente las peticiones seria mirar el resultado de la petición el cual se obtendría mediante:
Código: python
print peticion.status_code

Y comos nos devuelve un 200 podemos asumir que significa todo va bien, en caso de que nos devuelva otro tipo de dato podríamos indagar sobre su significado (¿404?¿Not Found?), ahora que ya tenemos la primera parte de nuestro algoritmo podríamos destacar que dentro de "Beautiful Soup" tenemos un método llamado "prettify", el cual nos mostraría el contenido de manera organizada. Es un método a tener en cuenta, su uso puede servirnos en diversas ocasiones.
Ahora nos tocaría parsear el contenido HTML que almacenaremos en una variable, para eso haremos uso de otro método en este caso llamado "find_all" este nos ayuda a filtrar el contenido HTML por ejemplo si le pasamos una etiqueta ("a") nos devolvería todas las etiquetas HTML del tipo buscado, como nosotros queremos obtener los títulos si hacemos uso de un depurador web podemos ver lo siguiente:
Lo más lógico para poder extraer los títulos sería extraer el contenido de las etiquetas "td" cuya clase sea "noalign", así que sin mucho que pensar gracias a BeautifulSoup y un bucle sencillo para recorrer el contenido:
Código: python
import requests
from bs4 import BeautifulSoup

peticion = requests.get("http://biblioteca.underc0de.org/")

soup = BeautifulSoup(peticion.content)

for i in soup.find_all('td', {'class', 'noalign'}):
    print i

Lo cual nos devuelve:
Código: text
<td class="noalign">Nombre</td>
<td class="noalign"><a href="?dir=ARDUINO - RASPBERRY PI/"><div style="width: 100%; height: 100%;float: left;">ARDUINO - RASPBERRY PI</div></a></td>
<td class="noalign"><a href="?dir=CRIPTOGRAFIA/"><div style="width: 100%; height: 100%;float: left;">CRIPTOGRAFIA</div></a></td>
<td class="noalign"><a href="?dir=E-BOOKS/"><div style="width: 100%; height: 100%;float: left;">E-BOOKS</div></a></td>
<td class="noalign"><a href="?dir=E-ZINES/"><div style="width: 100%; height: 100%;float: left;">E-ZINES</div></a></td>
<td class="noalign"><a href="?dir=ESTEGANOGRAFIA/"><div style="width: 100%; height: 100%;float: left;">ESTEGANOGRAFIA</div></a></td>
<td class="noalign"><a href="?dir=HARDWARE - ELECTRONICA/"><div style="width: 100%; height: 100%;float: left;">HARDWARE - ELECTRONICA</div></a></td>
<td class="noalign"><a href="?dir=INFORMATICA FORENSE/"><div style="width: 100%; height: 100%;float: left;">INFORMATICA FORENSE</div></a></td>
<td class="noalign"><a href="?dir=INGENIERIA INVERSA/"><div style="width: 100%; height: 100%;float: left;">INGENIERIA INVERSA</div></a></td>
<td class="noalign"><a href="?dir=MALWARES/"><div style="width: 100%; height: 100%;float: left;">MALWARES</div></a></td>
<td class="noalign"><a href="?dir=OTROS/"><div style="width: 100%; height: 100%;float: left;">OTROS</div></a></td>
<td class="noalign"><a href="?dir=PENTESTING/"><div style="width: 100%; height: 100%;float: left;">PENTESTING</div></a></td>
<td class="noalign"><a href="?dir=PHREAK/"><div style="width: 100%; height: 100%;float: left;">PHREAK</div></a></td>
<td class="noalign"><a href="?dir=PROGRAMACION/"><div style="width: 100%; height: 100%;float: left;">PROGRAMACION</div></a></td>
<td class="noalign"><a href="?dir=QA/"><div style="width: 100%; height: 100%;float: left;">QA</div></a></td>
<td class="noalign"><a href="?dir=REDES/"><div style="width: 100%; height: 100%;float: left;">REDES</div></a></td>
<td class="noalign"><a href="?dir=SEGURIDAD - INSEGURIDAD/"><div style="width: 100%; height: 100%;float: left;">SEGURIDAD - INSEGURIDAD</div></a></td>
<td class="noalign"><a href="?dir=SEGURIDAD WEB/"><div style="width: 100%; height: 100%;float: left;">SEGURIDAD WEB</div></a></td>
<td class="noalign"><a href="?dir=SEO/"><div style="width: 100%; height: 100%;float: left;">SEO</div></a></td>
<td class="noalign"><a href="?dir=SISTEMAS OPERATIVOS/"><div style="width: 100%; height: 100%;float: left;">SISTEMAS OPERATIVOS</div></a></td>

En principio vamos bien, ya hemos logrado un intervalo similar al que buscábamos y con similar me refiero a que si hacemos uso del método "text" de Beautiful Soup el cual nos devuelve el texto que está en el interior de las etiquetas, nos devuelve todos los nombres y algo más:
Nombre
Y nosotros no queremos que incluya el contenido de la primera etiqueta "td" así que haremos un bucle anidado de manera que nos busque las etiquetas de las direcciones:
Código: python
import requests
from bs4 import BeautifulSoup

peticion = requests.get("http://biblioteca.underc0de.org/")

soup = BeautifulSoup(peticion.content)

for i in soup.find_all('td', {'class', 'noalign'}):
    for j in i.find_all('a'):
        print j

Ahora sí que nos devuelve únicamente las etiquetas que buscábamos de manera que si hacemos uso del método "text" nos devolvería algo tal que así:
Código: text
ARDUINO - RASPBERRY PI
CRIPTOGRAFIA
E-BOOKS
E-ZINES
ESTEGANOGRAFIA
HARDWARE - ELECTRONICA
INFORMATICA FORENSE
INGENIERIA INVERSA
MALWARES
OTROS
PENTESTING
PHREAK
PROGRAMACION
QA
REDES
SEGURIDAD - INSEGURIDAD
SEGURIDAD WEB
SEO
SISTEMAS OPERATIVOS

Correcto, ahora solos nos quedaría obtener el contenido de nuestro atributo "href" que es donde apunta el enlace y para eso haremos uso de otro sencillo método en este caso "get" al cual se le pasa como parámetro el filtro en este caso sería "href", pero nos encontramos ante otro problema algunos links tienen espacios en blanco por lo que no nos los reconocería como parte de la dirección así que si hacemos un reemplazo a dichos espacios en blanco tendríamos la solución a nuestro problema, por defecto el navegador codifica los espacios en blanco como "%20", el código sería el siguiente:
Código: python
import requests
from bs4 import BeautifulSoup

peticion = requests.get("http://biblioteca.underc0de.org/")

soup = BeautifulSoup(peticion.content)

for i in soup.find_all('td', {'class', 'noalign'}):
    for j in i.find_all('a'):
        print j.get('href').replace(" ","%20")

Y ahora que tenemos el título y el contenido simplemente hacemos una salida por pantalla estructurada:
Código: python
import requests
from bs4 import BeautifulSoup

peticion = requests.get("http://biblioteca.underc0de.org/")

soup = BeautifulSoup(peticion.content)

for i in soup.find_all('td',{'class','noalign'}):
    for j in i.find_all('a'):
        print "%s : http://biblioteca.underc0de.org/%s" %(j.text, j.get("href").replace(" ", "%20"))

El resultado:
Espero que os haya servido de algo y cualquier crítica / cuestión siéntanse libres de ponerse en contacto conmigo.
Un saludo,
MagoAstral
Lo que sabemos es una gota de agua; lo que ignoramos es el océano.


@No tienes permitido ver los links. Registrarse o Entrar a mi cuenta

Siempre es bueno y necesario leer este tipo de aportes.
Claro, explicativo y útil para los que no sabemos y aprendemos de él.

Gracias por tu tiempo y, fundamentalmente, por com-partir.

Gabi.
Tú te enamoraste de mi valentía, yo me enamoré de tu oscuridad; tú aprendiste a vencer tus miedos, yo aprendí a no perderme en tu abismo.

Como te dije antes, excelente aporte @No tienes permitido ver los links. Registrarse o Entrar a mi cuenta!

Otra librería interesante para realizar este tipo de tareas es No tienes permitido ver los links. Registrarse o Entrar a mi cuenta. Aquí dejo un código equivalente al último que presentaste:
Código: python
import mechanize

br = mechanize.Browser()
br.open("http://biblioteca.underc0de.org/")

for link in br.links():
  if "?dir" in link.url:
    print "{0} : {1}".format(link.text, link.url)


Este código no es más que para ejemplificar y, por supuesto, se podría mejorar muchísimo. Pero eso ya quedaría para otro post  ;)

Saludos!
WhiZ


Tenía previa noción de mechanize. Definitivamente request es muy funcional y con un api muy simple.

Gracias

MagoAstral, darte las gracias por tomarte el tiempo de escribir y aportar al foro.

Que buen POST!, justo me estoy iniciando en python y que mejor aprendizaje que comenzar con los paquetes requests y mechanize para respuestas y envíos de servicios web  +10

Gracias por el aporte, muy bien explicado para los que estamos empezando.


Jugar o perder

Gracias estoy interesado en este tema. Tengo en mente una web de futbol, por lo que me serviría para obtener datos de una web en específico.