Come creare uno scraper con User-Agent Rotation

L’informazione ‘user-agent’ è una stringa che un web browser o una app invia ad ogni sito web visitato. Una tipica stringa di ‘user-agent’ contiene dettagli come: il tipo di applicazione, il sistema operativo, il fornitore del software o la versione software utilizzato dal client che interroga il Web Server di un sito. I Web Server utilizzano questi dati per valutare le funzionalità del computer, ottimizzando le prestazioni e la visualizzazione di una pagina.

Di seguito un esempio di stringa user-agent dell’header:

user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36

Ogni richiesta effettuata da un browser Web contiene un’intestazione user-agent. Quando si analizzano molte pagine di un sito Web con uno scraper, l’uso dello stesso user-agent porta coerentemente al rilevamento della presenza di un bot. Un modo per bypassare tale rilevamento è fingere il proprio user-agent e modificarlo con ogni richiesta effettuata su un sito web.

In questo tutorial, vedremo come modificare e rendere casuale il proprio user-agent per evitare di essere bloccati durante lo scraping di un sito web.

Come modificare il proprio user-agent con Python 3

Utilizzando la libreria ‘requests’ possiamo modificare il nostro user-agent passando un parametro nell’header della chiamata GET. Per testare il codice possiamo utilizzare il sito httpbin.org:

import requests 
url = 'https://httpbin.org/user-agent'
user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0'
headers = {'User-Agent': user_agent}
response = requests.get(url,headers=headers)
html = response.content
print(response.content)

Questo è quello che otterremo come risultato, una stringa contenente i dati dell’user-agent che abbiamo impostato in modo manuale:

'{\n  "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0"\n}'

Per rendere casuale la stringa dell’user-agent possiamo impostare una lista contenente una serie di 10 user-agent diversi. Una volta generata la lista possiamo pescare in modo casuale un elemento della lista grazie alla funzione choice della libreria ‘random‘. Aggiungiamo anche un ciclo while per ripetere la richiesta 10 volte. Vediamo il codice modificato:

import requests
import random
i=0
url = 'https://httpbin.org/user-agent'
user_agent = [
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0',
    'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36',
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
    'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
    'Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1)',
    'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko',
    'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)',
    'Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko',
    'Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0)',
    'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko']

while i<10:
    headers = {'User-Agent': random.choice(user_agent)}
    response = requests.get(url,headers=headers)
    html = response.content
    print(response.content)
    i=i+1

Se lanciamo lo script vederemo un risultato simile al seguente:

b'{\n  "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0"\n}\n'
b'{\n  "user-agent": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)"\n}\n'
b'{\n  "user-agent": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0)"\n}\n'
b'{\n  "user-agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"\n}\n'
b'{\n  "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0"\n}\n'
b'{\n  "user-agent": "Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 6.1)"\n}\n'
b'{\n  "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"\n}\n'
b'{\n  "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"\n}\n'
b'{\n  "user-agent": "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"\n}\n'
b'{\n  "user-agent": "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0)"\n}\n'

Come si può notare questa semplice tecnica ci permette di fingere che le nostre chiamate tramite uno script Python vengano considerate come chiamate effettuate da normali web browser, ogni chiamata sembrerà effettuata da un browser scelto in modo casuale da una lista appositamente preimpostata.

Con questa tecnica è possibile ridurre il rischio di essere bloccati durante un lavoro di scraping dalle misure solitamente presenti nei web server per la limitazione delle chiamate al server.

Pubblicato da Ferro Mauro

Contattami se ha bisogno di una consulenza sulla sicurezza aziendale per difenderti dal social engineering