Questo articolo apparteneva al vecchio blog (blog.danilopetrozzi.it), per cui le informazioni potrebbero non essere più aggiornate ed attendibili.

Come costruire uno web scraper personalizzato con Python

Python è un linguaggio di programmazione interpretato (non serve la compilazione) molto versatile e facile da usare. Data la quantità spropositata di moduli liberamente scaricabili e utilizzabili, Python è estremamente versatile.

Un grande vantaggio di Python rispetto a altri linguaggi di progrmamazione più ostici, è la possibilità di usare IDLE, una shell interattiva che esegue le istruzioni in tempo reale (senza dover stare a compilare / lanciare di volta in volta uno script, come succede per altri linguaggi compilati).

Il problema che andiamo a affrontare oggi è il seguente: come faccio a costruire un semplicissimo web scraper in Python che possa soddisfare le mie esigenze?

Se ad esempio:

– vuoi prelevare in automatico i meta di un determinato

– scaricare il sorgente di una pagina e salvarlo in automatico da qualche parte

– vuoi prelevare una determinata informazione da centinaia di siti in modo automatico

Allora questa mini guida fa per te 🙂

A cosa serve uno scraper

Con uno scraper è possibile ottenere informazioni da pagine web in modo automatizzato. Gli utilizzi di uno scraper sono sostanzialmente infiniti!

Se ad esempio sei un SEO specialist, potresti aver bisogno di prelevare delle informazioni da uno o più competitor in modo automatizzato.

Oppure potrei fare scraping su Wikipedia per rubare il contenuto di migliaia di pagine 😀

Oppure potrei fare scraping per prelevare la lista dei siti in una SERP di Google (questo è effettivamente uno degli scrape più diffusi, e difficili, da effettuare)

E così via..

Prepariamo gli strumenti

La prima cosa che ti serve è logicamente Python. Anche se qualcuno si ostina a usare la famiglia 2.x, noi useremo l’ultima versione di Python ossia la 3.4.1

Dopo aver installato Python, dobbiamo installare due moduli indispensabili per creare lo scraper: requests e BeautifulSoup. Se sai già come si installano manualmente i moduli, allora procedi, altrimenti, se sei alle prime armi, puoi usare il metodo “pip”: nelle ultime versioni di Python è stato integrato un modulo che si occupa di installare/disinstallare altri moduli in modo facile e intuitivo.

Per installare i due moduli che ho citato in alto, devi semplicemente aprire il DOS (cmd.exe) e digitare questi due comandi:

pip install requests

pip install BeautifulSoup

(ognuno dei due comandi richiederà qualche secondo, dato che pip si occupa di scaricare e installare il modulo specifico)

Ora che hai Python, BS e requests, hai tutto il necessario per creare il tuo primo scraper!

Creiamo il nostro baby-scraper

Creiamo un nuovo file e lo chiamiamo scraper.py, al quale aggiungiamo subito i due import:

 Con queste due istruzioni abbiamo caricato i moduli precedentemente installati (rispettivamente BeautifulSoup e requests). Il passo successivo è quello di definire una funzione generica e molto semplice che, dato in input un URL, ne estrapola il codice sorgente.

Questo avviene grazie alla funzione requests.get() e alla successiva proprietà .text. Vediamo:

def estrapola_sorgente(url):  -> definisce una nuova funzione di nome “estrapola_sorgente” che ha bisogno di un solo parametro che noi definiamo come “url”

sorgente = requests.get(url).text -> all’interno della variabile temporanea “sorgente” facciamo confluire il testo (.text) della funzione requests.get(url) che è colei che esegue la richiesta HTTP

return(sorgente) -> dopo aver prelevato il sorgente, la funzione restituisce questo valore in output (altrimenti non potremmo manipolarlo più avanti)

