martes, 14 de octubre de 2014

PYTHON: CREANDO NUESTRA HERRAMIENTA DE WEB SCRAPING [I]

INTRODUCCIÓN

Este articulo esta diseñado para formar parte de una serie de entradas mas bien cortas en las que se irán incluyendo poco a poco funciones para ir ensamblando la herramienta.

Asumiré antes que nada que se tiene los conceptos básicos de Python y que ya se ha jugado un poco con el lenguaje, en caso de no ser así recomiendo ampliamente pasarse un par de minutos a learnpythonthehardway.org para aprender las bases y de forma adicional recomiendo revisar este link para los mensajes de error mas habituales. En lo personal me gusto mucho la guía aunque no fue precisamente el primer material sobre Python que cayo en mis manos. Establecido esto, podemos empezar.

¿QUE ES WEB SCRAPING ?

Web Scraping es básicamente recolectar información de paginas web, extrayendo lo que consideremos útil desde e-mails, links, recopilación de datos personales como nombre, teléfono, dirección etc. El proceso puede ser usado para la creación de herramientas OSINT y/o como complemento para tareas más... em... intrusivas y elaboradas - probablemente ilegales... es mas bien una área un tanto gris... tendría que investigarse bien la pagina a la que se esta sometiendo- como el pujado automático en sitios de subastas. Entre otras cosas.

EXTRAYENDO LA PAGINA.

De entrada, requeriremos extraer todo el código HTML de la pagina (o paginas) de las que queremos extraer o minar información. Para esto recurriremos a la siguiente función usando la librería de mechanize- se pueden lograr resultados similares usando urllib2:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def Extraer_HTML(URL):
    try:
        navegador = mechanize.Browser()                     # Inicializar Navegador
        navegador.set_proxies({"http": "97.77.104.22:80"})  # Establecer Proxy
        ncookie = cookielib.LWPCookieJar()                  # Cookie
        navegador.set_cookiejar(ncookie)
        navegador.set_handle_robots(False)                      # Ignorar Robots
        navegador.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1)
        navegador.addheaders = [('User-agent', USER_AGENT)]     # Establecer User-Agent
        respuesta = navegador.open(URL)                         # Abrir URL
        return  respuesta.read()                                # Regresar codigo fuente de la pagina
    except Exception, e:
        print "[ERROR: Extraer_HTML(URL)] - ",e
        sys.exit(1)

La función básicamente obtiene el código HTML y lo retorna para su posterior análisis y extracción de datos. Ese sera el alcance de esta entrada.  Nos permite cierto grado de anonimato estableciendo un proxy y mutando el user_agen al azar en cada consulta según la lista que tengamos agregada en un archivo llamado user_agent.txt que se encuentre ubicado en el mismo directorio donde ejecutemos el script que contenga la función - o podemos mapearlo de forma permanente según nos resulte mas cómodo. Se pueden encontrar algunas listas de  user_agent y proxys en los siguientes sitios:

User Agent:

Proxy:
-http://free-proxy.cz/en/

El script en general de momento solo tomara en cuenta la extracción del código de una pagina objetivo, sin separar nada de momento. Lo crearemos de tal forma que funcione con parámetros desde consola y dejaremos preparada la ayuda que se ira expandiendo conforme se anexen entradas relacionadas a este articulo:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#!/usr/bin/python -u
# -*- coding: utf-8 -*-
import mechanize
import cookielib
import sys
from random import choice

#VARIABLES GLOBALES
PROYECTO    = "WebScraping"
VERSION     = "v 0.1"
AUTOR       = "Rodrigo Anael Perez Castro"
TWITTER     = "@rapcx1981"

USER_AGENT  = {'User-Agent':(choice(open("user_agent.txt",'r').readlines()))}
PROXY       = (choice(open("proxy.txt",'r').readlines()))

#FUNCIONES
def Mostrar_Ayuda():
 try:
  print "\t[  -h --parametro] - Muestra detalle del parametro y ejemplos de uso."
  print "\t[-url --url      ] - Extrael el codigo fuente de la pagina indicada."
 except Exception, e:
  print "[Error: Mostrar_Ayuda()] - ", e
  sys.exit(1)

