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


In [1]:
import webbrowser

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.


In [2]:
webbrowser.open('http://github.com/')


Out[2]:
True

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.


In [3]:
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])


Project Gutenberg's Latin for Beginners, by Benjamin Leonard D'Ooge

This eBook is for the use of anyone anywhere at no cost and with
almost no restrictions whatsoever.  You may copy it, give it away or
re-use it under the terms of the Project G

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.


In [4]:
res = requests.get('http://github.com/yomeinventoesto')
res.raise_for_status()


---------------------------------------------------------------------------
HTTPError                                 Traceback (most recent call last)
<ipython-input-4-577eab1b3e67> in <module>()
      1 res = requests.get('http://github.com/yomeinventoesto')
----> 2 res.raise_for_status()

/usr/local/lib/python3.5/dist-packages/requests/models.py in raise_for_status(self)
    860 
    861         if http_error_msg:
--> 862             raise HTTPError(http_error_msg, response=self)
    863 
    864     def close(self):

HTTPError: 404 Client Error: Not Found for url: https://github.com/yomeinventoesto

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.


In [5]:
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()

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.


In [6]:
import bs4

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.


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


Out[7]:
bs4.BeautifulSoup

Ahora, buscaremos todas las estructuras td que tengan el atributo class con valor content.


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


Out[8]:
bs4.element.ResultSet

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.


In [9]:
len(tabla_archivos)


Out[9]:
23

In [10]:
print(tabla_archivos)


[<td class="content" colspan="3">Failed to load latest commit information.</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/tree/master/Evaluaci%C3%B3n" id="f65268c13fd62c5d4e9269ebcd9e11ca-8ed6e5c0b159f72f1829ff55eb7c4856e58e43b9" title="Evaluación">Evaluación</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/tree/master/Proyecto" id="c126d9cdd553787e63d4a48608f608cc-5099d554c9d22731a50e7784cee7e458bcc9b81f" title="Proyecto">Proyecto</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/.gitignore" id="a084b794bc0759e7a6b77810e01874f2-8cec0970c2bcc6a64ca702e6ace3072bec1db708" title=".gitignore">.gitignore</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/Git.ipynb" id="c24916e53ed7ca5bfbd5552ec60b9864-c89b09c88c856d8d41558fa24d8da697173a834c" title="Git.ipynb">Git.ipynb</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/Jupyter%20Notebook%20Basico.ipynb" id="56994abf3c173eef1f731f415a113e73-649ceea4101089ff2d9e22c518e09e713604115a" title="Jupyter Notebook Basico.ipynb">Jupyter Notebook Basico.ipynb</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/Jupyter%20Notebook%20Intermedio.ipynb" id="ffc05e347c4818563b4f8fe19ecf90f5-639517140f687747088d911f602f1ed76aea5d13" title="Jupyter Notebook Intermedio.ipynb">Jupyter Notebook Intermedio.ipynb</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/LICENSE" id="9879d6db96fd29134fc802214163b95a-cd3541098e80cceefd8bca945781da52d50826ae" itemprop="license" title="LICENSE">LICENSE</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/LaTeX_basico.pdf" id="445e300dd1ef8a87aca1c1f559f6d865-04e35031b5713ccaa5eca1aec68cee2fe0709006" title="LaTeX_basico.pdf">LaTeX_basico.pdf</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/LaTeX_basico.tex" id="d183b1b27b2723139e34a2c2c2563d3b-16930e488482ae4f67e88156c0e24c35b4d1a3c6" title="LaTeX_basico.tex">LaTeX_basico.tex</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/Linux%20Bash.ipynb" id="ae97da1784350f80f600c7a109ee6021-f5c0a06f7de9516a809c6978b59dd966d71015ed" title="Linux Bash.ipynb">Linux Bash.ipynb</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/Linux%20Basico.ipynb" id="67a20284f502e3f94cd48308516bece6-84b42c08ef7ecfa057f547a1b8aed4e7274b7665" title="Linux Basico.ipynb">Linux Basico.ipynb</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/README.md" id="04c6e90faac2675aa89e2176d2eec7d8-a7ef4975f70435aebf7a78f843df649b2006ac49" title="README.md">README.md</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/R_basico.ipynb" id="a374c2b16cceed1093078668f0f2a077-b76411f9d8e075cb40f4428a2d83d945b7ed2972" title="R_basico.ipynb">R_basico.ipynb</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/algebra_computacional.ipynb" id="4484cecc709691bd6f7aa604fa5e619d-6990c171d5cfa11a4d226871f107a7ed02072ac3" title="algebra_computacional.ipynb">algebra_computacional.ipynb</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/datos_abiertos.md" id="11f66d58f88e6022a18fe1cbf9b3bbf4-24664abb3ee537b8311fdeea217ab11a53c85fc5" title="datos_abiertos.md">datos_abiertos.md</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/historial_talleres.md" id="3919bdb26f7850379608f0e7af744435-35692b7cc202043e2c8196abad636ff1865d32b3" title="historial_talleres.md">historial_talleres.md</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/hoja_de_ruta.md" id="200c2939ccd869061076b9c85f6ab4e5-b5f00e541809bea4070d4220a4e9e7a1cfbb6e18" title="hoja_de_ruta.md">hoja_de_ruta.md</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/jupyter.png" id="965598871a36b41718db396637a2afe8-480932523cd389416c1b7dfffb8b0580616e9051" title="jupyter.png">jupyter.png</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/presentacion_herramientas.md" id="aa6132db9bd8b7f9301a40f9347bacc3-817b6de1714a3015409eddbd7b4a25d0931600c4" title="presentacion_herramientas.md">presentacion_herramientas.md</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/procesamiento_de_texto.ipynb" id="fa6d566a808c31e0fc9045b530040e88-a14c94d5ce44f69024491a037df19e7768f61d4b" title="procesamiento_de_texto.ipynb">procesamiento_de_texto.ipynb</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/r_datos.txt" id="70ff05431638f94f914ae68cc1eecc6a-9eb903b0113089f99b4a8349f95731e42a9a9dd4" title="r_datos.txt">r_datos.txt</a></span>
</td>, <td class="content">
<span class="css-truncate css-truncate-target"><a class="js-navigation-open" href="/cosmoscalibur/herramientas_computacionales/blob/master/web_scrapping.ipynb" id="634ac137a7e35d0e03e15bc603462ab7-983a57f7dab52e377388e0e5e2a7df7750a7dde4" title="web_scrapping.ipynb">web_scrapping.ipynb</a></span>
</td>]

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.


