import webbrowser

"""
Explanation: Extracción de datos web (Web scrapping)
Ante la generación masiva a traves de la red es importante tener herramientas que permitan la extracción de datos a partir de fuentes cuya ubicación es esta. De esto se trata el web scrapping.  
Se pueden tener elementos poco especificos mediante las mismas alternativas del procesamiento de texto para algunos casos, sin embargo esto no siempre será efectivo ni eficiente. Por ejemplo, podemos usar wget para descargar una página y hacer la búsqueda de elementos html en ella por medio de expresiones regulares, pero la descarga de la página implica que el contenido debio ser estatico. Igualmente, las expresiones regulares no son la mejor herramienta siempre, y es más eficiente usar elementos especialmente diseñados para recorrer la estructura html sin depender de la generación de expresiones de coincidencia sino obedeciendo exclusivamente a los patrones que ya sabemos que existirán por defecto.  
Herramientas (en python)
Para esta labor contamos con algunas herramientas como lo son:  

urllib: Modulo incluido en python para la recuperación de contenido de una url.  
webbrowser: Modulo incluido en python para la apertura de url's en una instancia del navegador predefinido.  
html: Modulo incluido en python para el analisis sintactico html.  
Request: Reemplazo externo para urllib con mayores caracteristicas.  
Beautiful Soup: Reemplazo externo para html con mayores caracteristicas.  
Selenium: Reemplazo externo para webbrowser con mayores caracteristicas.  
Wget: Port de wget para python.  

Instalar requisitos
Primero que todo, partimos que ya tenemos instalado al menos un navegador (firefox por defecto en la mayor parte de las distribuciones linux). Se puede trabajar con otros navegadores, y es de especial interes PhantomJS, una opción de navegador que no genera interface gráfica, ideal para pruebas o automatización (en caso de ser molesto que el navegador se vea abrir y cerrar, etc...).  
pip install selenium beautifulsoup4 Requests

Aplicando
End of explanation
"""


webbrowser.open('http://github.com/')

"""
Explanation: Al usar la función open de webbrowser se abrirá el navegador o una pestaña nueva si el navegador ya estaba abierto. Ya que no indicamos el navegador, esto se realiza con el navegador configurado por defecto en nuestro sistema. Se puede usar para abrir pestañas y ventanas nuevas, cerrarlo, y tambien usar un navegador especifico.
End of explanation
"""


import requests
res = requests.get('http://www.gutenberg.org/files/18251/18251-0.txt')
res.status_code == requests.codes.ok # Validar código 200 (ok)
type(res)
len(res.text)
print(res.text[:250])

"""
Explanation: Sin embargo, la labor de extracción web depende de obtener el código fuente o elementos disponibles en las páginas, lo cual es imposible con solo abrir el navegador. Para este fin es posible usar urllib o como lo haremos en esta sesión, con request.
End of explanation
"""


res = requests.get('http://github.com/yomeinventoesto')
res.raise_for_status()

"""
Explanation: Ante un fallo en el proceso de obtención del código con la función get, es posible generar una notificación del motivo de fallo.
End of explanation
"""


res = requests.get('http://www.programmableweb.com/sites/default/files/github-jupyter.jpg')
archivo_imagen = open('github-jupyter.jpg', 'wb')
for bloques in res.iter_content(100000):
    archivo_imagen.write(bloques)
archivo_imagen.close()

"""
Explanation: Cuando obtenemos un elemento de una dirección, este se encuentra como binario y no como texto plano. Esto nos facilita algunas cosas. Nos permite descargar contenido que no se solo texto plano (archivos de texto o código fuente) sino tambien directamente archivos binarios como imagenes, ejecutables, videos, archivos de word y otros. Es importante aclarar, que si vamos a almacenar el archivo de texto plano, debemos hacerlo con creación de archivos binarios para no perder la codificación original que tenga el archivo.
End of explanation
"""


import bs4

"""
Explanation: En el bloque anterior, el método iter_content genera bloques del archivo con el tamaño indicado en su argumento. Esto conviene para la escritura de archivos de gran tamaño.
End of explanation
"""