def Mostrar_Creditos():
        try:
            print "\t["+PROYECTO+"\t"+VERSION+"\t\t]"
            print "\t["+AUTOR+"\t]"
            print "\t["+TWITTER+"\t\t\t\t\t]\n"
        except Exception, e:
            print "[ERROR: Mostrar_Creditos()] - ", e
            sys.exit(1)

def Extraer_HTML(URL):
    try:
        navegador = mechanize.Browser()                     # Inicializar Navegador
        navegador.set_proxies({"http": "97.77.104.22:80"})  # Establecer Proxy
        ncookie = cookielib.LWPCookieJar()                  # Cookie
        navegador.set_cookiejar(ncookie)
        navegador.set_handle_robots(False)                      # Ignorar Robots
        navegador.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1)
        navegador.addheaders = [('User-agent', USER_AGENT)]     # Establecer User-Agent
        respuesta = navegador.open(URL)                         # Abrir URL
        return  respuesta.read()                                # Regresar codigo fuente de la pagina
    except Exception, e:
        print "[ERROR: Extraer_HTML(URL)] - ",e
        sys.exit(1)

def main():
    try:
        if len(sys.argv)<=1:
            Mostrar_Creditos()
            Mostrar_Ayuda()

        if len(sys.argv)>1:
            if sys.argv[1]=="-url":
                URL = sys.argv[2]
                R = Extraer_HTML(URL)
                print R
            elif sys.argv[1]=="-h":
                print 'En Contruccion...'

    except Exception, e:
        print "[ERROR: main()] - ",e

if __name__ == '__main__':
    main()

Usaremos la pagina httpbin.org para probar los cambios de user_agent y la veracidad del proxy. Podemos usar también whatsmyuseragent.com que nos muestra igualmente user_agent e IP al mismo tiempo, pero el resultado esta mas cargado debido al código HTML, por lo que, por cuestiones de practicidad y acomodo en este post dejare esa prueba a ustedes. Aqui solo se mostrara una parte como parte de nuestra prueba de testeo del script.

Apreciamos que el cambio aleatorio de user_agent funciona sin problemas:



También el proxy:



Y nos regresa sin problemas el código fuente de las pagina que consultamos:



Se pueden añadir algunas otras opciones y detalles, pero, para nuestro propósito y de momento esto bastara.

NOTAS:

-No he podido de momento hacer que el proxy se cambie al azar desde una lista en archivo de la misma manera que el user_agent... o, dicho de forma mas exacta, no que el objeto navegador lo tome... espero hacerlo funcionar en un futuro.
-El manejo de argumentos/parámetros en consola puede ser mejorado usando otra librería (argparse)... pero de momento no lo considero necesario y aun no la he explorado.
-Existen muchas formas de mejorar el script e incluso existen ya actualmente muchos que hacen lo mismo... En el libro de Violent Python ya viene incluida una clase para realizar esto de forma mas eficiente (Capitulo 6), sin embargo, considero básico realizar funciones propias y no simplemente acudir a un copy-paste. Ciertamente no hay mucha gracias en reinventar la rueda y tampoco mucho caso... pero para cuestiones de aprendizaje no hay nada mejor que ponerse a jugar y ver si podemos hacer lo que ya existe de manera diferente... es una simple consideración personal.

REFERENCIAS.

-http://es.wikipedia.org/wiki/Web_scraping
-http://www.osintinsight.com/shared.php?expand=&folderid=220&user=Mediaquest
-http://www.decalage.info/en/python/tutorial
-http://wwwsearch.sourceforge.net/mechanize/doc.html
-https://www.jetbrains.com/pycharm/
-Violent Python, TJ O'Connor
-http://www.pythonforbeginners.com/cheatsheet/python-mechanize-cheat-sheet
-http://stockrt.github.io/p/emulating-a-browser-in-python-with-mechanize/
-http://python.org.ar/MensajesExcepcionales
-http://stackoverflow.com/questions/10589620/syntaxerror-non-ascii-character-xa3-in-file-when-function-returns-%C2%A3



No hay comentarios:

Publicar un comentario

Nota: solo los miembros de este blog pueden publicar comentarios.