In [11]:
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)


Se encontro el archivo 'b'Evaluaci\xc3\xb3n'' con enlace '/cosmoscalibur/herramientas_computacionales/tree/master/Evaluaci%C3%B3n'.
Se encontro el archivo 'b'Proyecto'' con enlace '/cosmoscalibur/herramientas_computacionales/tree/master/Proyecto'.
Se encontro el archivo 'b'.gitignore'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/.gitignore'.
Se encontro el archivo 'b'Git.ipynb'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/Git.ipynb'.
Se encontro el archivo 'b'Jupyter Notebook Basico.ipynb'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/Jupyter%20Notebook%20Basico.ipynb'.
Se encontro el archivo 'b'Jupyter Notebook Intermedio.ipynb'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/Jupyter%20Notebook%20Intermedio.ipynb'.
Se encontro el archivo 'b'LICENSE'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/LICENSE'.
Se encontro el archivo 'b'LaTeX_basico.pdf'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/LaTeX_basico.pdf'.
Se encontro el archivo 'b'LaTeX_basico.tex'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/LaTeX_basico.tex'.
Se encontro el archivo 'b'Linux Bash.ipynb'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/Linux%20Bash.ipynb'.
Se encontro el archivo 'b'Linux Basico.ipynb'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/Linux%20Basico.ipynb'.
Se encontro el archivo 'b'README.md'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/README.md'.
Se encontro el archivo 'b'R_basico.ipynb'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/R_basico.ipynb'.
Se encontro el archivo 'b'algebra_computacional.ipynb'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/algebra_computacional.ipynb'.
Se encontro el archivo 'b'datos_abiertos.md'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/datos_abiertos.md'.
Se encontro el archivo 'b'historial_talleres.md'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/historial_talleres.md'.
Se encontro el archivo 'b'hoja_de_ruta.md'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/hoja_de_ruta.md'.
Se encontro el archivo 'b'jupyter.png'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/jupyter.png'.
Se encontro el archivo 'b'presentacion_herramientas.md'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/presentacion_herramientas.md'.
Se encontro el archivo 'b'procesamiento_de_texto.ipynb'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/procesamiento_de_texto.ipynb'.
Se encontro el archivo 'b'r_datos.txt'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/r_datos.txt'.
Se encontro el archivo 'b'web_scrapping.ipynb'' con enlace '/cosmoscalibur/herramientas_computacionales/blob/master/web_scrapping.ipynb'.

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.


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


