Scraping con l’aiuto di HTTPX
HTTPX è un pacchetto Python di terze parti che consente di effettuare richieste HTTP dal codice Python. Oggi impareremo a usarlo per raccogliere i post più recenti di un dato utente sul sito di social media di destra Gab.
Installiamo dalla riga di comando di Python il modulo httpx
con la funzione pip eseguendo il comando python3 -m pip install httpx. Dopo aver importato httpx
nel codice, dovremmo essere in grado di caricare una pagina web eseguendo la funzione httpx.get()
e passandole un URL. Questa funzione restituisce un oggetto-richiesta ed è possibile accedere al contenuto della richiesta con .content
, per i dati binari, o con .text
, per i dati testuali. Per esempio, il prossimo listato mostra il codice Python per effettuare una richiesta HTTP a https://example.com
e visualizzarne il contenuto.
>>> import httpx
>>> r = httpx.get("https://example.com")
>>> print(r.text)
<!doctypehtml>
<html>
<head>
<title>Example Domain</title>
--altre righe--
</head>
<body>
<div>
<h1>Example Domain</ h1>
<p>This domain is for use in illustrative examples in documents. You may use this ⤶
domain in literature
without prior coordination or asking for permission.</p>
<p><a href="https://www .iana .org /domains /example">More information...</a></p>
</div>
</body>
</html>
Innanzitutto, questo codice importa il modulo httpx
. Poi richiama la funzione httpx.get()
, passandole come argomento un URL e salva la risposta nella variabile r
. Infine, mostra la variabile r.text
, che è tutto il codice HTML che costituisce https://example.com
. Se stiamo caricando un file binario, come un’immagine, possiamo trovare i dati binari nella variabile r.content
. Questa semplice funzione httpx.get()
spesso è tutto ciò che serve per estrarre interi database di informazioni dalla rete.
Leggi anche: 9 libri per realizzare la cybersicurezza che ti serve
Poiché fare web scraping significa scrivere codice che carica URL, il primo passo dovrebbe essere determinare quali URL è necessario caricare. Il modo più semplice per farlo consiste nell’utilizzare gli strumenti di sviluppo integrati nel browser web. possiamo aprirli nella maggior parte dei browser premendo il tasto F12. Sia in Firefox sia in Chrome, possiamo vedere le richieste HTTP effettuate dal browser e l’aspetto delle risposte nella scheda Rete degli Strumenti per sviluppatori. Per esempio, se apriamo gli strumenti di sviluppo del browser e carichiamo la pagina del profilo di un utente Gab, possiamo vedere quali richieste HTTP effettua il browser per raccogliere i post più recenti di quell’utente. Una volta ottenute queste informazioni, possiamo sviluppare uno script che effettui quelle stesse richieste HTTP.
Dove sta la deputata
Per esempio, la pagina Gab di Marjorie Taylor Greene, deputata statunitense nazionalista cristiana e teorica del cospirazionismo di QAnon, si trova su https://gab.com/RealMarjorieGreene
. In un browser web, carichiamo l’URL e poi apriamo gli strumenti per sviluppatori. Aggiorniamo la pagina per visualizzare tutte le richieste HTTP nella scheda Rete.
Nella scheda Rete, vedremo diverse richieste http, elencate nella metà sinistra del pannello degli strumenti per sviluppatori. Quando facciamo clic su una richiesta, la metà destra del pannello visualizza le relative informazioni. La metà destra ha le proprie schede tramite le quali possiamo visualizzare dettagli come le intestazioni della richiesta, i cookie, il corpo della richiesta e la relativa risposta.
Quando ho caricato questa pagina e ho esaminato le richieste HTTP del mio browser e le relative risposte, ho deciso che ero particolarmente interessato ai seguenti URL.
https://gab.com/api/v1/account_by_username/RealMarjorieGreene
La risposta a questa richiesta include un oggetto JSON contenente informazioni sul profilo Gab di Greene, incluso l’ID del suo account Gab,3155503
.https://gab.com/api/v1/accounts/3155503/statuses
?sort_by=newest
La risposta a questa richiesta include un array JSON dei post su Gab più recenti di Greene. Il suo ID account è nell’URL stesso.
Il primo URL mi consente di cercare in Gab l’ID di qualsiasi account e il secondo URL mi consente di cercare i post recenti di un account, in base al suo ID su Gab. La figura che segue mostra l’aspetto degli strumenti per sviluppatori di Firefox in azione nel mio browser durante il caricamento di questa pagina.
Come possiamo vedere, questa risposta è in formato JSON. Volevo sviluppare uno script che, dato un nome-utente Gab, scaricasse gli ultimi post di quell’utente. Per scriverlo ho dovuto dedicare un po’ di tempo a studiare i dati JSON di queste risposte, per capire come erano strutturati e quali informazioni mi interessavano. Per esempio, visto che volevo iniziare con un nome-utente Gab, il mio script avrebbe prima dovuto caricare l’URL https://gab.com/api/v1/account_by_username/<
nome-utente>
, dove al posto di <
nome-utente>
deve essere posto il nome-utente di destinazione. Poi avrebbe dovuto analizzare i dati JSON ricevuti per estrarre l’ID di questo utente Gab. Quindi, utilizzando quell’ID, avrebbe dovuto caricare l’URL https://gab.com/api/v1/accounts/<
id>/statuses?sort_by=newest
, dove al posto di <
id>
occorre porre l’ID Gab dell’account in questione. Infine, doveva analizzare la risposta JSON per visualizzare gli ultimi suoi post su Gab.
Sulla base di questa ricerca, ho sviluppato il seguente script per recuperare gli ultimi post di qualsiasi account Gab. Ecco il codice di questo script di web scraping, httpx-example.py
:
import httpx
import click
@click.command()
@click.argument("gab_username") ➊
def main(gab_username):
"""Download a user's posts from Gab"""
# Get information about the user
r = httpx .get(f"https://gab.com /api /v1 /account by username /{gab username}") ➋
user_info = r.json()
if "error" in user_info:
print(user_info["error"])
return
# Display some user info
click.echo(f"Display name: {user_info['display_name']}")
click.echo(f"{user_info['followers_count']:,} followers, {user_info['following_count']:,}
following, {user_info['statuses_count']:,} posts") ➌
print()
# Get this user's posts
r = httpx .get(f"https://gab.com /api /v1 /accounts /{user info['id']} /statuses") ➍
posts = r.json()
for post in posts:
if post["reblog"]:
print(f"repost @{post['reblog']['account']['username']}: {post['reblog'] ⤶
['created_at']}:
{post['reblog']['content']}")
else:
print(f"{post['created_at']}: {post['content']}")
if __name__ == "__main__":
main()
Questo script importa prima il modulo httpx
, poiché ne avrà bisogno per effettuare le richieste HTTP. Come molti altri script Python, utilizza il modulo click
per accettare argomenti dalla riga di comando. In questo caso, accetta l’argomento gab_username
, il nome-utente dell’utente Gab in questione ➊.
Quando viene eseguita la funzione main()
, scarica le informazioni sull’utente richiamando la funzione httpx.get()
e passandole l’URL https://gab.com/api/v1/account_by_username/<
nome-utente-gab>
, sostituendo a <
nome-utente-gab>
il valore dell’argomento e memorizzando il risultato nella variabile r
➋. Come mostrano gli strumenti di sviluppo del mio browser, la risposta dovrebbe essere un oggetto JSON, quindi lo script richiama r.json()
su di esso per fare in modo che HTTPX lo converta in un dizionario, chiamato user_info
. Quindi controlla se user_info
ha una chiave error
; in tal caso, visualizza il messaggio d’errore e si chiude subito. Se Proviamo a caricare quell’URL con un nome-utente non valido, vedremo il seguente messaggio d’errore nella chiave error
: la stringa Record not found
.
Una volta che lo script ha recuperato con successo le informazioni su un utente Gab, visualizza alcune di queste informazioni (nome visualizzato, numero di follower, numero di persone seguite e numero di post) ➌. Lo script utilizza poi HTTPX per effettuare un’altra richiesta HTTP, questa volta per caricare i post dell’utente. Tenete in considerazione che questo URL include user_info['id']
, che è l’ID dell’utente scoperto dalla precedente richiesta HTTP ➍. Come prima, richiama r.json()
per convertire i dati JSON in un oggetto Python, questa volta una lista chiamata posts
. Nel ciclo for
seguente, lo script scorre l’elenco dei post, visualizzandoli uno alla volta.
Si può trovare una copia completa di questo codice nel repository GitHub del mio libro, all’indirizzo https://github.com/micahflee/hacks-
leaks-and-revelations/blob/main/appendix-b/httpx-example.py
.
Al momento in cui scrivo, potrei utilizzare questo script per scaricare i post recenti di qualsiasi utente Gab includendo il nome-utente come argomento. Per esempio, ecco quello che ho ottenuto quando ho eseguito questo script sull’account di Andrew Torba, fondatore e proprietario di Gab e autore del libro Christian Nationalism, il cui nome-utente Gab è a
:
micah@trapdoor appendix-b % python3 httpx-example.py a
Display name: Andrew Torba
3,803,381 followers, 2,662 following, 67,317 posts
2022-12-07T04:56:56.989Z: Is it really so crazy to think that I care nothing at all about a particular historical atrocity that happened on another continent 80 years ago when there is a genocide of babies happening right here, right now, today?
repost @ScipioAmericanus: 2022-12-07T04:50:37.560Z: Jews literally believe that they can reject God because they're justified according to the flesh and their own laws. Wicked stuff.
--altre righe--
L’output mostra il nome visualizzato di Torba, le statistiche sul suo account e molti dei suoi ultimi post su Gab. Come possiamo vedere, sono di stampo fascista. Torba ha 3,8 milioni di follower, perché ogni utente di Gab lo segue automaticamente quando crea un account.
I siti cambiano e così gli script
Proviamo a eseguire httpx-example.py
su qualsiasi account Gab. A meno che il sito web di Gab non sia cambiato, questo comando dovrebbe scaricare i post recenti di quell’utente. Tuttavia, è possibile che nel momento in cui eseguiremo questo script, il sito potrebbe essere cambiato e così che lo script non funzioni più. Questo è il difetto del web scraping. Ogni script che sviluppiamo per eseguire lo scraping del Web si basa su siti web che agiscono in un certo modo; in caso contrario, lo script potrebbe bloccarsi. Tuttavia, spesso è semplice aggiornare uno script in modo che torni a funzionare. Per fare ciò, dobbiamo utilizzare gli strumenti di sviluppo del browser per capire come è cambiato il sito web e poi aggiornare lo script in modo che corrisponda ai nuovi URL e al comportamento: in pratica, dobbiamo ripetere ciò che abbiamo appena fatto. Nel peggiore dei casi, se il sito web è cambiato molto, potrebbe essere necessario riscrivere da zero lo script di scraping.
Utilizzando codice Python e HTTPX, possiamo anche modificare lo script per ottenere tutti i post di un determinato account, anziché solo quelli recenti. Potremmo sviluppare uno script che trovi un utente Gab e scarichi l’elenco degli account che segue. Oppure potremmo prendere un post di Gab e scaricare un elenco di account che hanno messo Mi piace. Dobbiamo solo scoprire esattamente quali richieste HTTP effettuare per ottenere le informazioni che ci interessano e poi fare in modo che Python effettui tali richieste per noi. Alcune di queste attività sono più complicate di altre: per esempio, per ottenere i dati che stiamo cercando, potremmo dover creare un account Gab e fare in modo che lo scraper effettui richieste mentre abbiamo fatto login. Più script di web scraping svilupperemo, più ci risulterà facile.
Ulteriori informazioni sull’utilizzo del pacchetto HTTPX si trovano nella sua documentazione su https://www.python-httpx.org
.
Questo articolo richiama contenuti da Hacking, fughe di dati e rivelazioni.
Immagine di apertura originale di Towfiqu barbhuiya su Unsplash.