Raccoglitore di argomenti GitHub | Web-Scraping con Python

GitHub topic scraper with Python.

Lo scraping web è una tecnica utilizzata per estrarre dati dai siti web. Ci consente di raccogliere informazioni dalle pagine web e utilizzarle per vari scopi, come l’analisi dei dati, la ricerca o la creazione di applicazioni.

In questo articolo, esploreremo un progetto Python chiamato “GitHub Topics Scraper”, che sfrutta lo scraping web per estrarre informazioni dalla pagina dei topic di GitHub e recuperare i nomi dei repository e i dettagli per ogni argomento.

Introduzione

GitHub è una piattaforma ampiamente popolare per l’hosting e la collaborazione sui repository di codice. Offre una funzionalità chiamata “topic” che consente agli utenti di categorizzare i repository in base a soggetti o temi specifici. Il progetto GitHub Topics Scraper automatizza il processo di scraping di questi argomenti e il recupero di informazioni pertinenti sui repository.

Panoramica del progetto

Il GitHub Topics Scraper è implementato utilizzando Python e utilizza le seguenti librerie:

  • requests: Utilizzato per effettuare richieste HTTP per recuperare il contenuto HTML delle pagine web.
  • BeautifulSoup: Una potente libreria per il parsing HTML ed estrarre dati da esso.
  • pandas: Una libreria versatile per la manipolazione e l’analisi dei dati, utilizzata per organizzare i dati estratti in un formato strutturato.

Andiamo a vedere nel dettaglio il codice e capiamo come funziona ciascun componente del progetto.

Script Python

import requestsfrom bs4 import BeautifulSoupimport pandas as pd

Il frammento di codice sopra importa tre librerie: requests, BeautifulSoup e pandas.

def topic_page_authentication(url):        topics_url = url    response = requests.get(topics_url)    page_content = response.text    doc = BeautifulSoup(page_content, 'html.parser')    return doc

Definisce una funzione chiamata topic_page_authentication che prende un URL come argomento.

Ecco una panoramica di ciò che fa il codice:

1. topics_url = url: Questa riga assegna l’URL fornito alla variabile topics_url. Questo URL rappresenta la pagina web che vogliamo autenticare e recuperare il suo contenuto.

2. response = requests.get(topics_url): Questa riga utilizza la funzione requests.get() per inviare una richiesta HTTP GET all’URL topics_url e memorizza la risposta nella variabile response. Questa richiesta serve per recuperare il contenuto HTML della pagina web.

3. page_content = response.text: Questa riga estrae il contenuto HTML dall’oggetto di risposta e lo assegna alla variabile page_content. L’attributo response.text recupera il contenuto testuale della risposta.

4. doc = BeautifulSoup(page_content, 'html.parser')
Questa riga crea un oggetto BeautifulSoup chiamato doc parsando il page_content utilizzando il parser 'html.parser'. Questo ci consente di navigare ed estrarre informazioni dalla struttura HTML della pagina web.

5. return doc: Questa riga restituisce l’oggetto BeautifulSoup doc dalla funzione. Ciò significa che quando la funzione topic_page_authentication viene chiamata, restituirà il contenuto HTML analizzato come un oggetto BeautifulSoup.

Lo scopo di questa funzione è autenticare e recuperare il contenuto HTML di una pagina web specificata dall’URL fornito. Utilizza la libreria requests per inviare una richiesta HTTP per recuperare il contenuto della risposta e quindi lo analizza con BeautifulSoup per creare un oggetto navigabile che rappresenta la struttura HTML.

Si noti che il frammento di codice fornito gestisce i passaggi iniziali di autenticazione della pagina web e di parsing, ma non esegue alcun compito specifico di scraping o di estrazione dei dati.