Out[12]:
True

In [13]:
lineas_a[0].attrs # Atributos existentes


Out[13]:
{'class': ['js-navigation-open'],
 'href': '/cosmoscalibur/herramientas_computacionales/blob/master/web_scrapping.ipynb',
 'id': '634ac137a7e35d0e03e15bc603462ab7-983a57f7dab52e377388e0e5e2a7df7750a7dde4',
 'title': 'web_scrapping.ipynb'}

In [14]:
from selenium import webdriver

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).


In [15]:
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()

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.


In [16]:
codigo = browser.page_source
print(codigo)


<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml" lang="en" class=" is-copy-enabled is-u2f-enabled"><head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# object: http://ogp.me/ns/object# article: http://ogp.me/ns/article# profile: http://ogp.me/ns/profile#">
    <meta charset="utf-8" />
    <meta content="origin-when-cross-origin" name="referrer" />

    <link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/frameworks-cb37473586c0bff2206ff7c864d9afda5e2063afb40364d87d64eefa2536d1c0.css" integrity="sha256-yzdHNYbAv/Igb/fIZNmv2l4gY6+0A2TYfWTu+iU20cA=" media="all" rel="stylesheet" />
    <link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/github-1d1dd698ec7e26200c41f689c19707b13992a803afc430c1abe93cc850c026a7.css" integrity="sha256-HR3WmOx+JiAMQfaJwZcHsTmSqAOvxDDBq+k8yFDAJqc=" media="all" rel="stylesheet" />
    
    
    <link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/site-b637b3b72afffd79585a758c94c7bd5bc8d451dd7ff634ca3a1b23221da39613.css" integrity="sha256-tjeztyr//XlYWnWMlMe9W8jUUd1/9jTKOhsjIh2jlhM=" media="all" rel="stylesheet" />
    

    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta http-equiv="Content-Language" content="en" />
    <meta name="viewport" content="width=device-width" />
    
    <title>How people build software · GitHub</title>
    <link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub" />
    <link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub" />
    <link rel="apple-touch-icon" href="/apple-touch-icon.png" />
    <link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png" />
    <link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png" />
    <link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png" />
    <link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png" />
    <link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png" />
    <link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png" />
    <link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png" />
    <link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png" />
    <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png" />
    <meta property="fb:app_id" content="1401488693436528" />

      <meta property="og:url" content="https://github.com" />
      <meta property="og:site_name" content="GitHub" />
      <meta property="og:title" content="Build software better, together" />
      <meta property="og:description" content="GitHub is where people build software. More than 15 million people use GitHub to discover, fork, and contribute to over 38 million projects." />
      <meta property="og:image" content="https://assets-cdn.github.com/images/modules/open_graph/github-logo.png" />
      <meta property="og:image:type" content="image/png" />
      <meta property="og:image:width" content="1200" />
      <meta property="og:image:height" content="1200" />
      <meta property="og:image" content="https://assets-cdn.github.com/images/modules/open_graph/github-mark.png" />
      <meta property="og:image:type" content="image/png" />
      <meta property="og:image:width" content="1200" />
      <meta property="og:image:height" content="620" />
      <meta property="og:image" content="https://assets-cdn.github.com/images/modules/open_graph/github-octocat.png" />
      <meta property="og:image:type" content="image/png" />
      <meta property="og:image:width" content="1200" />
      <meta property="og:image:height" content="620" />
      <meta property="twitter:site" content="github" />
      <meta property="twitter:site:id" content="13334762" />
      <meta property="twitter:creator" content="github" />
      <meta property="twitter:creator:id" content="13334762" />
      <meta property="twitter:card" content="summary_large_image" />
      <meta property="twitter:title" content="GitHub" />
      <meta property="twitter:description" content="GitHub is where people build software. More than 15 million people use GitHub to discover, fork, and contribute to over 38 million projects." />
      <meta property="twitter:image:src" content="https://assets-cdn.github.com/images/modules/open_graph/github-logo.png" />
      <meta property="twitter:image:width" content="1200" />
      <meta property="twitter:image:height" content="1200" />
      <meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats" />
    <meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors" />
    <link rel="assets" href="https://assets-cdn.github.com/" />
    
    <meta name="pjax-timeout" content="1000" />
    
    <meta name="request-id" content="C9E91253:2141:4ECFAFE:57FFAD8E" data-pjax-transient="" />

    <meta name="msapplication-TileImage" content="/windows-tile.png" />
    <meta name="msapplication-TileColor" content="#ffffff" />
    <meta name="selected-link" value="/" data-pjax-transient="" />

    <meta name="google-site-verification" content="KT5gs8h0wvaagLKAVWq8bbeNwnZZK1r1XQysX3xurLU" />
