Foursquare détient des données de localisation publiques sur des millions de lieux : restaurants, cafés, parcs, bars et musées, chacun avec un nom, une catégorie, une adresse et une note publique. Pour la recherche sur les commerces locaux, l'analyse de marché ou la construction d'une fonctionnalité de recommandation, ces données publiques de lieux sont réellement utiles. Le hic, c'est que Foursquare rend ses pages avec JavaScript, de sorte qu'une simple requête HTTP renvoie une coquille quasi vide plutôt que la liste de lieux visible dans un navigateur.

Ce guide vous montre comment extraire des données publiques de lieux Foursquare avec Python via la Crawling API, qui rend la page et achemine la requête à travers une IP de confiance en un seul appel. Tout ici reste limité aux données publiques de lieux et d'établissements : noms, catégories, adresses et notes publiques. Cela ne couvre rien derrière une connexion, et cela ne touche pas aux données personnelles des utilisateurs individuels ni à leurs check-ins. Pour un usage en production, l'API officielle Foursquare Places est le bon outil, et la section sur la légalité, vers la fin, explique pourquoi.

Ce que vous allez construire

Un petit scraper Python qui prend une URL de recherche publique Foursquare ou l'URL d'un lieu unique, récupère la page entièrement rendue via la Crawling API, et analyse une poignée de champs publics de lieu :

  • Nom du lieu le nom de l'établissement ou de l'endroit affiché sur la fiche.
  • Catégorie le type de lieu, par exemple thaïlandais, boulangerie ou bar.
  • Adresse l'adresse postale publique du lieu.
  • Note la note publique agrégée que le lieu affiche.
  • Lien le permalien vers la page de détail publique du lieu.

Le script gère plusieurs résultats provenant d'une page de recherche, parcourt chaque fiche et exporte les enregistrements collectés en JSON et CSV pour que les données soient prêtes pour la recherche sur les commerces locaux. Remarquez ce qui est délibérément absent : aucun profil d'utilisateur individuel, aucun historique de check-ins, aucune donnée personnelle liée à une personne nommée. Ces éléments sont volontairement hors de portée ici.

Pourquoi une simple requête échoue sur Foursquare

Demandez une page de recherche Foursquare avec un client HTTP nu et vous obtenez une réponse techniquement réussie et pratiquement inutile. Le contenu des lieux se charge dynamiquement : les vraies fiches n'apparaissent qu'après l'exécution des scripts de la page dans un navigateur et la récupération des données depuis des points de terminaison internes. Une requête brute capture la page avant que tout cela ne se produise, donc il n'y a rien à analyser.

Au-delà du rendu, Foursquare surveille le trafic automatisé. Les plages d'IP de datacenter et les schémas de requêtes répétitifs sont mis au défi ou limités en débit avant que le contenu intéressant ne se charge. Un scraper fonctionnel a donc besoin de deux choses dans la même requête : un vrai navigateur qui rend la page, et une adresse IP que la plateforme interprète comme un visiteur ordinaire. Vous pouvez construire cela avec un navigateur sans interface et un pool de proxys résidentiels, mais maintenir cette pile en bonne santé représente l'essentiel du travail. La Crawling API regroupe les deux en un seul appel. Vous lui envoyez une URL, elle rend la page derrière une IP résidentielle de confiance, et elle vous renvoie un HTML fini que vous pouvez analyser. Pour le contexte plus approfondi, voyez notre guide sur comment explorer les sites web JavaScript.

Pourquoi le token JS

Crawlbase propose deux types de tokens. Le token normal récupère le HTML statique ; le token JavaScript (JS) rend d'abord la page dans un vrai navigateur. Foursquare effectue son rendu côté client, vous avez donc besoin du token JS ici. Le token normal renverrait la même coquille qu'une simple récupération, sans rien d'utile à en extraire.

Prérequis

Quelques éléments à mettre en place d'abord. Aucun ne prend longtemps.

Python de base. Vous devez être à l'aise pour exécuter un script et installer des paquets avec pip. Si vous débutez dans l'analyse du HTML, notre introduction sur comment utiliser BeautifulSoup en Python couvre le volet extraction.

