Scraper proprement
Ce qu'il faut vérifier avant d'écrire la première ligne d'un collecteur de données, puis comment le faire sans se faire bloquer.
Récupérer des données sur un site public est facile techniquement, et c'est exactement le piège. Vingt lignes de Python suffisent à aspirer un catalogue. Les ennuis, eux, arrivent trois semaines plus tard : une adresse IP bloquée, un courrier d'avocat, ou pire, un fichier de données personnelles dont tu ne sais plus quoi faire.
L'ordre de ce guide est volontaire. La partie juridique et l'étiquette d'abord, la technique ensuite. Un script propre qui collecte des données qu'on n'avait pas le droit de collecter reste un problème.
Quatre questions avant la première requête
Que disent les conditions d'utilisation ? Beaucoup de sites interdisent explicitement l'extraction automatisée dans leurs CGU. « Publiquement accessible » ne veut pas dire « libre de réutilisation ». Lis la page, elle fait rarement plus de deux écrans.
Y a-t-il une base de données protégée ? En droit français, l'article L342-1 du code de la propriété intellectuelle permet au producteur d'une base de données d'interdire l'extraction d'une partie substantielle de son contenu, appréciée qualitativement ou quantitativement. Aspirer les dix mille annonces d'un site, c'est typiquement ce que vise ce texte.
Y a-t-il des données personnelles ? Un nom, un e-mail, un pseudonyme rattachable à quelqu'un, une photo de profil : le RGPD s'applique même quand la donnée est publiquement affichée. Il te faut alors une base légale, et tu dois informer les personnes concernées.
Est-ce que ta collecte dégrade le service ? Une centaine de requêtes par seconde sur un petit site, c'est une panne pour tout le monde. C'est le point qui transforme un désaccord en plainte.
Ce guide n'est pas un conseil juridique
Il donne des repères pour savoir quand s'arrêter et poser la question. Pour un projet à enjeu, la réponse vient d'un juriste, pas d'un article de blog. Pour la partie données personnelles, la CNIL publie des fiches pratiques.
robots.txt : ce que le fichier dit, et ce qu'il ne dit pas
Le protocole d'exclusion des robots est normalisé depuis septembre 2022 par la
RFC 9309. Elle définit trois directives : user-agent, allow et disallow.
Sitemap est une extension optionnelle très répandue. Crawl-delay, en
revanche, ne fait pas partie du standard, et Google indique explicitement ne pas
le prendre en charge. Certains robots l'honorent, beaucoup l'ignorent.
Le fichier doit se trouver à /robots.txt à la racine du service, en
minuscules, et ne vaut que pour ce couple protocole plus hôte plus port. La RFC
recommande de ne pas garder une version en cache plus de 24 heures.
Un point de méthode : robots.txt est un signal d'intention, pas une barrière
juridique. Le respecter ne t'autorise pas à tout, et il n'existe pas de
« Allow » qui annulerait les CGU.
Avant de commencer
- Python 3 et
pip install requests - L'URL du site, et cinq minutes pour lire ses CGU
- Une idée précise des champs dont tu as besoin
1Faire lire robots.txt par ton code
La bibliothèque standard sait le faire, inutile d'installer quoi que ce soit :
import urllib.robotparser
AGENT = "VeilleInterne/1.0 (+https://monsite.fr/robot)"
rp = urllib.robotparser.RobotFileParser()
rp.set_url("https://exemple.fr/robots.txt")
rp.read()
if not rp.can_fetch(AGENT, "https://exemple.fr/annonces?page=2"):
raise SystemExit("Chemin interdit par robots.txt")
print(rp.crawl_delay(AGENT)) # None si le site n'en declare pas
print(rp.site_maps()) # None si aucun Sitemap n'est declare
crawl_delay() et site_maps() renvoient None quand la directive est absente
ou invalide. Ne pars pas du principe qu'un site en déclare une.
2T'identifier et tenir une cadence
Un User-Agent qui dit qui tu es et comment te joindre change tout : au lieu de
te bloquer, l'équipe en face t'écrit. Et une requête toutes les deux secondes
suffit dans l'immense majorité des cas.
import time
import requests
HEADERS = {"User-Agent": "VeilleInterne/1.0 (+https://monsite.fr/robot)"}
for url in urls:
r = requests.get(url, headers=HEADERS, timeout=20)
if r.status_code == 429:
# Retry-After contient soit un nombre de secondes, soit une date HTTP
attente = r.headers.get("Retry-After", "60")
time.sleep(int(attente) if attente.isdigit() else 300)
continue
traiter(r.text)
time.sleep(2)
Un code 429 signifie « tu vas trop vite ». Le bon réflexe est de ralentir, pas de changer d'adresse IP.
3Chercher la porte avant la fenêtre
Le HTML est le dernier recours, pas le premier. Dans l'ordre : une API publique
documentée, un export ou un jeu de données ouvert, un flux RSS, le sitemap.xml
pour connaître les URL sans parcourir tout le site. Chacune de ces options est
plus stable, plus légère pour le serveur d'en face, et beaucoup moins
susceptible d'être interdite.
Beaucoup de sites qui refusent le scraping proposent une API sous condition d'inscription. Une demande par e-mail coûte dix minutes.
4Écarter les données personnelles dès la collecte
La règle simple : si tu n'as pas besoin d'un champ, ne l'enregistre pas. Filtre à l'écriture, pas au moment de l'analyse. Une base « au cas où » qui contient des noms et des e-mails est une base que tu dois déclarer, sécuriser, et purger.
Si les données personnelles sont indispensables au projet, la collecte indirecte déclenche l'obligation d'informer les personnes concernées, sauf exceptions. C'est le moment de vérifier auprès de la CNIL avant d'écrire le script.
Ce qu'il ne faut pas faire
- Contourner une authentification, un paywall ou un captcha. On sort de la zone grise.
- Faire tourner le script depuis plusieurs IP pour échapper à une limitation. C'est l'aveu que la limitation était voulue.
- Se faire passer pour un navigateur ou pour Googlebot dans le
User-Agent. - Republier telle quelle une base extraite d'un autre site.
- Relancer une collecte complète chaque nuit alors qu'un delta suffit.
Le test des trois questions
Est-ce que j'accepterais qu'on fasse ça sur mon site ? Est-ce que je peux expliquer ma collecte à l'équipe d'en face sans gêne ? Est-ce que je saurais supprimer ces données si on me le demandait ? Trois oui, tu peux lancer.
Quelques prompts pour aller plus loin
| Objectif | Prompt à adapter |
|---|---|
| Cadrer avant de coder | Voici les CGU de [SITE] et son robots.txt. Liste ce qui est explicitement interdit, ce qui est autorise, et ce qui n'est pas tranche. Ne conclus pas a ma place. |
| Repérer une source officielle | Cherche si [SITE] expose une API publique, un export de donnees, un flux RSS ou un sitemap. Donne les URL et ce que chacune contient. |
| Écrire l'extracteur | Voici un extrait du HTML de [SITE]. Ecris une fonction qui extrait uniquement [CHAMPS]. Ignore tout le reste. Si un champ est absent, renvoie None au lieu de deviner. |
| Auditer son propre script | Relis ce script de collecte. Signale : absence de User-Agent identifiable, absence de pause entre requetes, gestion manquante du code 429, et tout champ collecte qui ressemble a une donnee personnelle. |
| Nettoyer une base existante | Voici le schema de la table collectee. Liste les colonnes qui contiennent ou pourraient contenir des donnees personnelles, et propose lesquelles supprimer. |
Tu as d’autres ressources comme ça ?
Ce que tu viens de lire est entièrement gratuit. Une nouvelle ressource part chaque semaine dans la newsletter : guides, modèles à copier et liens triés, sans compte à créer.
Me contacter
Une question, un projet, une envie de collaborer ? Écris-moi.
Cette page est en accès libre, n’hésite pas à la partager.