Persistance de Session en Web Scraping : Reutiliser les Cookies pour Scraper plus Vite
Si ton scraper demarre un navigateur headless pour chaque page, tu paies le chemin le plus lent possible a chaque requete. Lancer un vrai navigateur coute de quelques centaines de millisecondes a plusieurs secondes, consomme de la memoire et refait encore et encore le meme travail de connexion et de resolution de defis.
Il existe un meilleur schema : chauffe une session une seule fois dans un navigateur, capture les cookies et confie-les a un client HTTP rapide pour le gros de tes requetes. C’est la persistance de session, et c’est l’une des optimisations a plus fort effet de levier que tu puisses appliquer a un pipeline de scraping. Bien faite, elle divise ton cout par requete par un ordre de grandeur et rend ton trafic plus coherent, pas moins.
Ce guide explique ce qu’est vraiment une session, comment en deplacer une d’un navigateur vers un client HTTP ordinaire, pourquoi les cookies a courte duree de vie comme __cf_bm t’obligent a rafraichir, et comment garder le tout stable en production.
Ce qu’est Vraiment une “Session”
Quand on dit “rester connecte” ou “maintenir la session en vie”, on parle en general des cookies. Mais une session, c’est plus qu’un jeton de connexion. Sur un site moderne protege par une couche anti-bot, une session qui fonctionne est un ensemble d’elements qui doivent rester coherents :
- Cookies d’authentification. Le jeton qui prouve que tu es connecte (souvent quelque chose comme
access_token,session_idou un JWT signe dans un cookie). - Jetons CSRF. Parfois dans un cookie, parfois dans un en-tete ou un champ de formulaire cache.
- Cookies de gestion des bots. Ceux-la, on les oublie. Cloudflare pose
__cf_bm(un cookie de gestion des bots a courte duree de vie, valable en general une trentaine de minutes) et, apres un defi,cf_clearance. D’autres fournisseurs ont leurs propres equivalents. - Une identite client coherente. Le meme
User-Agent, le meme large jeu d’en-tetes, idealement la meme adresse IP et une empreinte TLS correspondant a un vrai navigateur.
Le piege est de traiter une session comme “juste le cookie de connexion”. Tu copies le cookie d’authentification dans requests, ca marche quelques minutes, puis tout se met a renvoyer des 403 ou a rediriger vers une page de defi. C’est presque toujours un cookie de gestion des bots qui expire, ou une empreinte TLS qui ne correspond pas, pas ta connexion qui meurt.
Le Schema Hybride : Chauffer dans un Navigateur, Executer dans un Client HTTP
L’idee centrale est une division du travail :
- Utilise un vrai navigateur (ou headless) pour etablir la session. Le navigateur gere les defis JavaScript, le flux de connexion et toute generation de jeton cote client. C’est la partie couteuse, que tu fais rarement.
- Exporte les cookies. Recupere tous les cookies que le navigateur a collectes, pas seulement celui de connexion.
- Rejoue avec un client HTTP rapide. Pour les vraies pages de donnees, utilise un client leger qui reutilise ces cookies. Pas de navigateur, pas de moteur JavaScript, juste du HTTP.
Le hic, c’est le fingerprinting. Une requete requests classique a une signature TLS Python que les systemes anti-bot reperent instantanement, donc les cookies que tu as eu tant de mal a generer finissent rejetes. La solution est d’utiliser un client HTTP qui imite l’empreinte TLS et HTTP/2 d’un navigateur. En Python, curl_cffi fait exactement cela.
Etape 1 : Chauffer la Session dans Playwright
from playwright.sync_api import sync_playwright
def warm_session(url: str) -> dict:
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
context = browser.new_context()
page = context.new_page()
# Charge le site pour qu'il execute son JS et pose ses cookies.
page.goto(url, wait_until="networkidle")
# S'il y a une connexion, fais-la ici pour que les cookies d'auth soient poses.
# page.fill("#email", "..."); page.fill("#password", "...")
# page.click("button[type=submit]"); page.wait_for_load_state("networkidle")
cookies = context.cookies()
user_agent = page.evaluate("() => navigator.userAgent")
browser.close()
# Aplati en un dict nom -> valeur pour le client HTTP.
jar = {c["name"]: c["value"] for c in cookies}
return {"cookies": jar, "user_agent": user_agent}
Remarque que tu captures aussi le User-Agent. Le client HTTP doit envoyer le meme, sinon la session paraitra incoherente.
Etape 2 : Rejouer avec curl_cffi
from curl_cffi import requests as cffi
def fetch_with_session(url: str, session: dict) -> str:
resp = cffi.get(
url,
cookies=session["cookies"],
headers={"User-Agent": session["user_agent"]},
impersonate="chrome", # imite l'empreinte TLS/HTTP2 d'un vrai Chrome
timeout=30,
)
resp.raise_for_status()
return resp.text
Tu peux maintenant lancer des centaines de ces appels par session chauffee. Chacun est une requete HTTP normale qui porte une empreinte de niveau navigateur et un pot de cookies complet. Aucun surcout de navigateur par page.
Pourquoi il Faut Rafraichir : le Probleme des Cookies a Courte Duree de Vie
C’est ici que la plupart des implementations naives s’effondrent. Certains cookies sont durables (un jeton de connexion peut durer des jours), mais les cookies de gestion des bots sont deliberement a courte duree de vie. Le __cf_bm de Cloudflare en est l’exemple classique : il est concu pour expirer en une trentaine de minutes afin qu’une session capturee ne puisse pas etre rejouee indefiniment.
Une session n’est donc pas une capture unique. C’est une chose vivante que tu dois recompleter. Les cookies durables (ta connexion) restent valides ; les cookies a courte duree de vie doivent etre reforges. Le modele propre est le suivant :
- Conserve les cookies durables (auth) dans un stockage a long terme.
- Rouvre periodiquement un navigateur avec ces cookies durables deja injectes, laisse le site te remettre des cookies frais a courte duree de vie, et renvoie le pot mis a jour a ton client rapide.
Injecter les cookies durables dans un contexte de navigateur neuf avant de naviguer signifie que tu sautes la connexion complete a chaque fois. Tu ne paies que l’etape bon marche “recharger et collecter des jetons frais”.
def refresh_session(url: str, durable_cookies: list[dict]) -> dict:
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
context = browser.new_context()
context.add_cookies(durable_cookies) # injecte les cookies d'auth a longue duree de vie
page = context.new_page()
page.goto(url, wait_until="networkidle") # le site forge des cookies frais a courte duree de vie
cookies = context.cookies()
browser.close()
return {c["name"]: c["value"] for c in cookies}
Execute ceci avec un minuteur confortablement plus court que la duree de vie du cookie le plus court. Si __cf_bm dure une trentaine de minutes, rafraichir toutes les 10 a 15 minutes te maintient en securite dans la fenetre.
Detecter une Session Perimee
Ne te fie pas qu’a l’horloge. Les sites changent les TTL, et une session peut mourir plus tot. Ajoute une verification de sante bon marche pour que ton client sache quand declencher un rafraichissement au lieu de scraper des dechets en silence.
Signaux qu’une session a expire :
- Un
403ou429la ou tu obtenais auparavant un200. - Une redirection vers
/login,/challengeou une page intermediaire Cloudflare. - Une reponse
200dont le corps est la page de defi, pas tes donnees (un blocage silencieux en HTTP 200). - Ton selecteur CSS ou ta cle JSON attendue disparait soudainement.
def looks_blocked(resp) -> bool:
if resp.status_code in (401, 403, 429):
return True
body = resp.text.lower()
markers = ["just a moment", "verify you are human", "cf-challenge", "enable javascript"]
return any(m in body for m in markers)
Quand looks_blocked se declenche, remets l’URL dans la file, declenche un rafraichissement et reessaie. Traite une seule detection de peremption comme un declencheur, pas comme un echec.
Les Details de Production qui Comptent Vraiment
Quelques elements separent une demo d’un pipeline qui tourne pendant des semaines :
- Garde l’IP coherente avec celle ou les cookies ont ete forges. Les systemes anti-bot lient les sessions de facon lache au reseau ou elles ont ete creees. Si tu chauffes une session sur une IP et la rejoues depuis une autre tres differente, tu provoques un defi. La ou tu utilises des proxys, garde une session epinglee a une sortie stable pour toute sa duree de vie.
- Fais correspondre tout le profil d’en-tetes, pas seulement le User-Agent. L’ordre des en-tetes,
Accept-Language, les indicesSec-Ch-UaetAccept-Encodingdoivent ressembler au navigateur avec lequel tu as chauffe. Leimpersonatedecurl_cffigere l’essentiel pour toi. - Ne surcharge pas une seule session. Une unique session de navigateur qui martele des milliers de requetes par minute est elle-meme un indice revelateur. Repartis la charge sur plusieurs sessions chauffees et alterne entre elles.
- Persiste les cookies sur disque ou dans une petite base de donnees. Si ton processus redemarre, tu ne veux pas refaire chaque connexion. Stocke les cookies durables, recharge-les et rafraichis.
- Alterne les identites si tu geres plusieurs comptes. Garde les cookies durables de chaque compte separes et choisis-en un au hasard par lot. Cela repartit toute limite de debit par compte, meme si cela ne change rien a la reputation sous-jacente de ton IP.
Ce dernier point merite de l’honnetete. La reutilisation de session resout la vitesse et le throttling par compte. Elle ne repare pas une mauvaise IP. Si tes adresses de sortie sont deja signalees, aucune hygiene de cookies ne te sauvera, et c’est la qu’une couche de deblocage geree gagne sa place.
Foire aux Questions
Ai-je encore besoin d’un navigateur si j’utilise la persistance de session ? Oui, mais rarement. Le navigateur etablit et rafraichit la session ; le client HTTP rapide fait le gros de la recuperation. Tu passes d’un lancement de navigateur par page a un toutes les 10 a 30 minutes.
Pourquoi mon cookie copie fonctionne-t-il dans le navigateur mais pas dans requests ?
Presque toujours une empreinte qui ne correspond pas. requests nu a une signature TLS Python que les systemes anti-bot reperent au premier coup d’oeil. Utilise curl_cffi avec impersonate, ou un autre client qui imite une empreinte de navigateur, et envoie le meme User-Agent.
Qu’est-ce que le cookie __cf_bm et pourquoi expire-t-il sans cesse ?
__cf_bm est le cookie de gestion des bots de Cloudflare. Il est volontairement a courte duree de vie (environ 30 minutes) pour que les sessions capturees ne puissent pas etre rejouees indefiniment. Rafraichis ta session dans cette fenetre.
Puis-je partager une session entre plusieurs machines ? Tu peux, mais garde-les derriere la meme IP de sortie ou une IP similaire et ne depasse pas des debits de requete raisonnables. Repartir une session entre de nombreuses IP a la fois est un moyen courant de l’invalider.
Pour Conclure
La persistance de session consiste surtout a respecter le fonctionnement reel des sessions : un ensemble de cookies durables et a courte duree de vie, lie a une identite client et un reseau coherents. Chauffe une fois dans un navigateur, rejoue avec un client a empreinte correspondante, rafraichis avant l’expiration des cookies a courte duree de vie, et surveille les blocages silencieux pour rechauffer a temps.
Si tu preferes ne pas gerer toi-meme la flotte de navigateurs, le rafraichisseur de cookies et la rotation des proxys, c’est exactement ce que ScrapeUnblocker gere derriere un seul appel API : il gere la session, l’empreinte et le deblocage pour que tu demandes simplement une URL et recuperes la page. Tu peux lire la documentation pour developpeurs pour voir comment cela s’integre dans un pipeline existant. Dans tous les cas, le principe reste le meme : fais le travail couteux une fois, et reutilise-le.
Essayez ScrapeUnblocker gratuitement
Taux de réussite de plus de 95 % · à partir de 0,55 € pour 1 000 appels · 500 requêtes gratuites à l'inscription.