def topicSraper(doc):        # Extract title     title_class = 'f3 lh-condensed mb-0 mt-1 Link--primary'    topic_title_tags = doc.find_all('p', {'class':title_class})    # Extract description    description_class = 'f5 color-fg-muted mb-0 mt-1'    topic_desc_tags = doc.find_all('p', {'class':description_class})    # Extract link    link_class = 'no-underline flex-1 d-flex flex-column'    topic_link_tags = doc.find_all('a',{'class':link_class})    #Extract all the topic names    topic_titles = []    for tag in topic_title_tags:        topic_titles.append(tag.text)    #Extract the descrition text of the particular topic    topic_description = []    for tag in topic_desc_tags:        topic_description.append(tag.text.strip())    #Extract the urls of the particular topics    topic_urls = []    base_url = "https://github.com"    for tags in topic_link_tags:        topic_urls.append(base_url + tags['href'])    topics_dict = {    'Title':topic_titles,    'Description':topic_description,    'URL':topic_urls    }    topics_df = pd.DataFrame(topics_dict)    return topics_df

Definisce una funzione chiamata topicScraper che prende come argomento un oggetto BeautifulSoup (doc).

Certificati in ChatGPT + Conversational UX + Dialogflow

Ecco una descrizione di cosa fa il codice:

1. title_class = 'f3 lh-condensed mb-0 mt-1 Link--primary': Questa linea definisce il nome della classe CSS (title_class) per l’elemento HTML che contiene i titoli dei topic sulla pagina web.

2. topic_title_tags = doc.find_all('p', {'class':title_class}): Questa linea utilizza il metodo find_all() dell’oggetto BeautifulSoup per trovare tutti gli elementi HTML (<p>) con la classe CSS specificata (title_class). Restituisce una lista di oggetti BeautifulSoup Tag che rappresentano i tag dei titoli dei topic.

3. description_class = 'f5 color-fg-muted mb-0 mt-1': Questa linea definisce il nome della classe CSS (description_class) per l’elemento HTML che contiene le descrizioni dei topic sulla pagina web.

4. topic_desc_tags = doc.find_all('p', {'class':description_class}): Questa linea utilizza il metodo find_all() per trovare tutti gli elementi HTML (<p>) con la classe CSS specificata (description_class). Restituisce una lista di oggetti BeautifulSoup Tag che rappresentano i tag di descrizione dei topic.

5. link_class = 'no-underline flex-1 d-flex flex-column': Questa linea definisce il nome della classe CSS (link_class) per l’elemento HTML che contiene i link dei topic sulla pagina web.

6. topic_link_tags = doc.find_all('a',{'class':link_class}): Questa linea utilizza il metodo find_all() per trovare tutti gli elementi HTML (<a>) con la classe CSS specificata (link_class). Restituisce una lista di oggetti BeautifulSoup Tag che rappresentano i tag di link dei topic.

7. topic_titles = []: Questa linea inizializza una lista vuota per memorizzare i titoli dei topic estratti.

8. for tag in topic_title_tags: ...: Questo ciclo itera sulla lista topic_title_tags e aggiunge il contenuto testuale di ogni tag alla lista topic_titles.

9. topic_description = []: Questa linea inizializza una lista vuota per memorizzare le descrizioni dei topic estratti.

10. for tag in topic_desc_tags: ...: Questo ciclo itera sulla lista topic_desc_tags e aggiunge il contenuto testuale di ogni tag senza spazi alla lista topic_description.

11. topic_urls = []: Questa linea inizializza una lista vuota per memorizzare gli URL dei topic estratti.

12. base_url = "https://github.com": Questa linea definisce l’URL di base del sito web.

13. for tags in topic_link_tags: ...: Questo ciclo itera sulla lista topic_link_tags e aggiunge l’URL concatenato (URL di base + attributo href) di ogni tag alla lista topic_urls.

14. topics_dict = {...}: Questo blocco crea un dizionario (topics_dict) che contiene i dati estratti: titoli dei topic, descrizioni e URL.

15. topics_df = pd.DataFrame(topics_dict): Questa linea converte il dizionario topics_dict in un DataFrame pandas, dove ogni chiave diventa una colonna nel DataFrame.

16. return topics_df: Questa linea restituisce il DataFrame pandas contenente i dati estratti.