<meta name="google-site-verification" content="ZzhVyEFwb7w3e0-uOTltm8Jsck2F5StVihD0exw2fsA" />
    <meta name="google-analytics" content="UA-3769691-2" />

<meta content="collector.githubapp.com" name="octolytics-host" /><meta content="github" name="octolytics-app-id" /><meta content="C9E91253:2141:4ECFAFE:57FFAD8E" name="octolytics-dimension-request_id" />




  <meta class="js-ga-set" name="dimension1" content="Logged Out" />



        <meta name="hostname" content="github.com" />
    <meta name="user-login" content="" />

        <meta name="expected-hostname" content="github.com" />
      <meta name="js-proxy-site-detection-payload" content="YzA0MzM1MGE4ZTBhOTIyOWVhYTllMWFjZmFkNzMzMWZjYjA5ZDEwMzdmYzcyZTBjZjEwYzI5YjU0MDgzYTJkY3x7InJlbW90ZV9hZGRyZXNzIjoiMjAxLjIzMy4xOC44MyIsInJlcXVlc3RfaWQiOiJDOUU5MTI1MzoyMTQxOjRFQ0ZBRkU6NTdGRkFEOEUiLCJ0aW1lc3RhbXAiOjE0NzYzNzM5MDMsImhvc3QiOiJnaXRodWIuY29tIn0=" />


      <link rel="mask-icon" href="https://assets-cdn.github.com/pinned-octocat.svg" color="#4078c0" />
      <link rel="icon" type="image/x-icon" href="https://assets-cdn.github.com/favicon.ico" />

    <meta name="html-safe-nonce" content="062e33e1c8fce0e7b993fd7f8e6c751a56cbb403" />
    <meta content="403bc94b54542af53c48c62c08b64939a374ee70" name="form-nonce" />

    <meta http-equiv="x-pjax-version" content="8403c43a44078b6591ec9c83bcaa633b" />
    

        <meta name="viewport" content="width=device-width" />
  <link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/site-b637b3b72afffd79585a758c94c7bd5bc8d451dd7ff634ca3a1b23221da39613.css" integrity="sha256-tjeztyr//XlYWnWMlMe9W8jUUd1/9jTKOhsjIh2jlhM=" media="all" rel="stylesheet" />


      <link rel="canonical" href="https://github.com/" data-pjax-transient="" />
  </head>


  <body class="logged-out  env-production linux  page-responsive sn-grid min-width-0 alt-body-font">
    <div id="js-pjax-loader-bar" class="pjax-loader-bar"><div class="progress"></div></div>
    <a href="#start-of-content" tabindex="1" class="accessibility-aid js-skip-to-content">Skip to content</a>

    
    
    



          <header class="site-header js-details-container" role="banner">
  <div class="container-responsive">
    <a class="header-logo-invertocat" href="https://github.com/" aria-label="Homepage" data-ga-click="(Logged out) Header, go to homepage, icon:logo-wordmark">
      <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="octicon octicon-mark-github" height="32" version="1.1" viewBox="0 0 16 16" width="32"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"/></svg>
    </a>

    <button class="btn-link float-right site-header-toggle js-details-target" type="button" aria-label="Toggle navigation">
      <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="octicon octicon-three-bars" height="24" version="1.1" viewBox="0 0 12 16" width="18"><path d="M11.41 9H.59C0 9 0 8.59 0 8c0-.59 0-1 .59-1H11.4c.59 0 .59.41.59 1 0 .59 0 1-.59 1h.01zm0-4H.59C0 5 0 4.59 0 4c0-.59 0-1 .59-1H11.4c.59 0 .59.41.59 1 0 .59 0 1-.59 1h.01zM.59 11H11.4c.59 0 .59.41.59 1 0 .59 0 1-.59 1H.59C0 13 0 12.59 0 12c0-.59 0-1 .59-1z"/></svg>
    </button>

    <div class="site-header-menu">
      <nav class="site-header-nav site-header-nav-main">
        <a href="/personal" class="js-selected-navigation-item nav-item nav-item-personal" data-ga-click="Header, click, Nav menu - item:personal" data-selected-links="/personal /personal">
          Personal