res = requests.get('https://github.com/cosmoscalibur/herramientas_computacionales')
gh = bs4.BeautifulSoup(res.text, "lxml")
type(gh)

"""
Explanation: Usarmos ahora bs4 (forma de importar Beautiful Soup), lo cual nos permitirá la búsqueda de texto y estructuras html especificas. Este es más conveniente que usar expresiones regulares directamente en el código fuente.  
Al crear el objeto, debemos indicar el texto sobre el cual actuará (puede ser obtenido directamente de un archivo abierto tambien) y el tipo de analizador sintactico, en este caso lxml.
End of explanation
"""


tabla_archivos = gh.find_all('td', {'class':'content'})
type(tabla_archivos)

"""
Explanation: Ahora, buscaremos todas las estructuras td que tengan el atributo class con valor content.
End of explanation
"""


len(tabla_archivos)

print(tabla_archivos)

"""
Explanation: El resultado es una lista con todos los resultados obtenidos. Tambien es posible una búsqueda uno a uno, usando find en lugar de find_all.
End of explanation
"""


for content in tabla_archivos:
    lineas_a = content('a')
    if lineas_a:
        texto = "Se encontro el archivo '{}'".format(lineas_a[0].string.encode("utf-8"))
        texto += " con enlace '{}'.".format(lineas_a[0].get("href"))
        print(texto)

"""
Explanation: En el filtrado anterior, ahora buscaremos todas las etiquetas a las cuales asociamos con la presencia del atributo href. De esta forma localizaremos la lista de archivos. Para obtener el texto al interior de una etiqueta, usamos la propiedad string y el valor de un atributo con el método get.
End of explanation
"""


lineas_a[0].has_attr("href") # Existencia de un atributo

lineas_a[0].attrs # Atributos existentes

from selenium import webdriver

"""
Explanation: Nos vimos en la necesidad de usar encode("utf-8") ya que la codificación de la página es utf-8 y no ascii (el usado por defecto en python). Podemos consultar los atributos de una etiqueta o si posee un atributo especifico, y no solo obtener el valor, de la siguiente forma.
End of explanation
"""


browser = webdriver.Chrome("/home/cosmoscalibur/Downloads/chromedriver")
browser.get('http://github.com')
username = browser.find_element_by_id("user[login]")
username.send_keys("cosmoscalibur@gmail.com")
dar_click = browser.find_element_by_link_text("privacy policy")
dar_click.click()

"""
Explanation: Invocar la instancia del controlador del navegador depende del navegador de interes. Hay que tener encuenta que no todos los navegadores son soportados. Podemos encontrar soporte para Chrome, Firefox, Opera, IE y PhantomJS. Este último permite realizar la labor sin la generación de una ventana para el navegador (en caso de ser necesario, incluso se puede generar capturas de pantalla para su validación con ayuda del controlador).
Acorde a cada navegador, se puede tener requerimientos especificos. En el caso de firefox, se presenta la necesidad de indicar el directorio del perfil de usuario, en el caso de chrome se requiere indicar la ruta del controlador (se descarga ya que no viene incluido como si sucede en firefox o phantomjs).
Podría ser posible (no he verificado) usar otros navegadores si usan el mismo motor de navegación realizando la indicación explicita de la ruta del ejecutable. Por ejemplo, se podría controlar vivaldi realizando el cambio de ruta de chrome (usan el mismo motor de navegación).
End of explanation
"""


codigo = browser.page_source
print(codigo)

"""
Explanation: Resulta bastante útil el uso de selenium no tanto en los casos que requieran de interacción sino en los casos donde los contenidos (incluye elementos de interacción) son de generación dinámica o tras la interacción el nuevo enlace o contenido tiene retrasos apreciables, lo cual evitaría que Request obtenga el código adecuado. Podemos extraer el código fuente de la página en la cual se encuentra el foco del navegador de la siguiente forma.
End of explanation
"""