Lo scopo di questa funzione è di effettuare lo scraping e l’estrazione di informazioni dal documento di BeautifulSoup fornito ( doc ). Recupera i titoli degli argomenti, le descrizioni e gli URL da specifici elementi HTML della pagina web e li memorizza in un frame dati di pandas per ulteriore analisi o elaborazione.

def topic_url_extractor(dataframe):        url_lst = []    for i in range(len(dataframe)):        topic_url = dataframe['URL'][i]        url_lst.append(topic_url)    return url_lst

Definisce una funzione chiamata topic_url_extractor che prenda come argomento un panda DataFrame ( dataframe ).

Ecco una descrizione di ciò che fa il codice:

1. url_lst = [] : Questa riga inizializza una lista vuota ( url_lst ) per memorizzare gli URL estratti.

2. for i in range(len(dataframe)): ... : Questo ciclo itera sugli indici delle righe del DataFrame.

3. topic_url = dataframe['URL'][i] : Questa riga recupera il valore della colonna ‘URL’ per l’indice corrente della riga ( i ) nel frame dati.

4. url_lst.append(topic_url) : Questa riga aggiunge l’URL recuperato alla lista url_lst.

5. return url_lst : Questa riga restituisce la lista url_lst contenente gli URL estratti.

Lo scopo di questa funzione è di estrarre gli URL dalla colonna ‘URL’ del DataFrame fornito.

Itera su ogni riga del DataFrame, recupera il valore dell’URL per ogni riga e lo aggiunge ad una lista. Infine, la funzione restituisce la lista degli URL estratti.

Questa funzione può essere utile quando si desidera estrarre gli URL da un DataFrame per ulteriore elaborazione o analisi, come visitare ciascun URL o effettuare ulteriori scraping sulle singole pagine web.

def parse_star_count(stars_str):        stars_str = stars_str.strip()[6:]    if stars_str[-1] == 'k':        stars_str =  float(stars_str[:-1]) * 1000    return int(stars_str)

Definisce una funzione chiamata parse_star_count che prenda come argomento una stringa ( stars_str ).

Ecco una descrizione di ciò che fa il codice:

1. stars_str = stars_str.strip()[6:] : Questa riga rimuove gli spazi vuoti iniziali e finali dalla stringa stars_str utilizzando il metodo strip(). Quindi, taglia la stringa a partire dal sesto carattere e assegna il risultato di nuovo a stars_str. Lo scopo di questa riga è quello di rimuovere eventuali caratteri o spazi indesiderati dalla stringa.

2. if stars_str[-1] == 'k': ... : Questa riga controlla se l’ultimo carattere di stars_str è ‘k’, indicando che il conteggio delle stelle è in migliaia.

3. stars_str = float(stars_str[:-1]) * 1000 : Questa riga converte la parte numerica della stringa (escludendo la ‘k’) in un valore in virgola mobile e quindi lo moltiplica per 1000 per convertirlo nel conteggio effettivo delle stelle.

4. return int(stars_str) : Questa riga converte la stringa stars_str in un intero e lo restituisce.

Lo scopo di questa funzione è di analizzare e convertire il conteggio delle stelle da una rappresentazione in stringa a un valore intero. Gestisce i casi in cui il conteggio delle stelle è in migliaia (‘k’) moltiplicando la parte numerica della stringa per 1000. La funzione restituisce il conteggio delle stelle analizzato come un intero.

Questa funzione può essere utile quando si hanno i conteggi delle stelle rappresentati come stringhe, come ad esempio ‘1.2k’ per 1.200 stelle, e si devono convertire in valori numerici per ulteriore analisi o elaborazione.

def get_repo_info(h3_tags, star_tag):    base_url = 'https://github.com'    a_tags = h3_tags.find_all('a')    username = a_tags[0].text.strip()    repo_name = a_tags[1].text.strip()    repo_url = base_url + a_tags[1]['href']    stars = parse_star_count(star_tag.text.strip())    return username, repo_name, stars, repo_url