Python 3.8 ou ultérieur. Confirmez avec python --version. Si vous ne l'avez pas, installez-le depuis python.org.

Un compte Crawlbase et un token JS. Inscrivez-vous, ouvrez votre tableau de bord et copiez votre token JavaScript (JS). Crawlbase vous offre jusqu'à 20 000 requêtes gratuites pour démarrer, et vous ne payez que pour les requêtes réussies. Traitez le token comme un mot de passe : il authentifie vos requêtes, donc gardez-le hors du contrôle de version.

Configurer le projet

Créez un environnement virtuel isolé, puis installez les deux bibliothèques dont le scraper a besoin.

bash
python --version

python -m venv foursquare_env
source foursquare_env/bin/activate

pip install crawlbase beautifulsoup4

Sous Windows, activez avec foursquare_env\Scripts\activate au lieu de la ligne source. Deux dépendances font le travail : crawlbase est le client officiel de la Crawling API, et beautifulsoup4 analyse le HTML renvoyé pour que vous puissiez extraire les champs individuels par sélecteur.

Étape 1 : Récupérer la page de recherche rendue

Commencez par obtenir la page finie. Importez CrawlingAPI, initialisez-la avec votre token JS et demandez une URL de recherche publique. Comme Foursquare charge les fiches de façon asynchrone, passez les options ajax_wait et page_wait pour que l'API patiente jusqu'à ce que le contenu soit rendu. Vérifiez le statut avant l'analyse pour que les échecs restent bruyants plutôt que silencieux.

python
from crawlbase import CrawlingAPI

crawling_api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"})

def make_crawlbase_request(url):
    options = {
        "ajax_wait": "true",
        "page_wait": "5000",
    }
    response = crawling_api.get(url, options)

    if response["headers"]["cb_status"] == "200":
        return response["body"].decode("utf-8")
    print(f"Failed to fetch the page. Crawlbase status: {response['headers']['cb_status']}")
    return None

if __name__ == "__main__":
    url = "https://foursquare.com/explore?near=New%20York&q=Food"
    html = make_crawlbase_request(url)
    print(html[:500] if html else "No HTML returned")

Les deux options d'attente comptent pour une cible rendue côté client. ajax_wait indique à l'API d'attendre la fin du chargement du contenu asynchrone, et page_wait patiente un nombre fixe de millisecondes après le chargement pour que les fiches au rendu tardif apparaissent avant la capture de la page. Cinq secondes constituent un point de départ raisonnable ; augmentez la valeur si les fiches reviennent vides. La vérification de statut lit cb_status (legacy pc_status) dans les en-têtes de réponse, qui est le statut Crawlbase du crawl lui-même. Exécutez le script et vous devriez voir un véritable balisage de lieux, ce qui confirme que le rendu fonctionne avant d'écrire le moindre sélecteur.

Crawlbase Crawling API

Foursquare a besoin d'une page rendue derrière une IP de confiance, en un seul appel. La Crawling API prend un token JS, exécute la page dans un vrai navigateur pour que ces fiches ajax_wait se chargent réellement, fait tourner des IP résidentielles côté serveur et vous remet un HTML fini, pour que vous évitiez de gérer vous-même une flotte sans interface et un pool de proxys. Pointez-la d'abord sur une page de recherche publique avec l'offre gratuite.

Étape 2 : Inspecter le balisage et analyser les fiches

Avant d'écrire des sélecteurs, ouvrez une page de résultats de recherche Foursquare dans votre navigateur, faites un clic droit sur une fiche et choisissez Inspecter. Vous cherchez les éléments qui enveloppent chaque lieu et contiennent les champs que vous voulez. Sur la page de résultats de recherche, chaque endroit se trouve à l'intérieur d'un élément de liste, et les champs publics correspondent à ces sélecteurs :

  • Nom du lieu se trouve dans une balise <a> à l'intérieur d'un div.venueName.
  • Adresse se trouve dans un div.venueAddress.
  • Catégorie se trouve dans un span.categoryName.
  • Lien est le href de cette même ancre div.venueName a.

