Avec son énorme base d'utilisateurs et son vaste
répertoire d'entreprises,
Yelp est devenu une ressource incontournable pour des millions de personnes à la recherche de restaurants, de services et plus encore. Avec plus de
135 millions de visiteurs mensuels, Yelp offre une mine de données que les entrepreneurs, les spécialistes du marketing et les chercheurs peuvent exploiter pour obtenir des informations et prendre des décisions éclairées. Dans cet article, nous allons apprendre à
scraper les annonces de Yelp en utilisant
Python.
En utilisant Python avec
requests, nous allons extraire
les annonces de restaurants de Yelp à partir d'une
URL de recherche et
6 attributs de données. Nous allons scraper les noms, les URL, les notes, les critiques, les catégories et les quartiers. Plongeons et découvrons comment scraper les annonces de restaurants de Yelp en utilisant
Python et
requests.
Prérequis
Avant de scraper les annonces de restaurants de Yelp, nous devons nous assurer que nous avons les outils nécessaires en place. Les deux composants essentiels dont nous avons besoin sont Python et Sublime Text.
- Python : Assurez-vous d'avoir Python installé sur votre système. Si vous n'avez pas Python installé, vous pouvez le télécharger et l'installer à partir du site officiel de Python. Choisissez la version appropriée en fonction de votre système d'exploitation.
- Sublime Text : Sublime Text est un éditeur de texte populaire et léger qui offre un environnement simple et efficace pour écrire du code Python. Vous pouvez télécharger Sublime Text à partir du site officiel et l'installer sur votre ordinateur.
Une fois que vous avez Python et Sublime Text configurés, vous serez prêt à créer un scraper Yelp en utilisant Python et à écrire le code nécessaire.
Requirements
Pour scraper avec succès les annonces de Yelp en utilisant Python, nous devrons installer et importer plusieurs bibliothèques qui fournissent les fonctionnalités nécessaires. Voici les principales bibliothèques que nous utiliserons :
- requests : une bibliothèque HTTP puissante et conviviale pour Python. Elle simplifie le processus de réalisation de requêtes HTTP et de gestion des réponses, nous permettant de récupérer le contenu HTML des pages web.
- csv : offre des fonctionnalités pour lire et écrire des fichiers CSV (Comma-Separated Values). Nous utiliserons cette bibliothèque pour stocker les données dans un fichier CSV pour une analyse et un traitement ultérieurs.
- lxml : une bibliothèque robuste et efficace pour analyser les documents HTML et XML. Elle offre une navigation facile et une extraction de données en utilisant xPath ou les sélecteurs CSS, ce qui sera crucial pour extraire des éléments spécifiques des pages HTML de Yelp. lxml est généralement plus rapide que bs4, et elle peut analyser des HTML plus complexes. Cependant, elle est également plus complexe à utiliser et nécessite une dépendance externe en C.
- argparse : nous permet de gérer les arguments de la ligne de commande avec facilité. Il simplifie le processus de spécification des options et des paramètres lors de l'exécution du scraper Yelp, nous permettant de personnaliser l'URL de recherche et le nombre maximum de pages à scraper.
- time : fournit des fonctions pour les opérations liées au temps. Nous l'utiliserons pour introduire des délais entre les requêtes successives afin d'éviter de submerger le serveur.
Avant de continuer, assurez-vous que ces bibliothèques sont installées dans votre environnement Python. Nous pouvons facilement les installer en utilisant le gestionnaire de paquets Python pip.
pip install requests lxml
Les bibliothèques csv et argparse sont incluses dans la bibliothèque standard de Python, aucune installation séparée n'est nécessaire.
Code complet
Le code complet est accessible sur Github juste
ici.
Et ci-dessous:
import requests
import csv
from lxml import html
import argparse
import time
class YelpSearchScraper:
def iter_listings(self, url):
response = requests.get(url)
if response.status_code != 200:
print("Error: Failed to fetch the URL")
return None
with open('response.html', 'w') as f:
f.write(response.text)
tree = html.fromstring(response.content)
scraped_data = []
businesses = tree.xpath('//div[contains(@class, "container__09f24__mpR8_") and contains(@class, "hoverable__09f24__wQ_on") and contains(@class, "border-color--default__09f24__NPAKY")]')
for business in businesses:
data = {}
name_element = business.xpath('.//h3[contains(@class, "css-1agk4wl")]/span/a')
if name_element:
data['Name'] = name_element[0].text.strip()
data['URL'] = "https://www.yelp.com" + name_element[0].get('href')
rating_element = business.xpath('.//div[contains(@aria-label, "star rating")]')
if rating_element:
rating_value = rating_element[0].get('aria-label').split()[0]
if rating_value != 'Slideshow':
data['Rating'] = float(rating_value)
else:
data['Rating'] = None
reviews_element = business.xpath('.//span[contains(@class, "css-chan6m")]')
if reviews_element:
reviews_text = reviews_element[0].text
if reviews_text:
reviews_text = reviews_text.strip().split()[0]
if reviews_text.isnumeric():
data['Reviews'] = int(reviews_text)
else:
data['Reviews'] = None
price_element = business.xpath('.//span[contains(@class, "priceRange__09f24__mmOuH")]')
if price_element:
data['Price Range'] = price_element[0].text.strip()
# ok getting proper xpath
categories_element = business.xpath('.//span[contains(@class, "css-11bijt4")]')
if categories_element:
data['Categories'] = ", ".join([c.text for c in categories_element])
neighborhood_element = business.xpath('.//p[@class="css-dzq7l1"]/span[contains(@class, "css-chan6m")]')
if neighborhood_element:
neighborhood_text = neighborhood_element[0].text
if neighborhood_text:
data['Neighborhood'] = neighborhood_text.strip()
assert data
scraped_data.append(data)
return scraped_data
def save_to_csv(self, data, filename):
keys = data[0].keys()
with open(filename, 'w', newline='', encoding='utf-8-sig') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=keys, extrasaction='ignore')
writer.writeheader()
writer.writerows(data)
print("Success! \nData written to CSV file:", filename)
def scrape_results(self, search_url, max_page):
all_results = []
for page in range(1, max_page):
page_url = search_url + f'&start={(page-1)*10}'
print(f"Scraping Page {page}")
results = self.iter_listings(page_url)
if results:
all_results.extend(results)
time.sleep(2)
return all_results
def main():
s = time.perf_counter()
argparser = argparse.ArgumentParser()
argparser.add_argument('--search-url', '-u', type=str, required=False, help='Yelp search URL', default='https://www.yelp.com/search?find_desc=Burgers&find_loc=London')
argparser.add_argument('--max-page', '-p', type=int, required=False, help='Max page to visit', default=5)
args = argparser.parse_args()
search_url = args.search_url
max_page = args.max_page
assert all([search_url, max_page])
scraper = YelpSearchScraper()
results = scraper.scrape_results(search_url, max_page)
if results:
scraper.save_to_csv(results, 'yelp_search_results.csv')
else:
print("No results to save to CSV")
elapsed = time.perf_counter() - s
elapsed_formatted = "{:.2f}".format(elapsed)
print("Elapsed time:", elapsed_formatted, "seconds")
print('''~~ success
_ _ _
| | | | | |
| | ___ | |__ ___| |_ __ __
| |/ _ \| '_ \/ __| __/| '__|
| | (_) | |_) \__ \ |_ | |
|_|\___/|_.__/|___/\__||_|
''')
if __name__ == '__main__':
main()
Explication détaillée du code étape par étape
Importation des bibliothèques requises
Pour commencer à coder notre scraper Yelp, nous devons d'abord importer les bibliothèques. En important ces bibliothèques, nous nous assurons que nous avons accès aux outils et fonctionnalités requis pour notre scraper Yelp.
import requests
import csv
from lxml import html
import argparse
import time
Création de la classe YelpSearchScraper
Pour rendre notre code de scraping réutilisable et organisé, nous allons créer une classe appelée YelpSearchScraper. Cette classe contiendra toutes les méthodes nécessaires pour scraper et sauvegarder les données. La création de la classe YelpSearchScraper nous aide à organiser notre code et à le rendre réutilisable et maintenable. Nous pouvons créer des instances de cette classe et appeler ses méthodes à chaque fois que cela est nécessaire.
Collecte des données des annonces d'entreprises sur Yelp
Au sein de la classe YelpSearchScraper, nous avons la méthode iter_listings. Cette méthode prend un paramètre URL, représentant la page que nous voulons scraper.
class YelpSearchScraper:
def iter_listings(self, url):
response = requests.get(url)
if response.status_code != 200:
print("Error: Failed to fetch the URL")
return None
Voici ce qui se passe dans cette méthode :
- Elle envoie une requête HTTP GET à l'URL spécifiée en utilisant la fonction requests.get() et attribue la réponse à la variable de réponse.
- Le code vérifie ensuite l'attribut status_code de l'objet de réponse. Un code de statut 200 indique une réponse réussie. Si le code de statut n'est pas 200, cela signifie qu'il y a eu une erreur lors de la récupération de l'URL.
- Si le code de statut n'est pas 200, le code affiche un message d'erreur indiquant l'échec de la récupération de l'URL et renvoie None.
Après avoir récupéré le contenu HTML de la page Yelp, nous voulons le sauvegarder pour référence. Pour cela, nous pouvons utiliser le code suivant :
with open('response.html', 'w') as f:
f.write(response.text)
En sauvegardant le contenu HTML dans le fichier 'response.html', nous pouvons facilement examiner la structure et les éléments de la page récupérée. Cela est particulièrement utile pour comprendre les données et concevoir des expressions xPath appropriées ou des sélecteurs CSS pour extraire des informations spécifiques lors du processus de scraping.
Une fois que nous avons récupéré le contenu HTML de la page Yelp, l'étape suivante consiste à l'analyser et à en extraire les informations pertinentes. Examinons le code suivant :
tree = html.fromstring(response.content)
scraped_data = []
Dans ce morceau de code, nous utilisons la bibliothèque lxml pour analyser le contenu HTML et créer une représentation en arbre structurée. Voici comment cela fonctionne :
- Nous utilisons la fonction fromstring() du module html dans lxml pour créer un objet d'arbre appelé tree. Cette fonction prend en entrée response.content, qui contient le contenu HTML récupéré de Yelp.
- response.content représente le contenu HTML brut en bytes. En le passant à fromstring(), nous le convertissons en un objet d'arbre structuré que nous pouvons parcourir et extraire des données.
- Nous initialisons une liste vide appelée scraped_data pour stocker les données extraites des annonces de restaurants Yelp.
En créant l'objet tree, nous pouvons maintenant naviguer dans la structure HTML et extraire des éléments spécifiques en utilisant des expressions xPath. La liste scraped_data stockera les informations extraites.
Notre prochaine étape est d'extraire les annonces d'entreprises de la page Yelp. Ouvrons notre page response.html que nous avons sauvegardée plus tôt et utilisons l'outil d'inspection pour trouver le xPath pour localiser les éléments qui représentent les annonces d'entreprises sur la page Yelp.
Les annonces d'entreprises sur la page de résultats de recherche Yelp sont structurées sous forme de liste non ordonnée (<ul>). Chaque annonce d'entreprise est un <li>. Mais il y a aussi quelques éléments <li> vides. Au début, j'ai utilisé l'élément <ul> comme canon mais cela a abouti à l'extraction de données non désirées. J'ai donc changé pour le xPath <li>. Cela a également abouti à un scraping de données inexactes.
Pour éviter ces problèmes, nous nous limitons à un élément <div> à l'intérieur de <li> avec les classes "container__09f24__mpR8_", "hoverable__09f24__wQ_on", "border-color--default__09f24__NPAKY". Ces classes sont communes à toutes les cartes d'annonces d'entreprises mais pas aux éléments de liste vides et autres éléments non désirés.
businesses = tree.xpath('//div[contains(@class, "container__09f24__mpR8_") and contains(@class, "hoverable__09f24__wQ_on") and contains(@class, "border-color--default__09f24__NPAKY")]')
Dans ce morceau de code, nous utilisons la méthode xpath() de l'objet tree pour extraire les éléments souhaités du HTML analysé en fonction d'une expression xPath. Voici ce qui se passe :
- La méthode xpath() est appelée sur l'objet tree et prend une expression xPath en argument. L'expression xPath utilisée ici est
'//div[contains(@class, "container__09f24__mpR8_") and contains(@class, "hoverable__09f24__wQ_on") and contains(@class, "border-color--default__09f24__NPAKY")]'.
L'expression xPath cible les éléments <div> qui contiennent certaines classes. En utilisant la fonction contains(), nous spécifions que l'élément doit contenir les trois classes mentionnées dans l'expression. Cela nous aide à localiser les éléments spécifiques qui représentent les annonces commerciales sur la page Yelp.
La méthode xpath() renvoie une liste d'éléments correspondants, qui est assignée à la variable businesses.
Ce code extraira les éléments <div> pertinents représentant les annonces commerciales à partir du HTML analysé. Ces éléments serviront de base pour l'extraction d'informations spécifiques sur chaque restaurant, telles que le nom, la note, les avis, la fourchette de prix, et plus encore.
Maintenant que nous avons extrait les éléments d'annonce commerciale et les avons stockés dans la liste des entreprises, nous pouvons procéder à l'extraction de détails spécifiques pour chaque annonce.
for business in businesses:
data = {}
name_element = business.xpath('.//h3[contains(@class, "css-1agk4wl")]/span/a')
if name_element:
data['Nom'] = name_element[0].text.strip()
data['URL'] = "https://www.yelp.com" + name_element[0].get('href')
Dans ce fragment de code, nous parcourons chaque élément business dans la liste des entreprises et extrayons les informations pertinentes. Voici le détail du fragment :
- Pour chaque élément business, nous initialisons un dictionnaire vide appelé data pour stocker les détails extraits pour ce business particulier.
- Nous utilisons la méthode xpath() sur l'élément business pour trouver le nom du restaurant. L'expression xPath:
'.//h3[contains(@class, "css-1agk4wl")]/span/a'
cible l'élément <h3> avec la classe css-1agk4wl, qui contient un élément <span> suivi d'un élément <a> représentant le nom du restaurant.
- Si l'élément_nom est trouvé, nous extrayons le texte de l'élément en utilisant .text.strip() et l'assignons à data['Nom']. Nous construisons également l'URL du restaurant en concaténant "https://www.yelp.com" avec l'attribut href de l'élément <a> en utilisant .get('href'). Cette URL est assignée à data['URL'].
C'est ainsi que ce fragment de code va scraper les noms d'entreprises Yelp et les URLs des annonces.
Poursuivant l'extraction, extrayons les notes d'entreprises Yelp de chaque annonce. Pour cela, nous extrairons l'élément <div> avec l'attribut aria-label.
rating_element = business.xpath('.//div[contains(@aria-label, "star rating")]')
if rating_element:
rating_value = rating_element[0].get('aria-label').split()[0]
if rating_value != 'Slideshow':
data['Note'] = float(rating_value)
else:
data['Note'] = None
Dans ce fragment de code, nous extrayons les informations de notation pour chaque annonce d'entreprise. Voici comment cela fonctionne :
- Encore une fois, nous avons utilisé la méthode xpath() sur l'élément business pour localiser l'élément <div> qui contient les informations de notation. L'expression xPath:
'.//div[contains(@aria-label, "star rating")]'
sélectionne l'élément <div> qui a un attribut aria-label contenant le texte "star rating".
Si le rating_element est trouvé, nous extrayons la valeur de notation de l'attribut aria-label de l'élément. Nous récupérons l'attribut aria-label en utilisant .get('aria-label') et le divisons en une liste de mots en utilisant .split(). La valeur de notation est le premier élément de cette liste, représentant la valeur de notation numérique.
Nous vérifions si la valeur de notation extraite n'est pas égale à 'Slideshow' (un cas spécial où Yelp affiche un diaporama dynamique au lieu d'une notation numérique). Si ce n'est pas 'Slideshow', nous convertissons la valeur de notation en float en utilisant float(rating_value) et l'attribuons à data['Note']. Sinon, si c'est 'Slideshow', nous attribuons None à data['Note'].
Pour extraire le nombre d'avis, nous allons extraire le <span> ayant la classe css-chan6m. Voici le code qui va extraire les avis en utilisant ce xPath.
reviews_element = business.xpath('.//span[contains(@class, "css-chan6m")]')
if reviews_element:
reviews_text = reviews_element[0].text
if reviews_text:
reviews_text = reviews_text.strip().split()[0]
if reviews_text.isnumeric():
data['Reviews'] = int(reviews_text)
else:
data['Reviews'] = None
Voici une explication de ce morceau de code :
Nous utilisons la méthode xpath() pour localiser l'élément pour extraire le nombre d'avis.
Si l'élément reviews_element existe, nous extrayons le contenu textuel de l'élément en utilisant .text. Le texte extrait représente le nombre d'avis.
Nous nous assurons que reviews_text n'est pas vide ou None. S'il contient une valeur, nous extraisons la partie numérique du texte en supprimant tous les espaces blancs et en prenant le premier mot.
Après avoir extrait la partie numérique, nous vérifions si c'est un nombre valide en utilisant .isnumeric(). Si c'est le cas, on le convertit en entier et on l'affecte à data['Reviews']. Sinon, si ce n'est pas un nombre valide, on affecte None à data['Reviews'].
L'extraction de la fourchette de prix est la partie la plus simple de notre processus. Il suffit de localiser le <span> avec la classe priceRange__09f24__mmOuH et votre code ressemblera à ceci :
price_element = business.xpath('.//span[contains(@class, "priceRange__09f24__mmOuH")]')
if price_element:
data['Price Range'] = price_element[0].text.strip()
Ce simple extrait extraira la fourchette de prix des annonces.
Pour extraire les noms de catégories, nous utiliserons encore une fois l'inspecteur d'éléments pour trouver l'élément pertinent. Notre nom de catégorie se trouve dans le <span> avec la classe css-11bijt4. Ajoutons-le à notre code et extrayons les noms de catégories de toutes les annonces.
Pour récupérer les catégories associées à chaque annonce d'entreprise, nous utilisons le morceau de code suivant :
categories_element = business.xpath('.//span[contains(@class, "css-11bijt4")]')
if categories_element:
data['Categories'] = ", ".join([c.text for c in categories_element])
Voici ce que fait ce morceau de code :
Nous recherchons les éléments <span> qui contiennent une classe nommée "css-11bijt4" en utilisant le xpath()
Si l'élément categories_element existe, nous extrayons le contenu textuel de chaque élément <span> en utilisant une compréhension de liste : [c.text for c in categories_element]. Cela crée une liste des noms de catégories.
Ensuite, nous joignons les éléments de la liste en une seule chaîne, séparés par des virgules, en utilisant ", ".join(...). Cela consolide les noms de catégories en une chaîne formatée.
Si vous regardez le HTML, nous pouvons utiliser le nom de classe de <span> pour extraire les quartiers. Notre code localise la plupart des éléments en utilisant cette expression xPath. Mais dans le cas du quartier, le nom de la classe est css-chan6m, qu'est-ce qui le distingue ? C'est le même nom de classe que nous avons utilisé pour extraire les avis.
Si nous l'utilisons sans faire référence à un élément parent, cela perturbera toutes les données. Pour résoudre cela, nous utiliserons l'élément <p> parent comme référence. Voici à quoi ressemblera le code :
neighborhood_element = business.xpath('.//p[@class="css-dzq7l1"]/span[contains(@class, "css-chan6m")]')
if neighborhood_element:
neighborhood_text = neighborhood_element[0].text
if neighborhood_text:
data['Neighborhood'] = neighborhood_text.strip()
Nous avons déjà appris comment ce code fonctionne, donc pas besoin de l'expliquer à nouveau. Passons à la partie suivante de notre code.
Après avoir extrait les détails pertinents de chaque annonce d'entreprise, nous devons les stocker. Voici comment nous le faisons :
assert data
scraped_data.append(data)
return scraped_data
Ce morceau de code assure que le dictionnaire de données contient des informations valides avant de les stocker dans la liste scraped_data. Décortiquons le code :
L'instruction assert est utilisée pour valider une condition. Dans ce cas, nous affirmons que les données ne sont pas vides ou None. Si la condition est évaluée à False, une AssertionError est soulevée, indiquant qu'un événement inattendu s'est produit pendant le processus de scraping.
Après l'assertion, nous ajoutons le dictionnaire de données à la liste scraped_data. Cela ajoute les détails extraits pour une annonce d'entreprise particulière à la liste de toutes les données scrapées.
Enfin, nous renvoyons la liste scraped_data, qui contient des dictionnaires représentant les informations extraites pour chaque annonce d'entreprise.
Maintenant, notre script Python est fonctionnel et peut scraper les annonces Yelp avec 6 attributs de données. Sauvegardons les annonces Yelp que nous avons extraites dans un fichier CSV.
Enregistrement des données en CSV
Après avoir extrait les annonces Yelp avec les attributs de données souhaités, sauvegardons les données dans un fichier CSV. Pour ce faire, nous définirons une méthode save_to_csv dans la classe YelpSearchScraper.
def save_to_csv(self, data, filename):
keys = data[0].keys()
with open(filename, 'w', newline='', encoding='utf-8-sig') as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=keys, extrasaction='ignore')
writer.writeheader()
writer.writerows(data)
print("Succès!\nDonnées écrites dans le fichier CSV:", filename)
La méthode save_to_csv prend deux paramètres : data, représentant les données extraites, et filename, spécifiant le nom du fichier CSV à créer. Voici un décompte du code:
def save_to_csv(self, data, filename):
Cette ligne définit une méthode nommée save_to_csv au sein de la classe YelpSearchScraper. Elle prend trois paramètres : self, qui fait référence à l'instance de la classe, data, représentant les données extraites à sauvegarder, et filename, qui spécifie le nom du fichier CSV à créer.
Cette ligne récupère les clés (fieldnames) du premier dictionnaire de la liste data. Elle utilise la méthode keys() pour obtenir un objet de vue contenant les clés.
with open(filename, 'w', newline='', encoding='utf-8-sig') as csvfile:
Cette ligne ouvre le filename spécifié en mode écriture ('w') en utilisant la fonction open(). L'argument 'newline='' assure que les caractères de nouvelle ligne sont gérés correctement, et l'encodage 'utf-8-sig' est utilisé pour supporter les caractères non-ASCII.
writer = csv.DictWriter(csvfile, fieldnames=keys, extrasaction='ignore')
Cette ligne crée un objet DictWriter nommé writer. Il prend trois arguments : csvfile, qui est le fichier CSV ouvert, fieldnames=keys, qui spécifie les fieldnames pour le fichier CSV en fonction des clés obtenues précédemment, et extrasaction='ignore', qui indique à l'écrivain d'ignorer toutes les clés supplémentaires dans les dictionnaires.
writer.writeheader()
writer.writerows(data)
La méthode writeheader() écrit la ligne d'en-tête et writerows() écrit les lignes de données dans notre fichier CSV.
Enfin, la ligne imprime un message de succès, confirmant que les données ont été écrites avec succès dans le fichier CSV.
Lors de l'extraction des résultats de recherche Yelp, nous ne voulons pas seulement extraire la première page. Il n'y a que 10 résultats par page et Yelp vous montre 24 pages par URL de recherche. Cela signifie que vous pouvez extraire jusqu'à 240 résultats par URL de recherche. Jusqu'à présent, notre code est capable d'extraire uniquement la première page. Améliorons ses capacités et gérons la pagination de Yelp.
Pour ce faire, nous définirons une méthode nommée scrape_results et ajouterons la logique de pagination à celle-ci. Faisons-le.
def scrape_results(self, search_url, max_page):
all_results = []
for page in range(1, max_page):
page_url = search_url + f'&start={(page-1)*10}'
print(f"Extraction Page {page}")
results = self.iter_listings(page_url)
if results:
all_results.extend(results)
time.sleep(2)
return all_results
Décortiquons ce morceau de code pour une meilleure compréhension:
def scrape_results(self, search_url, max_page):
Cette ligne définit une méthode nommée scrape_results dans la classe YelpSearchScraper. Elle prend trois paramètres : self, qui se réfère à l'instance de la classe, search_url, qui représente l'URL pour la recherche Yelp, et max_page, qui spécifie le nombre maximum de pages à extraire.
Ceci initialise une liste vide nommée all_results qui sera utilisée pour stocker les données extraites de chaque page.
for page in range(1, max_page):
Ceci met en place une boucle qui itère sur une plage de numéros de pages, de 1 à max_page. Cette boucle contrôle le processus d'extraction pour chaque page.
page_url = search_url + f'&start={(page-1)*10}'
Ceci construit l'URL de chaque page en ajoutant le paramètre d'index de début approprié à search_url. L'index de départ est calculé comme (page-1)*10, où chaque page affiche 10 résultats.
results = self.iter_listings(page_url)
Ceci appelle la méthode iter_listings pour extraire les annonces de l'URL de page actuelle (page_url). La méthode renvoie une liste de dictionnaires représentant les données extraites pour chaque annonce commerciale sur la page.
if results:
all_results.extend(results)
Cette ligne vérifie si results n'est pas vide. S'il y a des résultats extraits de la page actuelle, ils sont ajoutés à la liste all_results en utilisant la méthode extend(). Cela garantit que toutes les données extraites sont accumulées sur toutes les pages.
Ceci introduit un délai de 2 secondes en utilisant la fonction time.sleep(). Cela aide à éviter de submerger le serveur avec des demandes fréquentes et assure un processus d'extraction plus poli.
Cette ligne renvoie la liste all_results, qui contient les données extraites de toutes les pages extraites.
Notre scraper Yelp est maintenant capable d'aller au-delà de la page 1 pour extraire tous les résultats en extrayant les annonces Yelp à partir d'une URL de recherche.
Finalisation du Yelp Scraper
Dans la dernière partie de notre code, nous avons la fonction main() responsable de l'exécution du Yelp scraper.
def main():
s = time.perf_counter()
argparser = argparse.ArgumentParser()
argparser.add_argument('--search-url', '-u', type=str, required=False, help='URL de recherche Yelp', default='https://www.yelp.com/search?find_desc=Burgers&find_loc=London')
argparser.add_argument('--max-page', '-p', type=int, required=False, help='Page maximum à visiter', default=5)
args = argparser.parse_args()
search_url = args.search_url
max_page = args.max_page
assert all([search_url, max_page])
scraper = YelpSearchScraper()
results = scraper.scrape_results(search_url, max_page)
if results:
scraper.save_to_csv(results, 'yelp_search_results.csv')
else:
print("Aucun résultat à sauvegarder en CSV")
elapsed = time.perf_counter() - s
elapsed_formatted = "{:.2f}".format(elapsed)
print("Temps écoulé :", elapsed_formatted, "secondes")
print('''~~ succès
_ _ _
| | | | | |
| | ___ | |__ ___| |_ __ __
| |/ _ \| '_ \/ __| __/| '__|
| | (_) | |_) \__ \ |_ | |
|_|\___/|_.__/|___/\__||_|
''')
if __name__ == '__main__':
main()
Faisons une rapide décomposition de notre fonction principale :
def main():
s = time.perf_counter()
Définit la fonction main(), qui sert de point d'entrée à notre programme. Au sein de cette fonction, nous initialisons une variable s pour stocker l'heure de début en utilisant time.perf_counter().
argparser = argparse.ArgumentParser()
argparser.add_argument('--search-url', '-u', type=str, required=False, help='URL de recherche Yelp', default='https://www.yelp.com/search?find_desc=Burgers&find_loc=London')
argparser.add_argument('--max-page', '-p', type=int, required=False, help='Page maximum à visiter', default=5)
args = argparser.parse_args()
Ces lignes créent une instance de la classe argparse.ArgumentParser() pour gérer les arguments de la ligne de commande. Nous définissons deux arguments optionnels : --search-url (ou -u) pour spécifier l'URL de recherche Yelp, et --max-page (ou -p) pour définir le nombre maximal de pages à visiter. Les valeurs par défaut sont fournies pour commodité. Grâce à cette partie de notre code, nous n'aurons pas besoin d'ouvrir notre script et de changer l'URL et le nombre maximal de pages à scraper à chaque fois. Nous pouvons le spécifier dans la ligne de commande.
search_url = args.search_url
max_page = args.max_page
Ces lignes extraient les valeurs des arguments de ligne de commande search_url et max_page de l'objet args, en les affectant aux variables respectives.
assert all([search_url, max_page])
Ceci utilise l'instruction assert pour valider que search_url et max_page ont des valeurs non vides. Si l'une des valeurs est manquante, une AssertionError est levée.
scraper = YelpSearchScraper()
results = scraper.scrape_results(search_url, max_page)
Cela crée une instance de la classe YelpSearchScraper nommée scraper. Nous appelons ensuite la méthode scrape_results() de l'objet scraper, en passant search_url et max_page en arguments. La méthode déclenche le processus de scraping et renvoie les résultats extraits.
if results:
scraper.save_to_csv(results, 'yelp_search_results.csv')
else:
print("Aucun résultat à sauvegarder en CSV")
Ce bloc if-else vérifie si la liste results n'est pas vide. S'il y a des résultats extraits, nous appelons la méthode save_to_csv() de l'objet scraper pour sauvegarder les résultats dans un fichier CSV nommé 'yelp_search_results.csv'. S'il n'y a pas de résultats, nous imprimons un message indiquant qu'il n'y a pas de résultats à sauvegarder.
elapsed = time.perf_counter() - s
elapsed_formatted = "{:.2f}".format(elapsed)
print("Temps écoulé :", elapsed_formatted, "secondes")
Ces lignes calculent le temps écoulé en soustrayant l'heure de début (s) de l'heure actuelle en utilisant time.perf_counter(). Le temps écoulé est stocké dans la variable elapsed. Il est ensuite formaté à deux décimales et stocké dans la variable elapsed_formatted. Enfin, nous imprimons le temps écoulé en secondes.
Scraping des annonces de restaurants Yelp à partir d'une URL de recherche
Il est temps de tester notre Yelp scraper. Nous allons scraper Yelp pour recueillir les détails de 30 restaurants chinois situés à Londres. La première étape consiste à obtenir l'URL. Visitez yelp.com, recherchez le mot-clé, et sélectionnez l'emplacement. Tout ce que nous avons à faire maintenant est de copier l'URL de la barre d'adresse.
Lançons notre yelp scraper basé sur python. Allez dans le dossier où vous avez sauvegardé le script python. Appuyez sur shift et faites un clic droit sur une zone vide de votre écran. Dans le menu, sélectionnez "ouvrir la fenêtre Powershell ici".
Dans votre console, tapez la commande suivante :
python {your_script_name.py} -u {url} -p {nombre maximum de pages à scraper}
Remplacez {your_script_name.py} par le nom de votre fichier python, {url} par l'URL Yelp que vous voulez scraper, et {nombre maximum de pages} par le nombre de pages que vous voulez scraper. Dans notre cas, la commande sera :
python yelpscraper.py -u "https://www.yelp.com/search?find_desc=Chinese&find_loc=London" -p 3
Appuyez sur Entrée et laissez la magie opérer.
Et voilà. Nous venons d'extraire 30 annonces de restaurants avec 6 attributs de données de Yelp. Voyons à quoi ressemble le fichier de sortie :
Et voici. 30 restaurants chinois situés à Londres extraits avec le nom, l'URL, la note, les avis, les catégories, et le quartier. Tout cela en seulement 17 secondes.
Limitations
Bien que notre scraper Yelp basé sur Python offre la commodité d'extraire les annonces de restaurants de Yelp, il a quelques limitations qui devraient être considérées. Ces limitations concernent l'étendue de l'extraction des données et l'absence de mesures pour contourner les anti-bots.
Tout d'abord, le scraper est incapable d'extraire les données des pages individuelles d'annonces, ce qui limite la profondeur et l'étendue des informations obtenues. Alors qu'il capture avec succès des attributs essentiels tels que le nom, la note, le quartier, et d'autres détails de base, il manque la capacité de naviguer vers les pages d'annonces individuelles et d'extraire des informations plus complètes comme les coordonnées, les heures d'ouverture, ou les éléments du menu.
De plus, l'absence de mesures anti-bots expose le scraper à la détection par les mécanismes de sécurité de Yelp. Cela peut entraîner une éventuelle interdiction de l'IP, entravant le processus de scraping et empêchant l'accès aux données de Yelp. Sans mesures anti-bots en place, la fiabilité et la scalabilité du scraper peuvent être compromises, posant des limitations pour les opérations de scraping à grande échelle ou l'extraction fréquente de données.
Pour surmonter ces limitations, nous recommandons d'utiliser
Yelp Search Export, une solution
sans code et
basée sur le cloud. Yelp Search Export offre un ensemble élargi de
13 attributs de données, incluant les informations de contact, les heures d'ouverture, les avis, les photos, et plus encore. Il intègre des mesures anti-bots avancées, garantissant un scraping fiable. La solution est conviviale, scalable, et propose une
version gratuite avec des plans premium disponibles pour des fonctionnalités supplémentaires.
Apprenez
comment scraper les annonces d'entreprises Yelp avec tous les attributs de données importants sans écrire une seule ligne de code.
Conclusion
En conclusion, cet article a fourni un point de départ pour scraper les annonces de restaurants de Yelp en utilisant Python et la bibliothèque requests. Nous avons parcouru le code, en expliquant sa fonctionnalité et ses limitations. Si vous êtes curieux du web scraping ou si vous cherchez à apprendre le web scraping avec Python, nous espérons que cet article vous a été utile pour vous initier au processus.
Cependant, si vous recherchez une solution pour le
scraping à grande échelle, l'efficacité, et le gain de temps, nous vous recommandons de considérer notre
Yelp Search Export. Il offre une solution robuste et sans tracas pour extraire les données de Yelp.
Joyeux scraping 🦞