sábado, 5 de agosto de 2017

Extraer Datos Estructurados, desde Sitios Web con Scrapy.


Vamos a explicar como utilizar  Scrapy, el cual es un framework open source construido con python, permite recuperar información desde paginas webs en forma estructurada.

Como ejemplo, utilizaremos el sitio web de supercom.gob.ec, en dicho sitio existe una pagina con un listado de medios de comunicación del Ecuador con la siguiente información: Nombre, sitio web, redes sociales. Vamos a trabajar con los canales de televisión. 

Para trabajar con Scrapy, demos tener conocimientos básicos sobre:
  • Ejecutar script con Python.
  • Conocer Html/CSS, o XPath.

Utilizaremos  Selectores CSS, para obtener un listado de medios de televisión existentes en Ecuador, los cuales se encuentran en la siguiente pagina:


Lo primero que debemos hacer, es analizar donde se encuentran los datos que vamos a extraer, para lo cual buscamos selectores CSS o etiquetas HTML que contengan los datos, podemos utilizar la herramienta de desarrollo del Chrome para este fin.



Figura 1. Inspector de Elementos de las herramientas de Desarrollo de Chrome.

El inspector de elementos, nos indica que la información de cada canal de televisión se encuentra dentro un "div" el cual posee una clase css "span6", dicho div contiene toda la información del canal de televisión, observe la figura 1. 

<div class="span6">
... Información del Canal ...
 </div>
Dentro de este bloque, el nombre del canal se encuentran en una  etiqueta "h2", con css "lead page-header", adicional el nombre es un enlace web, por lo tanto esta encerrado en una etiqueta  "a". Con el cual podemos utilizar el selector 'h2.page-header a' para obtener el nombre del canal. 

<h2 class="lead page-header">
<a href="...">TV Satelital</a> 
</h2>

Con los selectores analizados,  vamos a crear el spider de scrapy. Para lo cual creamos un archivo television_spider.py con el siguiente código:


import scrapy
class TelevisionSpider(scrapy.Spider):
name = 'Television'
start_urls = ['http://www.supercom.gob.ec/es/informate-y-participa/directorio-de-medios/22-television']
def parse(self, response):
for tv in response.css('div.span6'):
yield {
'titulo': tv.css('h2.page-header a::text').extract_first()
}

Explicamos linea por linea:
  • Linea 1. Importar la librearía scrapy.
  • Linea 3. Creamos nuestro spider, para lo cual hacemos una clase "TelevisionSpider" que herede de la clase "scrapy.Spider".
  • Linea 4. Le damos un nombre a  nuestro spider, utilizando la propiedad 'name'.
  • Linea 5. Establecemos las urls de las paginas web de las cuales vamos a obtener los datos. Para lo cual utilizamos la propiedad start_urls
  • Linea 7. Sobrecargamos el  método parse  de la clase, este método posee un parámetro response, el cual nos permite procesar el contenido de las urls establecidas en la Linea 5. 
  • Linea 9. Conocemos que cada canal de televisión, esta dentro de un <div class='span6>...</div>, entonces utilizamos el selector css 'div.span6'. El objeto response contiene un método css, el cual permite utilizar selectores css para extraer información. La instrucción "for tv in response.css('div.span6'):", indica al spider que obtengan todos los elementos que cumplan el selector, recorremos cada elemento encontrado.   
  • Linea 10,11,12. Para obtener el nombre del canal de televisión utilizamos el selector css 'h2.page-header a', como nos interesa el texto de la etiqueta "a", utilizamos la variante "::text", por lo cual el selector final seria 'h2.page-header a::text'. Utilizamos el método extract_first(), para guardar el contenido en el campo 'titulo' de nuestros datos extraídos.  

Para ejecutar nuestro spider utilizaremos el siguiente comando:

>>scrapy runspider television_spider.py -o datos.json

Nota. Observe que el nombre del  archivo "television_spider.py", debe corresponder al nombre de la clase del spider, en este caso sera  "TelevisionSpider" con estilo PascalCase.

Los datos generados son los siguientes:

[
{"titulo": "TV Satelital"},
{"titulo": "Ecuador TV (Canal 7)"},
{"titulo": "Teleandina (Canal 23)"},
{"titulo": "Ecuavisa (Canal 8)"},
{"titulo": "Unimax TV"},
{"titulo": "Ecuavisa Internacional (Canal 42)"},
{"titulo": "TV COLOR (Canal 36)"},
{"titulo": "Gama TV (Canal 2)"},
{"titulo": "TC Televisi\u00f3n"},
{"titulo": "Educa TV"},
{"titulo": "Teleamazonas"},
{"titulo": "Asomavisi\u00f3n (Canal 27)"},
{"titulo": "Canal Uno"},
{"titulo": "Ally TV"},
{"titulo": null},
{"titulo": null}
]
view raw datos.json hosted with ❤ by GitHub
Como se observa al final existen dos elementos nulos, esto se debe a que el selector "div.span6" se utiliza en otra parte de la pagina para algo diferente que contener la información del canal. Debemos ser mas específicos en el selector, podemos utilizar el contenedor de todos los canales, en este caso es "div.entry-container", por lo cual nuestro selector seria "div.entry-container div.span6".