Avec le HTML rendu en main, chargez-le dans BeautifulSoup et parcourez chaque fiche. Chaque ligne de résultat correspond à ul.recommendationList > li.singleRecommendation. Protéger chaque champ par une vérification d'existence évite que l'analyseur ne plante lorsqu'un lieu en manque un.

python
from bs4 import BeautifulSoup

def scrape_foursquare_listings(html):
    soup = BeautifulSoup(html, "html.parser")
    venues = []

    listings = soup.select("ul.recommendationList > li.singleRecommendation")
    for listing in listings:
        name_el = listing.select_one("div.venueName a")
        address_el = listing.select_one("div.venueAddress")
        category_el = listing.select_one("span.categoryName")
        rating_el = listing.select_one("span.venueScore")

        href = name_el["href"] if name_el and name_el.has_attr("href") else ""

        venues.append({
            "name": name_el.text.strip() if name_el else "",
            "category": category_el.text.strip() if category_el else "",
            "address": address_el.text.strip() if address_el else "",
            "rating": rating_el.text.strip() if rating_el else "",
            "link": f"https://foursquare.com{href}" if href else "",
        })

    return venues

La fonction renvoie une liste de dictionnaires, un par lieu, avec les cinq champs publics. Le lien est construit en joignant le href relatif à l'origine https://foursquare.com pour que chaque enregistrement porte un permalien utilisable. La note est lue depuis span.venueScore ; si Foursquare a renommé cette classe sur la page que vous inspectez, remplacez-la par la classe qui enveloppe la note visible. Traitez la note comme un agrégat public, et non comme un signal sur un évaluateur individuel.

Les sélecteurs dérivent

Foursquare change son balisage et ses noms de classe sans préavis. Lorsqu'un champ revient vide, réinspectez la page en direct dans les outils de développement de votre navigateur et mettez à jour le sélecteur. Une maintenance périodique est normale pour tout scraper en production, ce n'est pas le signe que quelque chose est cassé. L'extraction protégée ci-dessus fait qu'une classe renommée produit une chaîne vide plutôt qu'un plantage.

Étape 3 : Gérer plusieurs pages de résultats

Les résultats de recherche Foursquare utilisent une pagination par bouton : un bouton "See more results" charge le lot suivant de lieux sur place plutôt que de naviguer vers une nouvelle URL. La Crawling API peut cliquer ce bouton pour vous grâce à l'option css_click_selector, de sorte que le HTML rendu que vous recevez contient déjà la liste étendue. Pointez le sélecteur sur le bouton responsable du chargement de plus de résultats.

python
def make_request_with_pagination(url):
    options = {
        "ajax_wait": "true",
        "page_wait": "5000",
        "css_click_selector": "li.moreResults > button",
    }
    response = crawling_api.get(url, options)

    if response["headers"]["cb_status"] == "200":
        return response["body"].decode("utf-8")
    print(f"Failed to fetch the page. Crawlbase status: {response['headers']['cb_status']}")
    return None

La valeur de css_click_selector cible le bouton à l'intérieur de li.moreResults. Si la classe du bouton diffère sur la page que vous inspectez, mettez à jour le sélecteur pour qu'il corresponde. Gardez un volume modeste : la recherche sur données publiques n'exige pas de charger les fiches d'une ville entière en une seule exécution. Échantillonnez ce dont vous avez besoin, puis arrêtez.

Étape 4 : Assembler le scraper complet et exporter

Maintenant, câblez la récupération, l'analyse et l'export dans un seul script exécutable. Le script récupère une page de recherche avec pagination, analyse chaque fiche et écrit les enregistrements à la fois en JSON et en CSV. Le JSON conserve la structure intacte pour un traitement ultérieur ; le CSV tombe directement dans un tableur pour une recherche rapide sur les commerces locaux.

python
import json
import csv
from crawlbase import CrawlingAPI
from bs4 import BeautifulSoup

crawling_api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"})