Definisce una funzione chiamata get_repo_info che prende due argomenti: h3_tags e star_tag.

Ecco una panoramica di ciò che fa il codice:

1. base_url = 'https://github.com': Questa riga definisce l’URL di base del sito web di GitHub.

2. a_tags = h3_tags.find_all('a'): Questa riga utilizza il metodo find_all() dell’oggetto h3_tags per trovare tutti gli elementi HTML (<a>) al suo interno. Recupera una lista di oggetti Tag di BeautifulSoup che rappresentano i tag degli anchor.

3. username = a_tags[0].text.strip(): Questa riga estrae il contenuto testuale del primo tag degli anchor (a_tags[0]) e lo assegna alla variabile username. Rimuove inoltre eventuali spazi vuoti iniziali o finali utilizzando il metodo strip().

4. repo_name = a_tags[1].text.strip(): Questa riga estrae il contenuto testuale del secondo tag degli anchor (a_tags[1]) e lo assegna alla variabile repo_name. Rimuove inoltre eventuali spazi vuoti iniziali o finali utilizzando il metodo strip().

5. repo_url = base_url + a_tags[1]['href']: Questa riga recupera il valore dell’attributo ‘href’ dal secondo tag degli anchor (a_tags[1]) e lo concatena con base_url per formare l’URL completo del repository. L’URL risultante è assegnato alla variabile repo_url.

6. stars = parse_star_count(star_tag.text.strip())
Questa riga estrae il contenuto testuale dell’oggetto star_tag, rimuove eventuali spazi vuoti iniziali o finali e lo passa come argomento alla funzione parse_star_count. La funzione restituisce il conteggio di stelle analizzato come intero, che viene assegnato alla variabile stars.

7. return username, repo_name, stars, repo_url: Questa riga restituisce una tupla contenente le informazioni estratte: username, repo_name, stars e repo_url.

Lo scopo di questa funzione è quello di estrarre informazioni su un repository di GitHub dagli oggetti h3_tags e star_tag forniti. Recupera il nome utente, il nome del repository, il conteggio delle stelle e l’URL del repository navigando ed estraendo elementi specifici dalla struttura HTML. La funzione restituisce quindi queste informazioni come tupla.

Questa funzione può essere utile quando si desidera estrarre informazioni sui repository da una pagina web che contiene un elenco di repository, come nel caso dello scraping di GitHub topic.

def topic_information_scraper(topic_url):    # autenticazione della pagina    topic_doc = topic_page_authentication(topic_url)    # estrazione del nome    h3_class = 'f3 color-fg-muted text-normal lh-condensed'    repo_tags = topic_doc.find_all('h3', {'class':h3_class})    # recupera il tag delle stelle    star_class = 'tooltipped tooltipped-s btn-sm btn BtnGroup-item color-bg-default'    star_tags = topic_doc.find_all('a', {'class':star_class})    # ottiene le informazioni sul topic    topic_repos_dict = {'username': [], 'repo_name': [], 'stars': [], 'repo_url': []}    for i in range(len(repo_tags)):        repo_info = get_repo_info(repo_tags[i], star_tags[i])        topic_repos_dict['username'].append(repo_info[0])        topic_repos_dict['repo_name'].append(repo_info[1])        topic_repos_dict['stars'].append(repo_info[2])        topic_repos_dict['repo_url'].append(repo_info[3])        return pd.DataFrame(topic_repos_dict)

Definisce una funzione chiamata topic_information_scraper che prende un topic_url come argomento.

Ecco una panoramica di ciò che fa il codice:

1. topic_doc = topic_page_authentication(topic_url)
Questa riga chiama la funzione topic_page_authentication per autenticare e recuperare il contenuto HTML di topic_url. Il contenuto HTML analizzato è assegnato alla variabile topic_doc.

2. h3_class = 'f3 color-fg-muted text-normal lh-condensed' : Questa riga definisce il nome della classe CSS ( h3_class ) per l’elemento HTML che contiene i nomi dei repository all’interno della pagina del topic.