import scrapy
class TelevisionSpider(scrapy.Spider):
name = 'Television'
start_urls = ['http://www.supercom.gob.ec/es/informate-y-participa/directorio-de-medios/22-television']
def parse(self, response):
for tv in response.css('div.entry-container div.span6'):
yield {
'titulo': tv.css('h2.page-header a::text').extract_first()
}

Volvemos a ejecutar el spider con los cambios realizados, esta vez los datos generados no existen elementos nulos.

Hasta el momento se ha obtenido el nombre del canal, para obtener los otros datos,  analizamos las etiquetadas html y clases css, que contenga dichos datos. A continuacion se enumeran los diferentes datos con los selectores correspondientes que los contienen:
  • Dirección: div.spField.field_direccion
  • Teléfono: div.spField.field_telefono
  • Fax:  div.spField.field_fax
  • Sitio Web: div.spField.field_sitio_web
  • Email: div.spField.field_email
  • Twitter: div.spField.field_twitter

Con este análisis, modificamos nuestro código para recuperar todos los datos:

import scrapy
class TelevisionSpider(scrapy.Spider):
name = 'Television'
start_urls = ['http://www.supercom.gob.ec/es/informate-y-participa/directorio-de-medios/22-television']
def parse(self, response):
for tv in response.css('div.entry-container div.span6'):
yield {
'titulo': tv.css(' h2.page-header a::text').extract_first(),
'Direccion': tv.css('div.spField.field_direccion').extract_first(),
'Telefono': tv.css('div.spField.field_telefono').extract_first(),
'Fax': tv.css('div.spField.field_fax').extract_first(),
'Sitio Web': tv.css('div.spField.field_sitio_web').extract_first(),
'Email': tv.css('div.spField.field_email').extract_first(),
'Twitter': tv.css('div.spField.field_twitter').extract_first(),
}
El listado completo de canales, se encuentra en varias paginas, en nuestro ejemplo exactamente en cinco paginas. Podemos utilizar una opción estática para obtener toda la información, la cual consiste en  colocar el listado de todas las cinco url de las paginas en la propiedad "start_urls" de  la clase.

import scrapy
class TelevisionSpider(scrapy.Spider):
name = 'Television'
start_urls = ['http://www.supercom.gob.ec/es/informate-y-participa/directorio-de-medios/22-television',
'http://www.supercom.gob.ec/es/informate-y-participa/directorio-de-medios/22-television?site=2',
'http://www.supercom.gob.ec/es/informate-y-participa/directorio-de-medios/22-television?site=3',
'http://www.supercom.gob.ec/es/informate-y-participa/directorio-de-medios/22-television?site=4',
'http://www.supercom.gob.ec/es/informate-y-participa/directorio-de-medios/22-television?site=5']
def parse(self, response):
for tv in response.css('div.entry-container div.span6'):
yield {
'titulo': tv.css(' h2.page-header a::text').extract_first(),
'Direccion': tv.css('div.spField.field_direccion::text').extract_first(),
'Telefono': tv.css('div.spField.field_telefono::text').extract_first(),
'Fax': tv.css('div.spField.field_fax::text').extract_first(),
'Sitio Web': tv.css('div.spField.field_sitio_web::text').extract_first(),
'Email': tv.css('div.spField.field_email::text').extract_first(),
'Twitter': tv.css('div.spField.field_twitter::text').extract_first(),
}
Esta opción estática, no es muy recomendada, scrapy posee opciones mas dinámicas que nos permiten tratar escenarios de paginación, en un próximo post explicaremos estas opciones.








Related Posts:

  • Crear Encuestas con PollDaddyPolldaddy, nos ofrece la opcion de crear encuestas enlinea para nuestros sitios web. Nos ofrece 19 templates diferentes, ofrecer la posibilidad de que un lector pueda responder varias veces o no, crear una opción alternativa … Read More
  • Aplicaciones Web Utilizando - Ext.jsExt.js, Es un framwrork de javascript que nos ofrece una gran cantidad de widgets para crear interfaces de usuario complejas hechas en paginas web igual como las interfaces de usuario de los programas de escritorio.Alguna… Read More
  • xml-sitemaps.com, te permite generar un Sitemap de tu sitio webEsta herramienta te permite generar un SiteMap en linea, con solo proporcionar nuestra direccion del sitio. La herramienta tiene una limitación de generar 500 enlaces en la version gratuita, si tu sitio cuenta con un numero m… Read More
  • Los mejores sitios web e iniciativas TICs del Ecuador, 2008La Alianza Tecnológica Ecuatoriana, integrada por ISOC Ecuador, Colegio de Ingenieros Eléctricos y Electrónicos de Pichincha, CIEEPI y sector TICs de la Cámara de la Pequeña Industria de Pichincha, CAPEIPI, junto con la Corpo… Read More
  • Opciones para Guardar y Editar tus documentos en LineaExiste varias opciones para mantener nuestros documentos en linea ya sea como respaldo o para editarlos directamente en línea, lo que nos permite acceder desde cualquier computador con acceso a Internet y un navegador.A conti… Read More

0 comentarios: