Même si cette approche de la collecte de données semble bonne, elle est mal vue par de nombreux sites web, et il y a des conséquences à la poursuite du scraping, comme l'interdiction de notre IP.
D'un point de vue positif, les services de proxy permettent d'éviter ces conséquences. Ils nous permettent de prendre une autre IP pendant que nous collectons des données en ligne, et aussi sûr que cela puisse paraître, il est préférable d'utiliser plusieurs proxys. L'utilisation de plusieurs proxys pendant le scraping donne l'impression que l'interaction avec le site web est aléatoire et renforce la sécurité.
Le site web cible (source) de ce guide est une librairie en ligne. Il imite un site de commerce électronique pour les livres. On y trouve des livres avec un nom, un prix et une disponibilité. Comme ce guide ne se concentre pas sur l'organisation des données renvoyées mais sur la rotation des proxies, les données renvoyées ne seront présentées que dans la console.
Installer et importer quelques modules Python dans notre fichier avant de pouvoir commencer à coder les fonctions qui aideraient à la rotation des proxies et au scraping du site web.
pip install requests beautifulSoup4 lxml
3 des 5 modules Python nécessaires à ce script de scraping peuvent être installés à l'aide de la commande ci-dessus. Requests nous permet d'envoyer des requêtes HTTP au site web, beautifulSoup4 nous permet d'extraire les informations de la page HTML fournie par les requêtes, et LXML est un analyseur HTML.
En outre, nous avons également besoin du module de threading intégré pour permettre des tests multiples des proxies pour voir s'ils fonctionnent et json pour lire à partir d'un fichier JSON.
import requests
import threading
from requests.auth import HTTPProxyAuth
import json
from bs4 import BeautifulSoup
import lxml
import time
url_to_scrape = "https://books.toscrape.com"
valid_proxies = []
book_names = []
book_price = []
book_availability = []
next_button_link = ""
Construire un script de scraping qui fait tourner les proxies signifie que nous avons besoin d'une liste de proxies à choisir pendant la rotation. Certains proxys nécessitent une authentification, d'autres non. Nous devons créer une liste de dictionnaires avec les détails du proxy, y compris le nom d'utilisateur et le mot de passe du proxy si l'authentification est nécessaire.
La meilleure approche consiste à placer les informations relatives au proxy dans un fichier JSON distinct, organisé comme celui présenté ci-dessous :
[
{
"proxy_address": "XX.X.XX.X:XX",
"proxy_username": "",
"proxy_password": ""
},
{
"proxy_address": "XX.X.XX.X:XX",
"proxy_username": "",
"proxy_password": ""
},
{
"proxy_address": "XX.X.XX.X:XX",
"proxy_username": "",
"proxy_password": ""
},
{
"proxy_address": "XX.X.XX.X:XX",
"proxy_username": "",
"proxy_password": ""
}
]
Dans le champ "proxy_address", entrez l'adresse IP et le port, séparés par deux points. Dans les champs "proxy_username" et "proxy_password", indiquez le nom d'utilisateur et le mot de passe pour l'autorisation.
Voici le contenu d'un fichier JSON contenant quatre serveurs mandataires parmi lesquels le script peut choisir. Le nom d'utilisateur et le mot de passe peuvent être vides, ce qui indique que le proxy ne nécessite pas d'authentification.
def verify_proxies(proxy:dict):
try:
if proxy['proxy_username'] != "" and proxy['proxy_password'] != "":
proxy_auth = HTTPProxyAuth(proxy['proxy_username'], proxy['proxy_password'])
res = requests.get(
url_to_scrape,
auth = proxy_auth,
proxies={
"http" : proxy['proxy_address']
}
)
else:
res = requests.get(url_to_scrape, proxies={
"http" : proxy['proxy_address'],
})
if res.status_code == 200:
valid_proxies.append(proxy)
print(f"Proxy Validated: {proxy['proxy_address']}")
except:
print("Proxy Invalidated, Moving on")
Par précaution, cette fonction s'assure que les proxys fournis sont actifs et fonctionnent. Nous pouvons y parvenir en parcourant en boucle chaque dictionnaire du fichier JSON, en envoyant une requête GET au site web et, si un code de statut 200 est renvoyé, en ajoutant ce proxy à la liste des valid_proxies - une variable que nous avons créée plus tôt pour héberger les proxies qui fonctionnent à partir de la liste figurant dans le fichier. Si l'appel n'aboutit pas, l'exécution se poursuit.
Puisque beautifulSoup a besoin du code HTML du site web pour extraire les données dont nous avons besoin, nous avons créé request_function(), qui prend l'URL et le proxy de notre choix et renvoie le code HTML sous forme de texte. La variable proxy nous permet d'acheminer la requête à travers différents proxys, d'où la rotation du proxy.
def request_function(url, proxy):
try:
if proxy['proxy_username'] != "" and proxy['proxy_password'] != "":
proxy_auth = HTTPProxyAuth(proxy['proxy_username'], proxy['proxy_password'])
response = requests.get(
url,
auth = proxy_auth,
proxies={
"http" : proxy['proxy_address']
}
)
else:
response = requests.get(url, proxies={
"http" : proxy['proxy_address']
})
if response.status_code == 200:
return response.text
except Exception as err:
print(f"Switching Proxies, URL access was unsuccessful: {err}")
return None
data_extract() extrait les données dont nous avons besoin du code HTML fourni. Il rassemble l'élément HTML contenant les informations relatives au livre, telles que le nom du livre, le prix et la disponibilité. Il extrait également le lien vers la page suivante.
Cette opération est particulièrement délicate car le lien est dynamique, et nous avons donc dû tenir compte de ce dynamisme. Enfin, il parcourt les livres et extrait le nom, le prix et la disponibilité, puis renvoie le lien du bouton suivant que nous utiliserions pour récupérer le code HTML de la page suivante.
def data_extract(response):
soup = BeautifulSoup(response, "lxml")
books = soup.find_all("li", class_="col-xs-6 col-sm-4 col-md-3 col-lg-3")
next_button_link = soup.find("li", class_="next").find('a').get('href')
next_button_link=f"{url_to_scrape}/{next_button_link}" if "catalogue" in next_button_link else f"{url_to_scrape}/catalogue/{next_button_link}"
for each in books:
book_names.append(each.find("img").get("alt"))
book_price.append(each.find("p", class_="price_color").text)
book_availability.append(each.find("p", class_="instock availability").text.strip())
return next_button_link
Pour relier le tout, il faut :
with open("proxy-list.json") as json_file:
proxies = json.load(json_file)
for each in proxies:
threading.Thread(target=verify_proxies, args=(each, )).start()
time.sleep(4)
for i in range(len(valid_proxies)):
response = request_function(url_to_scrape, valid_proxies[i])
if response != None:
next_button_link = data_extract(response)
break
else:
continue
for proxy in valid_proxies:
print(f"Using Proxy: {proxy['proxy_address']}")
response = request_function(next_button_link, proxy)
if response is not None:
next_button_link = data_extract(response)
else:
continue
for each in range(len(book_names)):
print(f"No {each+1}: Book Name: {book_names[each]} Book Price: {book_price[each]} and Availability {book_availability[each]}")
import requests
import threading
from requests.auth import HTTPProxyAuth
import json
from bs4 import BeautifulSoup
import time
url_to_scrape = "https://books.toscrape.com"
valid_proxies = []
book_names = []
book_price = []
book_availability = []
next_button_link = ""
def verify_proxies(proxy: dict):
try:
if proxy['proxy_username'] != "" and proxy['proxy_password'] != "":
proxy_auth = HTTPProxyAuth(proxy['proxy_username'], proxy['proxy_password'])
res = requests.get(
url_to_scrape,
auth=proxy_auth,
proxies={
"http": proxy['proxy_address'],
}
)
else:
res = requests.get(url_to_scrape, proxies={
"http": proxy['proxy_address'],
})
if res.status_code == 200:
valid_proxies.append(proxy)
print(f"Proxy Validated: {proxy['proxy_address']}")
except:
print("Proxy Invalidated, Moving on")
# Récupère l'élément HTML d'une page
def request_function(url, proxy):
try:
if proxy['proxy_username'] != "" and proxy['proxy_password'] != "":
proxy_auth = HTTPProxyAuth(proxy['proxy_username'], proxy['proxy_password'])
response = requests.get(
url,
auth=proxy_auth,
proxies={
"http": proxy['proxy_address'],
}
)
else:
response = requests.get(url, proxies={
"http": proxy['proxy_address'],
})
if response.status_code == 200:
return response.text
except Exception as err:
print(f"Switching Proxies, URL access was unsuccessful: {err}")
return None
# Grattage
def data_extract(response):
soup = BeautifulSoup(response, "lxml")
books = soup.find_all("li", class_="col-xs-6 col-sm-4 col-md-3 col-lg-3")
next_button_link = soup.find("li", class_="next").find('a').get('href')
next_button_link = f"{url_to_scrape}/{next_button_link}" if "catalogue" in next_button_link else f"{url_to_scrape}/catalogue/{next_button_link}"
for each in books:
book_names.append(each.find("img").get("alt"))
book_price.append(each.find("p", class_="price_color").text)
book_availability.append(each.find("p", class_="instock availability").text.strip())
return next_button_link
# Obtenir un proxy à partir de JSON
with open("proxy-list.json") as json_file:
proxies = json.load(json_file)
for each in proxies:
threading.Thread(target=verify_proxies, args=(each,)).start()
time.sleep(4)
for i in range(len(valid_proxies)):
response = request_function(url_to_scrape, valid_proxies[i])
if response is not None:
next_button_link = data_extract(response)
break
else:
continue
for proxy in valid_proxies:
print(f"Using Proxy: {proxy['proxy_address']}")
response = request_function(next_button_link, proxy)
if response is not None:
next_button_link = data_extract(response)
else:
continue
for each in range(len(book_names)):
print(
f"No {each + 1}: Book Name: {book_names[each]} Book Price: {book_price[each]} and Availability {book_availability[each]}")
Après une exécution réussie, les résultats ressemblent à ce qui suit. Il extrait ensuite des informations sur plus de 100 livres à l'aide des deux serveurs mandataires fournis.
L'utilisation de plusieurs proxys pour le web scraping permet d'augmenter le nombre de requêtes vers la ressource cible et de contourner le blocage. Pour maintenir la stabilité du processus de scraping, il est conseillé d'utiliser des adresses IP qui offrent une vitesse élevée et un facteur de confiance important, comme les proxys statiques des FAI et les proxys résidentiels dynamiques. En outre, la fonctionnalité du script fourni peut être facilement étendue pour répondre à diverses exigences en matière de récupération de données.
Мы получили вашу заявку!
Ответ будет отправлен на почту в ближайшее время.
С уважением proxy-seller.com!
Commentaires: 0