</a>        <a href="/open-source" class="js-selected-navigation-item nav-item nav-item-opensource" data-ga-click="Header, click, Nav menu - item:opensource" data-selected-links="/open-source /open-source">
          Open source
</a>        <a href="/business" class="js-selected-navigation-item nav-item nav-item-business" data-ga-click="Header, click, Nav menu - item:business" data-selected-links="/business /business/partners /business/features /business/customers /business">
          Business
</a>        <a href="/explore" class="js-selected-navigation-item nav-item nav-item-explore" data-ga-click="Header, click, Nav menu - item:explore" data-selected-links="/explore /trending /trending/developers /integrations /integrations/feature/code /integrations/feature/collaborate /integrations/feature/ship /explore">
          Explore
</a>      </nav>

      <div class="site-header-actions">
            <a class="btn btn-primary site-header-actions-btn" href="/join?source=header-home" data-ga-click="(Logged out) Header, clicked Sign up, text:sign-up">Sign up</a>
          <a class="btn site-header-actions-btn mr-2" href="/login" data-ga-click="(Logged out) Header, clicked Sign in, text:sign-in">Sign in</a>
      </div>

        <nav class="site-header-nav site-header-nav-secondary">
          <a class="nav-item" href="/pricing">Pricing</a>
          <a class="nav-item" href="/blog">Blog</a>
          <a class="nav-item" href="https://help.github.com">Support</a>
          <a class="nav-item header-search-link" href="https://github.com/search">Search GitHub</a>
              <div class="header-search   js-site-search" role="search">
  <!-- '"` --><!-- </textarea></xmp> --><form accept-charset="UTF-8" action="/search" class="js-site-search-form" data-unscoped-search-url="/search" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /></div>
    <label class="form-control header-search-wrapper js-chromeless-input-container">
      <div class="header-search-scope"></div>
      <input type="text" class="form-control header-search-input js-site-search-focus " data-hotkey="s" name="q" placeholder="Search GitHub" aria-label="Search GitHub" data-unscoped-placeholder="Search GitHub" data-scoped-placeholder="Search" autocapitalize="off" />
    </label>
</form></div>

        </nav>
    </div>
  </div>
</header>




    <div id="start-of-content" class="accessibility-aid"></div>

      <div id="js-flash-container">
</div>


    <div role="main">
        
<div class="sn-jumbotron jumbotron-home sn-jumbotron-inverse">
  <div class="container-responsive">
    <div class="columns">
      <div class="homepage-hero-intro column">
        <h1 class="alt-h1 text-white text-shadow-dark lh-condensed mb-3">How people build software</h1>
        <p class="alt-lead text-white text-shadow-dark">Millions of developers use GitHub to build personal projects, support their businesses, and work together on open source technologies.</p>
      </div>
      <div class="homepage-hero-signup column">
          <div class="d-none-sm-dn">
            <!-- '"` --><!-- </textarea></xmp> --><form accept-charset="UTF-8" action="/join" autocomplete="off" class="home-hero-signup js-signup-form" data-form-nonce="403bc94b54542af53c48c62c08b64939a374ee70" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /><input name="authenticity_token" type="hidden" value="HHuMsqj7puvMNg2hJgQ+eSXK95o5fsDkujxSPkv/bOrAxx56Jmr2Xy9g2NSEtn3dO9eAHRX7wSgBcLKJWOTPBQ==" /></div>              <dl class="form">
                <dd>
                  <label class="form-label sr-only" for="user[login]">Pick a username</label>
                  <input type="text" name="user[login]" id="user[login]" class="form-control form-control-lg input-block is-autocheck-errored" placeholder="Pick a username" data-autocheck-url="/signup_check/username" autofocus="" />
                </dd>
              </dl>
              <dl class="form">
                <dd>
                  <label class="form-label sr-only" for="user[email]">Enter your email address</label>
                  <input type="text" name="user[email]" id="user[email]" class="form-control form-control-lg input-block js-email-notice-trigger" placeholder="Your email address" data-autocheck-url="/signup_check/email" />
                </dd>
              </dl>
              <dl class="form">
                <dd>
                  <label class="form-label sr-only" for="user[password]">Create a password</label>
                  <input type="password" name="user[password]" id="user[password]" class="form-control form-control-lg input-block" placeholder="Create a password" data-autocheck-url="/signup_check/password" />
                </dd>
                <p class="form-control-note">Use at least one letter, one numeral, and seven characters.</p>
              </dl>
              <input type="hidden" name="source" class="js-signup-source" value="form-home" />
              <button class="btn btn-theme-green btn-jumbotron btn-block" type="submit">Sign up for GitHub</button>
              <p class="form-control-note text-center">
                By clicking "Sign up for GitHub", you agree to our
                <a class="text-white" href="https://help.github.com/terms" target="_blank">terms of service</a> and
                <a class="text-white" href="https://help.github.com/privacy" target="_blank">privacy policy</a>. <span class="js-email-notice">We'll occasionally send you account related emails.</span>
              </p>
</form>          </div>
          <div class="d-none-md-up">
            <a href="/join?source=button-home" class="btn btn-theme-green btn-jumbotron" rel="nofollow">Sign up for GitHub</a>
          </div>
      </div>
    </div>
  </div>
</div>

<div class="featurette bg-white py-5">
  <div class="container-responsive" style="max-width:600px;">
    <a href="/universe-2016" class="d-block columns">
      <div class="one-fourth column">
        <img src="https://assets-cdn.github.com/images/modules/site/universe-logo.png" alt="" class="img-responsive mx-auto mb-3 mb-md-0" style="max-width:110px;" />
      </div>
      <div class="three-fourths column featurette-lead mb-0">
        <h3 class="alt-h3 text-blue">A whole new Universe</h3>
        <p class="mb-0 text-gray">
          Learn about the exciting features and announcements revealed at this year's GitHub Universe conference.
        </p>
      </div>
    </a>
  </div>
</div>

<div class="featurette pb-0 pt-6 shade-gray border-top">
  <div class="container-responsive">
    <h2 class="alt-h2 mt-3 mb-2 text-center">Welcome home, developers</h2>
    <p class="alt-lead text-center text-gray mb-6 pb-4 px-md-6 mx-lg-6">GitHub fosters a fast, flexible, and collaborative development process that lets you work on your own or with others.</p>
  </div>
  <div class="tile-block">
    <div class="tile-row">
      <div class="tile tile-bordered one-fourth text-center">
        <img src="https://assets-cdn.github.com/images/modules/site/home-ill-build.png?sn" alt="" class="img-responsive featurette-illo-sm mb-4 mt-4" />
        <h4 class="alt-h4">For everything you build</h4>
        <p class="alt-text-small text-gray">Host and manage your code on GitHub. You can keep your work private or share it with the world.</p>
      </div>
      <div class="tile tile-bordered one-fourth text-center">
        <img src="https://assets-cdn.github.com/images/modules/site/home-ill-work.png?sn" alt="" class="img-responsive featurette-illo-sm mb-4 mt-4" />
        <h4 class="alt-h4">A better way to work</h4>
        <p class="alt-text-small text-gray">From hobbyists to professionals, GitHub helps developers simplify the way they build software.</p>
      </div>
      <div class="tile tile-bordered one-fourth text-center">
        <img src="https://assets-cdn.github.com/images/modules/site/home-ill-projects.png?sn" alt="" class="img-responsive featurette-illo-sm mb-4 mt-4" />
        <h4 class="alt-h4">Millions of projects</h4>
        <p class="alt-text-small text-gray">GitHub is home to millions of open source projects. Try one out or get inspired to create your own.</p>
      </div>
      <div class="tile tile-bordered one-fourth text-center">
        <img src="https://assets-cdn.github.com/images/modules/site/home-ill-platform.png?sn" alt="" class="img-responsive featurette-illo-sm mb-4 mt-4" />
        <h4 class="alt-h4">One platform, from start to finish</h4>
        <p class="alt-text-small text-gray">With hundreds of integrations, GitHub is flexible enough to be at the center of your development process.</p>
      </div>
    </div>
  </div>
</div>

<div class="featurette pb-0">
  <div class="container-responsive">
    <h2 class="alt-h2">Who uses GitHub?</h2>
    <hr class="triband-hr mt-5 mb-0" />
    <div class="columns">
      <div class="one-third column my-4">
        <h3 class="alt-h3 my-2"><a href="/personal" class="text-blue octicon-middle">Individuals <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="octicon octicon-chevron-right" height="22" version="1.1" viewBox="0 0 8 16" width="11"><path d="M7.5 8l-5 5L1 11.5 4.75 8 1 4.5 2.5 3z"/></svg></a></h3>
        <p class="text-gray">Use GitHub to create a personal project, whether you want to experiment with a new programming language or host your life’s work.</p>
      </div>
      <div class="one-third column my-4">
        <h3 class="alt-h3 my-2"><a href="/open-source" class="text-orange octicon-middle">Communities <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="octicon octicon-chevron-right" height="22" version="1.1" viewBox="0 0 8 16" width="11"><path d="M7.5 8l-5 5L1 11.5 4.75 8 1 4.5 2.5 3z"/></svg></a></h3>
        <p class="text-gray">GitHub hosts one of the largest collections of open source software. Create, manage, and work on some of today’s most influential technologies.</p>
      </div>
      <div class="one-third column my-4">
        <h3 class="alt-h3 my-2"><a href="/business" class="text-purple octicon-middle">Businesses <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="octicon octicon-chevron-right" height="22" version="1.1" viewBox="0 0 8 16" width="11"><path d="M7.5 8l-5 5L1 11.5 4.75 8 1 4.5 2.5 3z"/></svg></a></h3>
        <p class="text-gray">Businesses of all sizes use GitHub to support their development process and securely build software.</p>
      </div>
    </div>
    <hr class="triband-hr mt-0" />
    <div class="columns columns-vertically-centered columns-reverse mt-6">
      <div class="one-third column">
        <p class="alt-text-small text-gray">
          GitHub is proud to host projects and organizations like <a href="//github.com/nasa">NASA</a>.
        </p>
      </div>
      <div class="two-thirds column">
        <img src="https://assets-cdn.github.com/images/modules/site/org_example_nasa.png?sn" class="img-responsive org-example-drop-shadow" alt="NASA is on GitHub" />
      </div>
    </div>
  </div>
</div>
<div class="featurette shade-gradient pb-4">
  <div class="container-responsive">
    <div class="pricing-card pricing-card-horizontal">
      <div class="pricing-card-cta">
        <a href="/join?source=button-home" class="btn btn-block btn-theme-green btn-jumbotron" rel="nofollow">Sign up for GitHub</a>
      </div>
      <div class="pricing-card-text alt-h3 mb-0 text-thin">
        Public projects are always free. Work together across unlimited private repositories for $7 / month.
      </div>
    </div>
  </div>
</div>

  <div class="modal-backdrop js-touch-events"></div>

    </div>

        <div class="container site-footer-container">
  <div class="site-footer" role="contentinfo">
    <ul class="site-footer-links float-right">
        <li><a href="https://github.com/contact" data-ga-click="Footer, go to contact, text:contact">Contact GitHub</a></li>
      <li><a href="https://developer.github.com" data-ga-click="Footer, go to api, text:api">API</a></li>
      <li><a href="https://training.github.com" data-ga-click="Footer, go to training, text:training">Training</a></li>
      <li><a href="https://shop.github.com" data-ga-click="Footer, go to shop, text:shop">Shop</a></li>
        <li><a href="https://github.com/blog" data-ga-click="Footer, go to blog, text:blog">Blog</a></li>
        <li><a href="https://github.com/about" data-ga-click="Footer, go to about, text:about">About</a></li>

    </ul>

    <a href="https://github.com" aria-label="Homepage" class="site-footer-mark" title="GitHub">
      <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="octicon octicon-mark-github" height="24" version="1.1" viewBox="0 0 16 16" width="24"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"/></svg>
