Este tutorial trata los siguientes puntos:
- ¿Por qué raspar repositorios de GitHub?
- Bibliotecas y herramientas de raspado de GitHub
- Crea un raspador de repositorios de GitHub con Beautiful Soup
¿Por qué raspar repositorios de GitHub?
Hay varios motivos para raspar repositorios de GitHub. Los más populares son:
- Seguir las tendencias tecnológicas: si realizas un seguimiento de las estrellas y las versiones del repositorio, podrás estar al tanto de las tendencias actuales en los lenguajes de programación, los marcos y las bibliotecas. Raspar GitHub permite analizar qué tecnologías están ganando popularidad para hacer un seguimiento de su crecimiento e identificar las tendencias emergentes. Estos datos pueden guiar las decisiones sobre la adopción de tecnología, el desarrollo de habilidades y la asignación de recursos.
- Obtén acceso a una amplia base de conocimientos de programación: GitHub es un todo un tesoro de proyectos de código abierto, ejemplos de código y soluciones. Esto significa que puedes recopilar una gran cantidad de conocimientos de programación y mejores prácticas de la plataforma. Esto resulta útil para fines educativos, mejorar las habilidades de codificación y comprender cómo se implementan las diferentes tecnologías.
- Obtén información sobre el desarrollo colaborativo: los repositorios ofrecen información sobre cómo colaboran los desarrolladores a través de solicitudes de incorporación de cambios, problemas y debates. Al recopilar estos datos, puedes estudiar los patrones de colaboración para diseñar estrategias de trabajo en equipo, mejorar la gestión de proyectos y perfeccionar los procesos de desarrollo de «software».
GitHub no es la única plataforma basada en la nube para alojar repositorios de git, sino que hay muchas alternativas. Sin embargo, sigue siendo la opción preferida para el raspado de datos debido a su:
- Amplia base de usuarios
- Alta actividad de los usuarios
- Reputación consolidada
En particular, los datos de GitHub son muy útiles para seguir las tendencias tecnológicas, descubrir bibliotecas y marcos y mejorar el proceso de desarrollo de «software». Esta información desempeña un papel esencial para estar a la vanguardia de la competencia en el mundo de la TI.
Bibliotecas y herramientas de raspado de GitHub
Python está ampliamente considerado como un lenguaje excelente para el raspado web gracias a su sintaxis sencilla, su naturaleza accesible a los desarrolladores y su amplia gama de bibliotecas. He aquí por qué es el lenguaje de programación recomendado para raspar GitHub. Obtén más información en nuestra guía detallada sobre cómo hacer raspado web con Python.
El siguiente paso es seleccionar las bibliotecas de raspado más adecuadas entre la amplia gama de opciones disponibles. Para tomar una decisión informada, primero debes explorar la plataforma en el navegador. Abre DevTools y echa un vistazo a las llamadas AJAX realizadas por las páginas del repositorio en GitHub. Observarás que la mayoría de ellos pueden ignorarse. De hecho, la mayoría de los datos de la página están incrustados en los documentos HTML que devuelve el servidor.
Esto supone que bastará con una biblioteca para realizar peticiones HTTP al servidor combinada con un analizador HTML. Por tanto, debes optar por:
- Requests: la biblioteca cliente HTTP más popular del ecosistema de Python. Agiliza el proceso de envío de peticiones HTTP y la gestión de sus correspondientes respuestas.
- Beautiful Soup: una completa biblioteca de análisis de HTML y XML. Proporciona una sólida API de extracción de datos y navegación DOM para el raspado web.
Gracias a Requests y Beautiful Soup, puedes raspar GitHub de forma eficaz con Python. ¡Vamos a ver los detalles de cómo lograrlo!
Crea un raspador de repositorios de GitHub con Beautiful Soup
Sigue este tutorial paso a paso para aprender a raspar GitHub en Python. ¿Quieres saltarte todo el proceso de codificación y raspado? Puedes comprar un conjunto de datos de Github en su lugar.
Paso 1: configurar el proyecto en Python
Antes de empezar, asegúrate de cumplir los siguientes requisitos previos:
- Tener Python 3+ instalado en el ordenador: descargar el instalador, ejecutarlo y seguir las instrucciones.
- El IDE de Python que prefieras: Visual Studio Code con la extensión de Python y PyCharm Community Edition son los dos IDE recomendados.
¡Ya tienes todo lo necesario para configurar un proyecto en Python!
Ejecuta los siguientes comandos en la terminal para crear una carpeta github-scraper e inicializarla con un entorno virtual Python:
mkdir github-scraper
cd github-scraper
python -m venv env
En Windows, ejecuta el siguiente comando para activar el entorno:
env\Scripts\activate.ps1
En Linux o macOS, ejecuta:
./env/bin/activate
A continuación, añade un archivo scraper.py
que contenga la siguiente línea en la carpeta del proyecto:
print('Hello, World!')
Por el momento, tu raspador de GitHub solo muestra «¡Hola, mundo!», pero pronto contendrá la lógica necesaria para extraer datos de repositorios públicos.
Puedes iniciar el script con:
python scraper.py
Si todo ha ido según lo planeado, debería mostrar este mensaje en la terminal:
Hello, World!
Ahora que sabes que funciona, abre la carpeta del proyecto en tu IDE de Python favorito.
¡Estupendo! Prepárate para escribir código Python.
Paso 2: instalar las librerías de raspado
Como hemos mencionado, Beautiful Soup y Requests te ayudan a realizar el raspado web en GitHub. En el entorno virtual activado, ejecuta el siguiente comando para añadirlos a las dependencias del proyecto:
pip install beautifulsoup4 requests
Borra scraper.py
y, a continuación, importa los dos paquetes con estas líneas:
import requestsfrom bs4 import BeautifulSoup
# scraping logic...
Asegúrate de que tu IDE de Python no informa de ningún error. Es posible que recibas advertencias debido a las importaciones no utilizadas. Ignóralas, ¡ya que estás a punto de usar estas bibliotecas de raspado para extraer los datos del repositorio de GitHub!
Paso 3: descargar la página de destino
Selecciona un repositorio de GitHub del que quieras recuperar datos. En esta guía, verás cómo raspar el repositorio luminati-proxy. Ten en cuenta que cualquier otro repositorio servirá, ya que la lógica de extracción será la misma.
Así es como aparece la página de destino en el navegador:
Almacena la URL de la página de destino en una variable:
url = 'https://github.com/luminati-io/luminati-proxy'
Luego, descarga la página con requests.get():
page = requests.get(url)
En segundo plano, requests
realiza una solicitud HTTP GET a esa URL y guarda la respuesta producida por el servidor en la variable page
. En lo que debes centrar tu atención es en su atributo de texto. Este contiene el documento HTML asociado a la página web de destino. Verifícalo con una sencilla instrucción print
:
print(page.text)
Ejecuta el raspador y debería aparecer esto en la terminal:
<!DOCTYPE html>
<html lang="en" data-color-mode="dark" data-light-theme="light" data-dark-theme="dark" data-a11y-animated-images="system" data-a11y-link-underlines="false">
<head>
<meta charset="utf-8">
<link rel="dns-prefetch" href="https://github.githubassets.com">
<link rel="dns-prefetch" href="https://avatars.githubusercontent.com">
<link rel="dns-prefetch" href="https://github-cloud.s3.amazonaws.com">
<link rel="dns-prefetch" href="https://user-images.githubusercontent.com/">
<link rel="preconnect" href="https://github.githubassets.com" crossorigin>
<link rel="preconnect" href="https://avatars.githubusercontent.com">
<!-- Omitted for brevity... -->
Awesome! Let’s now learn how to parse this
Paso 4: analizar el documento HTML
Para analizar el documento HTML recuperado anteriormente, pásalo a Beautiful Soup:
soup = BeautifulSoup(page.text, 'html.parser')
El constructor BeautifulSoup()
recibe dos argumentos:
- La cadena que contiene el contenido HTML: aquí se almacena en la variable
page.text
. - El analizador que utilizará Beautiful Soup: “
html.parser
” es el nombre del analizador HTML integrado en Python.
BeautifulSoup()
analizará el HTML y devolverá una estructura de árbol explorable. En concreto, la variable soup
proporciona métodos efectivos para seleccionar elementos del árbol DOM, como:
find()
: devuelve el primer elemento HTML que coincida con la estrategia de selección pasada como parámetro.find_all()
: devuelve la lista de elementos HTML que coincidan con la estrategia del selector de entrada.select_one ()
: Devuelve el primer elemento HTML que coincide con el selector de CSS pasado como parámetro.select()
: devuelve la lista de elementos HTML que coincidan con el selector CSS de entrada.
Ten en cuenta que estos métodos también se pueden invocar en un solo nodo del árbol. Además de estos, un objeto de nodo Beautiful Soup también expone:
find_next_sibling()
: devuelve el primer nodo HTML entre los elementos hermanos del elemento que coincide con el selector CSS dado.find_next_siblings()
: devuelve todos los nodos HTML de los elementos hermanos del elemento que coincidan con el selector CSS pasado como parámetro.
Gracias a estas funciones, ya estás preparado para raspar GitHub. ¡Veamos cómo!
Paso 5: conocer la página de destino
Antes de sumergirte en la programación, hay otro paso esencial que completar. La extracción de datos de un sitio web consiste en seleccionar los elementos HTML de interés y extraer datos de estos. Definir una estrategia de selección eficaz no siempre es fácil y debes dedicar algo de tiempo a analizar la estructura de la página web objetivo.
Por tanto, abre la página de destino de GitHub en el navegador y familiarízate con ella. Haz clic con el botón derecho y selecciona «Inspeccionar» para abrir DevTools:
Si profundizas en el código HTML, observarás que el sitio no califica muchos de sus elementos con clases o atributos únicos. Por tanto, normalmente es difícil navegar hasta el elemento deseado y es posible que tengas que analizar los elementos hermanos de una manera complicada.
Pero no te preocupes. Diseñar estrategias de selección eficaces para GitHub puede no ser fácil, pero tampoco imposible. ¡Continúa inspeccionando la página en DevTools hasta que estés listo para rasparla!
Paso 6: extraer los datos del repositorio
El objetivo es extraer datos útiles del repositorio de GitHub, como las estrellas, la descripción, el último commit, etc. Por tanto, debes inicializar un diccionario de Python para realizar un seguimiento de estos datos. Añade a tu código:
repo = {}
Primero, inspecciona el elemento «name»:
Ten en cuenta que tiene un atributo distintivo itemprop="name»
. Selecciónalo y extrae su contenido de texto con:
name_html_element = soup.select_one('[itemprop="name"]')name = name_html_element.text.strip()
Con un nodo de Beautiful Soup, usa el método get_text()
para acceder a su contenido de texto.
Si inspeccionas name_html_element.text
en el depurador, verás que:
\nluminati-proxy\n
Los campos de texto de GitHub tienden a contener espacios y líneas nuevas. Deshazte de ellos con la función Python strip()
.
Justo debajo del nombre del repositorio, está el selector de ramas:
Ten en cuenta que no es fácil seleccionar el elemento HTML que almacena el nombre de la rama principal. Lo que puedes hacer es seleccionar el nodo .octicon-git-branch
y luego buscar el span
objetivo en sus elementos hermanos:
git_branch_icon_html_element = soup.select_one('.octicon-git-branch')
main_branch_html_element = git_branch_icon_html_element.find_next_sibling('span')
main_branch = main_branch_html_element.get_text().strip()
El patrón para llegar a un elemento de interés a través de los elementos hermanos de un icono es bastante eficaz en GitHub. Verás que se usa varias veces en esta sección.
Ahora, céntrate en el encabezado de la rama:
Extrae la hora del último commit con:
relative_time_html_element = boxheader_html_element.select_one('relative-time')
latest_commit = relative_time_html_element['datetime']
Con un nodo, puedes acceder a sus atributos HTML como en un diccionario de Python.
Otro dato importante de esta sección es el número de commits:
Recopílalo con el patrón de iconos descrito anteriormente:
history_icon_html_element = boxheader_html_element.select_one('.octicon-history')
commits_span_html_element = history_icon_html_element.find_next_sibling('span')
commits_html_element = commits_span_html_element.select_one('strong')
commits = commits_html_element.get_text().strip().replace(',', '')
Ten en cuenta que find_next_sibling()
solo da acceso a los elementos hermanos de nivel superior. Para seleccionar a uno de sus elementos hijos, primero debes obtener el elemento hermano y luego llamar a select_one()
como se ha hecho anteriormente.
Como los números de más de mil contienen una coma en GitHub, elimínala con el método replace()
de Python.
A continuación, presta atención en el recuadro de información de la derecha:
Selecciónalo con:
bordergrid_html_element = soup.select_one('.BorderGrid')
Inspecciona el elemento de descripción:
De nuevo, puedes seleccionarlo a través de un elemento hermano:
about_html_element = bordergrid_html_element.select_one('h2')
description_html_element = about_html_element.find_next_sibling('p')
description = description_html_element.get_text().strip()
Luego, aplica el patrón de iconos para recuperar las estrellas, relojes y forks del repositorio.
Céntrate en los iconos y luego en sus elementos hermanos de texto:
star_icon_html_element = bordergrid_html_element.select_one('.octicon-star')
stars_html_element = star_icon_html_element.find_next_sibling('strong')
stars = stars_html_element.get_text().strip().replace(',', '')
eye_icon_html_element = bordergrid_html_element.select_one('.octicon-eye')
watchers_html_element = eye_icon_html_element.find_next_sibling('strong')
watchers = watchers_html_element.get_text().strip().replace(',', '')
fork_icon_html_element = bordergrid_html_element.select_one('.octicon-repo-forked')
forks_html_element = fork_icon_html_element.find_next_sibling('strong')
forks = forks_html_element.get_text().strip().replace(',', '')
¡Excelente! Acabas de raspar un repositorio de GitHub.
Paso 7: raspar el archivo «README»
Otra información esencial para recuperar es el archivo README.md
. Es un archivo de texto opcional que describe el repositorio de GitHub y explica cómo usar el código.
Si haces clic en el archivo README.md
y, a continuación, en el botón «Raw», se te redirigirá a la siguiente URL:
https://raw.githubusercontent.com/luminati-io/luminati-proxy/master/README.md
Por lo tanto, se puede deducir que la URL del archivo README de un repositorio de GitHub sigue el siguiente formato:
https://raw.githubusercontent.com/<repo_id>/<repo_main_branch>/README.md
Puesto que tienes la información de <repo_main_branch>
almacenada en la variable main_branch
, puedes construir programáticamente esta URL con una cadena f de Python:
readme_url = f'https://raw.githubusercontent.com/luminati-io/luminati-proxy/{main_branch}/README.md'
Luego, usa requests
para recuperar el contenido README de Markdown sin procesar:
readme_url = f'https://raw.githubusercontent.com/luminati-io/luminati-proxy/{main_branch}/README.md'
readme_page = requests.get(readme_url)
readme = None
# if there is a README.md file
if readme_page.status_code != 404:
readme = readme_page.text
Ten en cuenta la verificación 404 para evitar almacenar el contenido de la página 404 de GitHub cuando el repositorio no tiene un archivo README.
Paso 8: almacenar los datos extraídos
No olvides añadir las variables de datos extraídas al diccionario repo
:
repo['name'] = name
repo['latest_commit'] = latest_commit
repo['commits'] = commits
repo['main_branch'] = main_branch
repo['description'] = description
repo['stars'] = stars
repo['watchers'] = watchers
repo['forks'] = forks
repo['readme'] = readme
Utiliza print(repo)
para asegurarte de que el proceso de extracción de datos funciona como quieres. Ejecuta el raspador de GitHub en Python y obtendrás:
{'name': 'luminati-proxy', 'latest_commit': '2023-08-09T08:25:15Z', 'commits': '1079', 'main_branch': 'master', 'description': 'Luminati HTTP/HTTPS Proxy manager', 'stars': '645', 'watchers': '55', 'forks': '196', 'readme': '# Proxy manager\n\n (omitted for brevity...)'}
¡Estupendo! ¡Ya sabes cómo raspar GitHub!
Paso 9: exportar los datos extraídos a JSON
El último paso es hacer que los datos recopilados sean más fáciles de compartir, leer y analizar. La mejor manera de lograrlo es exportar los datos en un formato legible por humanos, como JSON:
import json
# ...
with open('repo.json', 'w') as file:
json.dump(repo, file, indent=4)
Importa json
de la biblioteca estándar de Python, inicializa un archivo repo.json
con open()
y, por último, usa json.ump()
para rellenarlo. Consulta nuestra guía para saber más sobre cómo analizar JSON en Python.
¡Perfecto! Es hora de echar un vistazo a todo el raspador de GitHub en Python.
Paso 10: armarlo todo
Así es como se ve el archivo scraper.py
completo:
import requests
from bs4 import BeautifulSoup
import json
# the URL of the target repo to scrape
url = 'https://github.com/luminati-io/luminati-proxy'
# download the target page
page = requests.get(url)
# parse the HTML document returned by the server
soup = BeautifulSoup(page.text, 'html.parser')
# initialize the object that will contain
# the scraped data
repo = {}
# repo scraping logic
name_html_element = soup.select_one('[itemprop="name"]')
name = name_html_element.get_text().strip()
git_branch_icon_html_element = soup.select_one('.octicon-git-branch')
main_branch_html_element = git_branch_icon_html_element.find_next_sibling('span')
main_branch = main_branch_html_element.get_text().strip()
# scrape the repo history data
boxheader_html_element = soup.select_one('.Box .Box-header')
relative_time_html_element = boxheader_html_element.select_one('relative-time')
latest_commit = relative_time_html_element['datetime']
history_icon_html_element = boxheader_html_element.select_one('.octicon-history')
commits_span_html_element = history_icon_html_element.find_next_sibling('span')
commits_html_element = commits_span_html_element.select_one('strong')
commits = commits_html_element.get_text().strip().replace(',', '')
# scrape the repo details in the right box
bordergrid_html_element = soup.select_one('.BorderGrid')
about_html_element = bordergrid_html_element.select_one('h2')
description_html_element = about_html_element.find_next_sibling('p')
description = description_html_element.get_text().strip()
star_icon_html_element = bordergrid_html_element.select_one('.octicon-star')
stars_html_element = star_icon_html_element.find_next_sibling('strong')
stars = stars_html_element.get_text().strip().replace(',', '')
eye_icon_html_element = bordergrid_html_element.select_one('.octicon-eye')
watchers_html_element = eye_icon_html_element.find_next_sibling('strong')
watchers = watchers_html_element.get_text().strip().replace(',', '')
fork_icon_html_element = bordergrid_html_element.select_one('.octicon-repo-forked')
forks_html_element = fork_icon_html_element.find_next_sibling('strong')
forks = forks_html_element.get_text().strip().replace(',', '')
# build the URL for README.md and download it
readme_url = f'https://raw.githubusercontent.com/luminati-io/luminati-proxy/{main_branch}/README.md'
readme_page = requests.get(readme_url)
readme = None
# if there is a README.md file
if readme_page.status_code != 404:
readme = readme_page.text
# store the scraped data
repo['name'] = name
repo['latest_commit'] = latest_commit
repo['commits'] = commits
repo['main_branch'] = main_branch
repo['description'] = description
repo['stars'] = stars
repo['watchers'] = watchers
repo['forks'] = forks
repo['readme'] = readme
# export the scraped data to a repo.json output file
with open('repo.json', 'w') as file:
json.dump(repo, file, indent=4)
En menos de 100 líneas de código, puedes crear una araña web para recopilar datos de repositorios.
Ejecuta el script con:
python scraper.py
Espera a que finalice el proceso de raspado y encontrarás un archivo repo.json
en la carpeta raíz de tu proyecto. Ábrelo y verás:
{
"name": "luminati-proxy",
"latest_commit": "2023-08-09T08:25:15Z",
"commits": "1079",
"main_branch": "master",
"description": "Luminati HTTP/HTTPS Proxy manager",
"stars": "645",
"watchers": "55",
"forks": "196",
"readme": "# Proxy manager\n\n[![dependencies Status](https://david-dm.org/luminati-io/luminati-proxy/status.svg)](https://david-dm.org/luminati-io/luminati-proxy)\n[![devDependencies Status](https://david-dm.org/luminati-io/luminati-proxy/dev-status.svg)](https://david-dm..."
}
¡Enhorabuena! Empezaste con datos sin procesar contenidos en una página web y ahora tienes datos semiestructurados en un archivo JSON. ¡Acabas de aprender a crear un raspador de repositorios de GitHub en Python!
Conclusión
En esta guía paso a paso, has visto los motivos por los que deberías crear un raspador de repositorios de GitHub. En concreto, has aprendido a raspar GitHub mediante un tutorial guiado. Como ves aquí, para esto solo hacen falta unas líneas de código.
Al mismo tiempo, cada vez más sitios están adoptando tecnologías antiraspado. Estas pueden identificar y bloquear solicitudes mediante la prohibición de IP y la limitación de velocidad, impidiendo que tu raspador acceda al sitio. La mejor manera de evitarlas es mediante un proxy. Explora la amplia oferta de Bright Data de servicios de proxy de primera categoría y los proxies de GitHub especializados.
Bright Data controla los mejores proxies para el raspado web y trabaja para empresas de la lista Fortune 500 y para más de 20 000 clientes. Tu red proxy mundial incluye:
- Proxies de centros de datos: más de 770 000 IP de centros de datos.
- Proxies residenciales: más de 72 millones de IP residenciales en más de 195 países.
- Proxies de ISP: más de 700 000 IP de ISP.
- Proxies móviles: más de 7 millones de IP móviles.
En conjunto, Bright Data es una de las redes de proxies orientadas al raspado web más grandes y fiables del mercado. Habla con uno de nuestros representantes de ventas y descubre cuál de los productos de Bright Data se adapta mejor a tus necesidades.
No se requiere tarjeta de crédito
Nota: nuestro equipo probó minuciosamente esta guía en el momento de redactar este artículo, pero como los sitios web actualizan su código y estructura con frecuencia, es posible que algunos pasos ya no funcionen como se esperaba.