Un problema comune che si incontra durante la scansione di un sito è quello di venir identificati come un agente malevolo e venir bloccati attraverso l’iscrizione del proprio IP in una black-list del sito.
Ci sono varie tecniche per evitare questo problema, in questo articolo vedremo come proteggerci con l’uso di un proxies che cambiano ad ogni chiamata che effettuiamo al server che stiamo interrogando.
L’utilizzo di proxy e di indirizzi IP rotanti in combinazione con user-agents rotanti può aiutarti a superare la maggior parte delle misure anti-scraping e impedire di essere rilevato come un bot.
Il concetto di rotazione degli indirizzi IP durante lo scraping è semplice: si cerca far credere al sito web oggetto dell’analisi che non sei un singolo “bot” o una persona che accede con più richieste, ma più utenti che accedono al sito da più postazioni. Se questa tecnica viene utilizzata in modo corretto le possibilità di essere bloccati sono minime.
L’utilizzo di un proxy con Python 3 e la libreria Requests è molto semplice:
import requests
url= 'https://httpbin.org/ip'
proxies = {
'http': 'http://10.10.1.10:3128',
'https': 'http://10.10.1.10:1080',
}
requests.get(url, proxies=proxies)
print(response.json())
Nell’esempio sopra riportato viene indicato un indirizzo IP di un proxy gratuito, che molto probabilmente non sarà più in funzione nel momento in cui state leggendo quest’articolo.
Per individuare una lista di proxies gratuiti ci si può affidare a diversi siti web come ad esempio:
Dato che i proxies di queste liste cambiano piuttosto di frequente dobbiamo trovare un modo per automatizzare il controllo dei proxies disponibili, fortunatamente ci piace lo scraping e possiamo fare affidamento su Python!
Partiamo dall’ultimo sito dell’elenco, possiamo una funzione che effettui una chiamata al sito per scaricare la pagina con la libreria ‘requests‘ e successivamente con la libreria ‘lxml‘ andare a cercare le informazioni che ci interessano: l’indirizzo IP e la porta dei proxies con livello di sicurezza ‘elite’.
def proxy_list():
url = 'https://free-proxy-list.net/'
response = requests.get(url)
parser = etree.HTML(response.content)
proxies = set()
for i in parser.xpath('//*[@id="proxylisttable"]/tbody/tr')[:10]:
if i.xpath('.//td[5][contains(text(),"elite proxy")]'):
proxy = ":".join([i.xpath('.//td[1]/text()')[0], i.xpath('.//td[2]/text()')[0]])
proxies.add(proxy)
return(proxies)
Questo è il risultato che ottengo mentre scrivo, mentre leggete l’articolo la pagina potrebbe avere subito delle variazioni e potrebbe essere necessario modificare il percorso xpath di alcuni elementi:
{'1.20.101.175:38263', '190.248.136.18:46090', '125.25.45.120:49887', '140.227.204.8:3128', '109.172.65.134:58147', '190.90.193.96:32455', '170.247.31.159:44669', '88.116.12.182:32871', '118.175.93.185:47007', '86.120.78.21:33666'}
Potete provare a fare lo stesso lavoro con gli altri siti elencati: noterete che per via di alcuni accorgimenti adottati il compito sarà più complicato (ma non impossibile!).
Ora che abbiamo un metodo per avere una lista sempre aggiornata di indirizzi IP di server proxy possiamo creare un programma che utilizzi in modo ciclico gli indirizzi IP della lista simulando che le nostre richieste provengano da diverse località.
Possiamo fare una prova verificando l’indirizzo IP con il sito httpbin.org (cliccando sul link vedrete il vostro indirizzo IP attualmente in uso):
import requests
from lxml import etree
from itertools import cycle
def main():
proxies = proxy_list()
proxy_pool = cycle(proxies)
url = 'https://httpbin.org/ip'
for i in range(1,16):
proxy = next(proxy_pool)
print(f'Request {i}')
try:
response = requests.get(url,proxies={"http": proxy, "https": proxy})
print(response.json())
except:
print("Skipping. Proxy Not Responding")
def proxy_list():
url = 'https://free-proxy-list.net/'
response = requests.get(url)
parser = etree.HTML(response.content)
proxies = set()
for i in parser.xpath('//*[@id="proxylisttable"]/tbody/tr')[:10]:
if i.xpath('.//td[5][contains(text(),"elite proxy")]'):
proxy = ":".join([i.xpath('.//td[1]/text()')[0], i.xpath('.//td[2]/text()')[0]])
proxies.add(proxy)
return(proxies)
if __name__ == '__main__':
main()
Il risultato ottenuto sarà simile al seguente:
Request 1
{'origin': '202.93.128.98'}
Request 2
{'origin': '206.189.148.118'}
Request 3
{'origin': '129.205.160.160'}
Request 4
{'origin': '109.207.112.212'}
Request 5
{'origin': '77.82.88.249'}
Request 6
{'origin': '125.25.165.127'}
Request 7
{'origin': '36.89.181.155'}
Request 8
{'origin': '5.9.239.164'}
Request 9
{'origin': '202.93.128.98'}
Request 10
{'origin': '206.189.148.118'}
Request 11
{'origin': '129.205.160.160'}
Request 12
{'origin': '109.207.112.212'}
Request 13
{'origin': '77.82.88.249'}
Request 14
{'origin': '125.25.165.127'}
Request 15
{'origin': '36.89.181.155'}
In alcuni casi la connessione con un proxy può fallire per questo motivo è bene creare una chiamata try except per verificare che tutto vada bene.
Questo semplice script permette di usufruire di proxy server sempre aggiornati utile durante un lavoro di scansione, se unito ad un metodo di rotazione dell’user-agent costituisce una buona difesa contro il blocco da parte di un sito web.
Si consiglia di utilizzare solo proxy con livello di protezione alto (elite proxy), solo questi permettono di essere simulare la chiamata come se si trattasse di un utente reale che non stia utilizzando alcun proxy.
Si segnala che l’utilizzo di un proxy gratuito in alcuni casi è inefficace e sarebbe bene utilizzare un proxy a pagamento. I proxy gratuiti a volte vengono inseriti in black-list e subito respinti dai siti con una valida protezione.