def make_request_with_pagination(url):
    options = {
        "ajax_wait": "true",
        "page_wait": "5000",
        "css_click_selector": "li.moreResults > button",
    }
    response = crawling_api.get(url, options)
    if response["headers"]["cb_status"] == "200":
        return response["body"].decode("utf-8")
    print(f"Failed to fetch the page. Crawlbase status: {response['headers']['cb_status']}")
    return None

def scrape_foursquare_listings(html):
    soup = BeautifulSoup(html, "html.parser")
    venues = []
    listings = soup.select("ul.recommendationList > li.singleRecommendation")
    for listing in listings:
        name_el = listing.select_one("div.venueName a")
        address_el = listing.select_one("div.venueAddress")
        category_el = listing.select_one("span.categoryName")
        rating_el = listing.select_one("span.venueScore")
        href = name_el["href"] if name_el and name_el.has_attr("href") else ""
        venues.append({
            "name": name_el.text.strip() if name_el else "",
            "category": category_el.text.strip() if category_el else "",
            "address": address_el.text.strip() if address_el else "",
            "rating": rating_el.text.strip() if rating_el else "",
            "link": f"https://foursquare.com{href}" if href else "",
        })
    return venues

def save_to_json(data, filename="foursquare_data.json"):
    with open(filename, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=4, ensure_ascii=False)
    print(f"Saved {len(data)} venues to {filename}")

def save_to_csv(data, filename="foursquare_data.csv"):
    if not data:
        return
    fields = ["name", "category", "address", "rating", "link"]
    with open(filename, "w", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=fields)
        writer.writeheader()
        writer.writerows(data)
    print(f"Saved {len(data)} venues to {filename}")

if __name__ == "__main__":
    url = "https://foursquare.com/explore?near=New%20York&q=Food"
    html = make_request_with_pagination(url)
    if html:
        venues = scrape_foursquare_listings(html)
        save_to_json(venues)
        save_to_csv(venues)

Voici tout le pipeline dans un seul fichier : récupération avec pagination, analyse des fiches et export dans les deux formats. L'écrivain CSV fige l'ordre des colonnes sur les cinq champs publics pour que la sortie soit stable d'une exécution à l'autre. Remplacez le url par n'importe quelle recherche publique Foursquare pour reciblez le scraper sur une autre ville ou catégorie.

À quoi ressemble la sortie

Exécutez le script complet et vous obtenez une liste propre d'enregistrements publics de lieux. Voici un échantillon JSON allégé de ce que contient foursquare_data.json.

json
[
    {
        "name": "Thai Diner",
        "category": "Thai",
        "address": "186 Mott St (at Kenmare), New York",
        "rating": "9.5",
        "link": "https://foursquare.com/v/thai-diner/5e46e2ec5791a10008c55728"
    },
    {
        "name": "Mah-Ze-Dahr Bakery",
        "category": "Bakery",
        "address": "28 Greenwich Ave (Charles Street), New York",
        "rating": "9.1",
        "link": "https://foursquare.com/v/mahzedahr-bakery/568c0ce238fafac5f5ffe631"
    }
]

La version CSV porte les mêmes champs sous forme d'une ligne par lieu avec une ligne d'en-tête, qui s'ouvre directement dans n'importe quel tableur. À partir de là, vous pouvez filtrer par catégorie, regrouper par quartier ou joindre les adresses à un autre jeu de données pour la recherche sur les commerces locaux. Si les signaux de prix font partie de votre analyse, notre guide sur le web scraping pour l'intelligence des prix couvre comment des données publiques agrégées alimentent ce genre de travail.

Passer à l'échelle des pages de détail de lieu

Le scraper de recherche vous donne une liste et un lien par lieu. Pour enrichir chaque enregistrement, renvoyez le champ link dans la même fonction de récupération et analysez la page propre du lieu, où Foursquare expose plus de détails publics structurés. Sur une page de lieu, les champs publics correspondent à ces sélecteurs : le nom se trouve dans un h1.venueName, l'adresse dans un div.venueAddress, la note dans un span[itemprop="ratingValue"], et le nombre public d'avis dans un div.numRatings. Réutilisez le motif d'extraction protégée de l'étape 2, espacez vos requêtes entre les récupérations de pages de détail, et gardez l'exécution limitée aux lieux dont vous avez réellement besoin plutôt que d'explorer tout ce qu'une recherche renvoie.