</a>
    <ul class="site-footer-links">
      <li>© 2016 <span title="0.05896s from github-fe154-cp1-prd.iad.github.net">GitHub</span>, Inc.</li>
        <li><a href="https://github.com/site/terms" data-ga-click="Footer, go to terms, text:terms">Terms</a></li>
        <li><a href="https://github.com/site/privacy" data-ga-click="Footer, go to privacy, text:privacy">Privacy</a></li>
        <li><a href="https://github.com/security" data-ga-click="Footer, go to security, text:security">Security</a></li>
        <li><a href="https://status.github.com/" data-ga-click="Footer, go to status, text:status">Status</a></li>
        <li><a href="https://help.github.com" data-ga-click="Footer, go to help, text:help">Help</a></li>
    </ul>
  </div>
</div>



    

    <div id="ajax-error-message" class="ajax-error-message flash flash-error">
      <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="octicon octicon-alert" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M8.865 1.52c-.18-.31-.51-.5-.87-.5s-.69.19-.87.5L.275 13.5c-.18.31-.18.69 0 1 .19.31.52.5.87.5h13.7c.36 0 .69-.19.86-.5.17-.31.18-.69.01-1L8.865 1.52zM8.995 13h-2v-2h2v2zm0-3h-2V6h2v4z"/></svg>
      <button type="button" class="flash-close js-flash-close js-ajax-error-dismiss" aria-label="Dismiss error">
        <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="octicon octicon-x" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"/></svg>
      </button>
      You can't perform that action at this time.
    </div>


      
      <script crossorigin="anonymous" integrity="sha256-1cdy43iaaZRstd4rQoAh+PoxMNSU5FWh1ErTVFR1kCE=" src="https://assets-cdn.github.com/assets/frameworks-d5c772e3789a69946cb5de2b428021f8fa3130d494e455a1d44ad35454759021.js"></script>
      <script async="async" crossorigin="anonymous" integrity="sha256-agmoE9+uJzt2c4n8SHkHTVWUwR5hAPxshHyLVqDb5ys=" src="https://assets-cdn.github.com/assets/github-6a09a813dfae273b767389fc4879074d5594c11e6100fc6c847c8b56a0dbe72b.js"></script>
      
      
      
      
      
      
    <div class="js-stale-session-flash stale-session-flash flash flash-warn flash-banner d-none">
      <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="octicon octicon-alert" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M8.865 1.52c-.18-.31-.51-.5-.87-.5s-.69.19-.87.5L.275 13.5c-.18.31-.18.69 0 1 .19.31.52.5.87.5h13.7c.36 0 .69-.19.86-.5.17-.31.18-.69.01-1L8.865 1.52zM8.995 13h-2v-2h2v2zm0-3h-2V6h2v4z"/></svg>
      <span class="signed-in-tab-flash">You signed in with another tab or window. <a href="">Reload</a> to refresh your session.</span>
      <span class="signed-out-tab-flash">You signed out in another tab or window. <a href="">Reload</a> to refresh your session.</span>
    </div>
    <div class="facebox" id="facebox" style="display:none;">
  <div class="facebox-popup">
    <div class="facebox-content" role="dialog" aria-labelledby="facebox-header" aria-describedby="facebox-description">
    </div>
    <button type="button" class="facebox-close js-facebox-close" aria-label="Close modal">
      <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="octicon octicon-x" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"/></svg>
    </button>
  </div>
</div>

  


</body></html>

Si se desea hacer pasar algún navegador especifico o una solicitud por request o urllib como un navegador dado (por ejemplo, evitar bloqueos de contenido por navegador o por politicas contra la extracción web), es necesario realizar la modificación del user-agent.