Questo significa che per ottenere il codice sorgente del mio sito, dovrei semplicemente lanciare questo comando:  estrapola_sorgente(‘http://www.danilopetrozzi.it’)

Aggiungiamo un controllo sull’input

Per essere sicuri che tutto funzioni alla perfezione, proviamo a aggiungere un controllo sull’input per verificare che la stringa passata alla funzione estrapola_sorgente() sia un URL valido. Per fare questo, aggiungiamo un semplicissimo costrutto if, in cima alla funzione.

Aggiungendo la condizione  if ‘http://’ in url:  ci proteggiamo da eventuali nostri errori di scrittura/copiatura. Sostanzialmente, se nell’URL inviato alla funzione c’è la stringa “http://”, allora procedo con le operazioni, altrimenti mi fermo in anticipo restituendo la frase “L’url non è valido”.

La funzione che estrapola il sorgente è pronta, non dobbiamo aggiungere altro. Ora passiamo alla seconda fase, quella in cui decidiamo COSA estrapolare, e COME farlo, dal codice sorgente.

Potremmo scrivere una istruzione diretta che esegue immediatamente “il COSA e il COME”, ma è più utile creare una seconda funzione, così in futuro saremo in grado di iterare il processo (alla fine del post capirai di cosa parlo).

Ora dobbiamo porci la domanda principale: che COSA vogliamo estrapolare dalle pagine?

Un tag HTML? Un meta? Una porzione di testo? Un

con id=”” particolare?

Grazie al regex o a BeautifulSoup, hai la possibilità di estrapolare letteralmente qualsiasi cosa ti venga in mente. Se è presente nel sorgente, allora la puoi estrapolare: questa è la regola!

Per fare un esempio semplice, ipotizziamo di voler prelevare tutti gli H1 di una pagina. Iniziamo col costruire una funzione che prepara l’elemento “soup”, vediamo:

Grazie alla nuova funzione estrapola_h1() saremo in grado di “tirare fuori” gli H1 da un determinato codice sorgente. La prima istruzione  soup = bs4.BeautifulSoup(sorgente) inizializza l’oggetto di BS con il quale andremo a estrapolare il contenuto che ci interessa.

Aggiungiamo le istruzioni che ci permettono effettivamente di prelevare gli H1 dal sorgente:

La funzione findAll, ci permette di ricercare un determinato tag all’interno del “soup”. L’output di questa funzione è una lista oppure NULL se non trova nulla. E’ proprio per questo che aggiungiamo l’istruzione  if elenco:  che serve proprio a verificare se sono stati trovati H1 oppure no.

Se “elenco” esiste, allora lo visualizziamo grazie a un mini ciclo for.

In linea di massima, abbiamo finito! Python è un codice facilissimo da leggere/scrivere, ed è estremamente corto. La stessa cosa fatta in PHP o C, avrebbe richiesto almeno il 30%-50% in più di codice.

Ora vediamo come migliorare un pò l’utilità di questo scraper basilare:

L’output di questo script è:

Abbiamo aggiunto per prima cosa una lista di stringhe, contenenti tutti gli URL che vogliamo scansionare (espertoseo.it, example.org e così via).

Successivamente abbiamo costruito un for su quella lista, e quindi il suo contenuto viene eseguito per ciascun URL.

Per ogni URL della lista viene estrapolato il sorgente (grazie a estrapola_sorgente()), vengono individuati gli H1 (grazie a estrapola_h1()). Ho aggiunto due print() per rendere più leggibile l’output finale. Il primo ( print(‘Elenco degli H1 di ‘ + sito) ) ci serve così in output sapremo a quale sito corrisponde la lista, mentre il secondo ( print() ) è un modo “spartano” per aggiungere una linea di intermezzo. 

Estrapolazione del rel=”author”

Se al posto degli H1 volessimo trovare il rel=”author” di ogni URL? Ci basta modificare un pò i nomi delle funzioni e il comando da passare a BeautifulSoup, e il gioco è fatto:

L’output di questo script è il seguente:

Estrapolazione di tutti i link con rel=”nofollow”

Rendiamo le cose più complicate: proviamo a fare scraping di tutti i link, ma solo con l’attributo rel=”nofollow”. Ecco come si fa:

L’output è il seguente:

Come puoi vedere da quest’ultimo esempio, abbiamo usato la funzione soup.find_all(‘a’) per cercare tutti i link (tutti gli a all’interno del codice )

Analizzando ogni risultato di questa ricerca ( grazie al for a in elenco: ) cerchiamo di capire se il link in esame contiene il nofollow oppure no. Il controllo è affidato all’istruzione if ‘nofollow’ in a.get(‘rel’)[0]:  che si accerta della presenza della stringa “nofollow” all’interno dell’attributo “rel” del link in esame.

Ho aggiunto l’indice [0] dato che in realtà la funzione va a cercare tutti i rel=””, ma sicuramente ogni link ha un solo rel=””, per cui dobbiamo indicare il primo elemento della lista (ossia l’index zero).

In conclusione

Abbiamo creato uno script basilare per sviluppare uno scraper in Python. Grazie a questo punto di partenza è possibile sviluppare algoritmi molto complessi e di notevole utilità.

Per rendere il post più semplice possibile, non mi sono addentrato in comandi “avanzati” di Python. Per fare un esempio, avremmo dovuto implementare la gestione delle eccezioni (con try: .. except: ..)  dato che, attualmente, se uno degli URL non risponde o è inesistente, porterebbe al blocco di tutto lo script.

Avremmo potuto implementare una funzione che scrive l’output all’interno di un file esterno, per maggiore praticità. (magari in formato .csv opportunamente strutturato, così da avere dei dati immediatamente fruibili).

Avremmo potuto implementare l’uso dei proxy e degli user-agent randomizzati, se per caso avessimo voluto effettuare “operazioni border-line” 🙂

Spero che la miniguida sia stata utile 😀

Nota: Le istruzioni che abbiamo visto oggi, sono alla base del mio software SEO OmnibuScanner, che è semplicemente un maxi-scraper in cui ho riunificato numerose estrapolazioni effettuate con regex, BeautifulSoup e altri moduli di questo tipo.

 

 

Danilo petrozzi

Ciao! Io sono Danilo Petrozzi, il fondatore di Eternal Curiosity. Oltre a essere un senior SEO Specialist e un Web Developer, è dall'età di 9 anni che mi appassiono a qualsiasi cosa ruoti intorno al web e all'informatica in generale.

Lascia un commento