Foursquare est un point d'entrée utile, mais les données de lieux et de commerces locaux vivent sur de nombreuses surfaces. Pour des techniques voisines, voyez nos guides sur comment extraire des données de Google Maps et sur l'extraction des fiches de commerces locaux, qui appliquent tous deux la même approche rendu-plus-IP-de-confiance à d'autres sources de cartes et d'annuaires.

Rester débloqué

Même avec le rendu pris en charge par la Crawling API, Foursquare surveille le trafic en forme de scraper. Quelques habitudes maintiennent une exécution saine, et elles s'appliquent à toute cible défendue.

  • Espacez vos requêtes. Marteler les pages dans une boucle serrée est le moyen le plus rapide de se faire limiter. Ajoutez de vrais délais entre les récupérations et résistez à l'envie de paralléliser agressivement.
  • Appuyez-vous sur la rotation. Un pool d'IP résidentielles répartit les requêtes sur de nombreuses adresses de vrais utilisateurs pour qu'aucune seule ne déclenche une limite de débit. La Crawling API s'en charge pour vous ; si vous construisez votre propre pile, c'est la partie à réussir.
  • Lisez les codes de statut. Une exécution qui se met à renvoyer des défis ou des erreurs vous indique que le débit actuel ou le palier d'IP ne suffit plus. Levez le pied plutôt que de pousser plus fort.
  • Gardez un volume faible et des cibles variées. La recherche sur données publiques n'exige pas d'explorer une ville entière. Échantillonnez ce dont vous avez besoin et arrêtez.

Pour le manuel plus large, voyez notre guide sur comment scraper des sites web sans se faire bloquer.

Est-il légal de scraper Foursquare ?

C'est la section à lire avant d'écrire du code de production. Le scraping de données publiques de lieux se situe dans une zone grise qui dépend fortement de la façon dont vous procédez et de ce que vous collectez. Les Conditions d'utilisation de Foursquare restreignent l'accès automatisé, alors lisez-les en même temps que le robots.txt du site, et traitez les deux comme la limite de ce que vous collectez et de la vitesse à laquelle vous le collectez. Le code ci-dessus fait fonctionner la partie technique ; il ne change pas ce que les conditions permettent.

Tenez-vous-en aux données publiques et non personnelles de lieux. Les noms de lieux, les catégories, les adresses publiques et les notes agrégées décrivent des endroits, pas des personnes, et c'est la voie sûre pour ce genre de recherche. Ce à quoi vous ne devez pas toucher : tout ce qui se trouve derrière une connexion, les profils d'utilisateurs individuels, les historiques de check-ins, ou toute donnée personnelle concernant des utilisateurs identifiables. La note agrégée d'un lieu est un nombre public sur un endroit ; les personnes qui ont laissé des avis ou se sont enregistrées ne sont pas à vous de récolter. Dès qu'une donnée personnelle est en jeu, des lois sur la vie privée comme le RGPD et le CCPA s'appliquent, ce qui signifie que vous avez besoin d'une base légale pour la traiter et que vous devez honorer les demandes de suppression. Le moyen le plus simple d'éviter ce fardeau est de ne pas collecter de données personnelles dès le départ, ce qui est exactement ce que fait ce guide.

Pour tout usage réel, continu ou commercial, le bon outil est l'API officielle Foursquare Places. C'est la voie sanctionnée, elle vous donne des données structurées de lieux et de catégories avec une licence d'utilisation claire, et elle vous maintient dans les conditions de Foursquare. Cet article est un tutoriel technique restreint étroitement aux données publiques de lieux, et non une approbation de la collecte à grande échelle ni d'un quelconque traitement de données personnelles d'utilisateurs. Si votre projet a besoin de plus qu'un échantillon de champs publics de lieux, l'API Places ou un accord de données formel est le bon chemin, pas un scraper plus astucieux.

Récapitulatif

Points clés

  • Foursquare effectue son rendu côté client. Une simple requête renvoie une coquille vide, vous devez donc rendre la page avant de l'analyser, ce dont le token JS de la Crawling API se charge.
  • Portez les vrais sélecteurs. Les fiches vivent dans li.singleRecommendation, avec nom, catégorie, adresse et lien dans venueName, categoryName et venueAddress.
  • Gérez la pagination côté serveur. L'option css_click_selector clique le bouton "See more results" pour que le HTML rendu contienne déjà la liste étendue.
  • Exportez pour la recherche. Écrivez les enregistrements de lieux en JSON pour la structure et en CSV pour les tableurs, puis filtrez-les ou joignez-les pour l'analyse des commerces locaux.
  • Lieux publics uniquement, préférez l'API officielle. Collectez des données de lieux, jamais de données personnelles d'utilisateurs ni de check-ins, et utilisez l'API Foursquare Places pour tout usage réel ou commercial.

Foire aux questions

Pourquoi une simple requête ne renvoie-t-elle aucune donnée de Foursquare ?

Parce que Foursquare charge ses fiches de lieux côté client avec JavaScript. Le HTML initial est une coquille qui ne se remplit qu'après l'exécution des scripts de la page dans un navigateur, de sorte qu'une requête HTTP brute renvoie un corps quasi vide. Pour obtenir de vraies données de lieux, vous devez d'abord rendre la page, ce dont le token JS de la Crawling API se charge pour vous.

Ai-je besoin du token normal ou du token JS pour Foursquare ?

Le token JS. Le token normal récupère le HTML statique, qui sur Foursquare est la même coquille vide qu'une simple requête renvoie. Le token JS rend la page dans un vrai navigateur avant de renvoyer le HTML, de sorte que les champs de lieu sont présents lorsque BeautifulSoup les analyse.

Quelles données Foursquare peut-on scraper sans risque ?

Les données publiques et non personnelles de lieux : noms de lieux, catégories, adresses publiques, notes agrégées et liens publics vers les pages de lieux. Tout ce qui se trouve derrière une connexion, les profils d'utilisateurs individuels et les historiques de check-ins sont interdits. Ce sont des données personnelles, et les collecter va à l'encontre des conditions de Foursquare et, dans de nombreux endroits, du droit de la vie privée.

Comment gérer la pagination en scrapant Foursquare ?

La recherche Foursquare utilise un bouton "See more results" plutôt que des URL séparées. Passez à la Crawling API l'option css_click_selector pointée sur ce bouton (par exemple li.moreResults > button), et l'API le clique pendant le rendu pour que le HTML que vous recevez contienne déjà la liste étendue de lieux.

Dois-je utiliser l'API officielle Foursquare Places ou scraper le site ?

Pour tout usage réel, continu ou commercial, utilisez l'API officielle Foursquare Places. C'est la voie sanctionnée, elle donne des données structurées de lieux et de catégories avec une licence claire, et elle vous maintient dans les conditions de Foursquare. Scraper un petit échantillon de champs publics de lieux avec l'approche présentée ici convient à une recherche légère où aucun accès API n'est en place, tant que vous respectez les conditions, le robots.txt et les limites de débit.

Comment éviter de me faire bloquer en scrapant Foursquare ?

Gardez un débit de requêtes par IP faible, ajoutez de vrais délais entre les requêtes, variez vos cibles au lieu d'explorer une ville entière, et acheminez via des IP résidentielles rotatives pour qu'aucune seule adresse ne déclenche une limite de débit. La Crawling API gère la rotation et un pool d'IP de confiance pour vous. Surveillez les codes de statut et levez le pied dès que vous commencez à voir des défis.

Commencer à construire

Crawlez n'importe quel site à grande échelle, sans combattre l'infrastructure.

Crawlbase gère les proxies, les empreintes et les CAPTCHA afin que votre équipe livre des pipelines de données au lieu de maintenir la plomberie de crawl. 1 000 requêtes gratuites, sans carte requise.

En libre-service · Sans appel commercial requis · Volumes de crawl entreprise disponibles