3. repo_tags = topic_doc.find_all('h3', {'class':h3_class}) : Questa riga utilizza il metodo find_all() dell’oggetto topic_doc per trovare tutti gli elementi HTML ( <h3> ) con la classe CSS specificata ( h3_class ). Recupera una lista di oggetti BeautifulSoup Tag che rappresentano i tag dei nomi dei repository.

4. star_class = 'tooltipped tooltipped-s btn-sm btn BtnGroup-item color-bg-default' : Questa riga definisce il nome della classe CSS ( star_class ) per l’elemento HTML che contiene il conteggio delle stelle nella pagina del topic.

5. star_tags = topic_doc.find_all('a',{'class':star_class}) : Questa riga utilizza il metodo find_all() per trovare tutti gli elementi HTML ( <a> ) con la classe CSS specificata ( star_class ). Recupera una lista di oggetti BeautifulSoup Tag che rappresentano i tag del conteggio delle stelle.

6. topic_repos_dict = {...} : Questo blocco crea un dizionario ( topic_repos_dict ) che conterrà le informazioni sui repository estratti: nome utente, nome repository, conteggio delle stelle e URL del repository.

7. for i in range(len(repo_tags)): ... : Questo ciclo itera sugli indici della lista repo_tags, assumendo che ha la stessa lunghezza della lista star_tags.

8. repo_info = get_repo_info(repo_tags[i], star_tags[i]) : Questa riga chiama la funzione get_repo_info per estrarre informazioni su un repository specifico. Passa come argomenti il tag del nome del repository corrente ( repo_tags[i] ) e il tag del conteggio delle stelle ( star_tags[i] ). Le informazioni restituite vengono assegnate alla variabile repo_info.

9. topic_repos_dict['username'].append(repo_info[0]) : Questa riga aggiunge l’username estratto da repo_info alla lista ‘username’ in topic_repos_dict.

10. topic_repos_dict['repo_name'].append(repo_info[1]) : Questa riga aggiunge il nome del repository estratto da repo_info alla lista ‘repo_name’ in topic_repos_dict.

11. topic_repos_dict['stars'].append(repo_info[2])
Questa riga aggiunge il conteggio delle stelle estratto da repo_info alla lista ‘stars’ in topic_repos_dict.

12. topic_repos_dict['repo_url'].append(repo_info[3]) : Questa riga aggiunge l’URL del repository estratto da repo_info alla lista ‘repo_url’ in topic_repos_dict.

13. return pd.DataFrame(topic_repos_dict) : Questa riga converte il dizionario topic_repos_dict in un DataFrame di pandas, dove ogni chiave diventa una colonna nel DataFrame. Il DataFrame risultante contiene le informazioni sui repository estratte.

Lo scopo di questa funzione è quello di estrarre informazioni sui repository all’interno di un topic specifico su GitHub. Autentica e recupera il contenuto HTML della pagina del topic, quindi estrae i nomi dei repository e il conteggio delle stelle utilizzando dei nomi di classe CSS specifici.

Chiama la funzione get_repo_info per ogni repository per recuperare l’username, il nome del repository, il conteggio delle stelle e l’URL del repository.

Le informazioni estratte vengono memorizzate in un dizionario e quindi convertite in un DataFrame di pandas, che viene restituito dalla funzione.

if __name__ == "__main__":    url = 'https://github.com/topics'    topic_dataframe = topicSraper(topic_page_authentication(url))    topic_dataframe.to_csv('GitHubtopics.csv', index=None)    # Crea altri file CSV in base ai topic    url = topic_url_extractor(topic_dataframe)     name = topic_dataframe['Title']    for i in range(len(topic_dataframe)):        new_df = topic_information_scraper(url[i])        new_df.to_csv(f'GitHubTopic_CSV-Files/{name[i]}.csv', index=None)

Il frammento di codice seguente mostra il flusso di esecuzione principale dello script.

Ecco una spiegazione di ciò che fa il codice:

1. if __name__ == "__main__": : Questa istruzione condizionale controlla se lo script viene eseguito direttamente (non importato come modulo).

2. url = 'https://github.com/topics' : Questa riga definisce l’URL della pagina dei topic di GitHub.

3. topic_dataframe = topicSraper(topic_page_authentication(url)) : Questa riga recupera il contenuto HTML della pagina dei topic utilizzando la funzione topic_page_authentication e quindi passa l’HTML analizzato ( doc ) alla funzione topicSraper. Assegna il dataframe risultante ( topic_dataframe ) a una variabile.

4. topic_dataframe.to_csv('GitHubtopics.csv', index=None) : Questa riga esporta il dataframe topic_dataframe in un file CSV chiamato ‘GitHubtopics.csv’. L’argomento index=None garantisce che gli indici delle righe non siano inclusi nel file CSV.

5. url = topic_url_extractor(topic_dataframe) : Questa riga chiama la funzione topic_url_extractor, passando il topic_dataframe come argomento. Recupera una lista di URL ( url ) estratti dal dataframe.

6. name = topic_dataframe['Title'] : Questa riga recupera la colonna ‘Title’ dal dataframe topic_dataframe e la assegna alla variabile name.

7. for i in range(len(topic_dataframe)): ... : Questo ciclo itera sugli indici del dataframe topic_dataframe.

8. new_df = topic_information_scraper(url[i]) : Questa riga chiama la funzione topic_information_scraper, passando l’URL ( url[i] ) come argomento. Recupera le informazioni del repository per l’URL del topic specifico e le assegna al dataframe new_df.

9. new_df.to_csv(f'GitHubTopic_CSV-Files/{name[i]}.csv', index=None) : Questa riga esporta il dataframe new_df in un file CSV. Il nome del file viene generato dinamicamente utilizzando una stringa f (f-string), che incorpora il nome del topic ( name[i] ). L’argomento index=None garantisce che gli indici delle righe non siano inclusi nel file CSV.

Lo scopo di questo script è quello di estrarre informazioni dalla pagina dei topic di GitHub e creare file CSV contenenti i dati estratti. Prima recupera la pagina dei topic principali, salva le informazioni estratte in ‘GitHubtopics.csv’ e quindi procede a estrarre le singole pagine dei topic utilizzando gli URL estratti.

Per ogni topic, crea un nuovo file CSV chiamato come il topic e salva le informazioni del repository al suo interno.

Questo script può essere eseguito direttamente per eseguire l’estrazione e generare i file CSV desiderati.

Output finale

url = 'https://github.com/topics'topic_dataframe = topicSraper(topic_page_authentication(url))topic_dataframe.to_csv('GitHubtopics.csv', index=None)

Una volta eseguito questo codice, verrà generato un file CSV chiamato ‘GitHubtopics.csv’, che assomiglia a questo e copre tutti i nomi dei topic, le loro descrizioni e i loro URL.

GitHubtopics.csv
url = topic_url_extractor(topic_dataframe) name = topic_dataframe['Title']for i in range(len(topic_dataframe)):    new_df = topic_information_scraper(url[i])    new_df.to_csv(f'GitHubTopic_CSV-Files/{name[i]}.csv', index=None)

Quindi questo codice verrà eseguito per creare i file CSV specifici basati sui topic salvati nel file ‘GitHubtopics.csv’ precedente. Quindi quei file CSV vengono salvati in una directory chiamata ‘GitHubTopic_CSV-Files’ con i loro nomi specifici del topic. Quelli csv files hanno questo aspetto.

GitHubTopcis_CSV-Files

Questi file csv di Topic contengono alcune informazioni sui topic, come il loro nome utente, il nome del repository, le stelle del repository e l’URL del repository.

3D.csv

Nota: i tag del sito web potrebbero cambiare, quindi prima di eseguire questo script python, controlla i tag una volta in base al sito web.

Accesso allo script completo >> https://github.com/PrajjwalSule21/GitHub-Topic-Scraper/blob/main/RepoScraper.py

Chatathon di Chatbot Conference