Utiliser des proxys en R : guide complet avec httr2 et rvest

Apprenez à configurer des proxys résidentiels en R avec httr2 (req_proxy) et rvest : géociblage, sessions persistantes, rotation d'IP, scraping de tables paginées et pages JS rendues.

Using Proxies in R: A Code-First Guide with httr2 and rvest

Vous scrapez des données publiques en R et vos appels httr2 commencent à renvoyer des erreurs 403 Forbidden après quelques dizaines de requêtes seulement. C'est le scénario classique : votre adresse IP est signalée par un pare-feu WAF ou un service anti-bot comme Cloudflare ou Datadome. Pour utiliser des proxys en R efficacement, il faut comprendre comment httr2 route les requêtes via req_proxy(), comment rvest parse le HTML récupéré, et comment configurer la rotation d'IP pour maintenir un taux de succès élevé. Ce guide couvre tout cela avec du code R exécutable.

Pourquoi utiliser des proxys en R avec httr2 et rvest

Le web scraping en R s'est considérablement modernisé. L'ancienne stack httr + XML a cédé la place à httr2 et rvest, deux packages du tidyverse qui offrent une API pipeline-first, une gestion d'erreurs structurée et une intégration native des proxys via req_proxy(). Mais même avec les meilleurs outils, votre IP de sortie reste votre talon d'Achille.

Les sites modernes déploient des systèmes anti-bot sophistiqués qui analysent l'adresse IP source, les en-têtes HTTP, le comportement de navigation et même les empreintes TLS. Une IP datacenter est souvent bloquée avant même la première requête, car les plages d'IP cloud (AWS, GCP, Azure) sont cataloguées comme non-résidentielles. Les proxys résidentiels utilisent des adresses IP fournies par de vrais FAI, ce qui les rend indiscernables du trafic organique.

Voici une comparaison des trois types de proxys disponibles pour vos projets R :

CaractéristiqueRésidentielDatacenterMobile
Origine IPFAI réelData centerOpérateur mobile
Risque de blocageFaibleÉlevéTrès faible
Latence typique~200 ms~50 ms~300 ms
Coût relatifMoyenBasÉlevé
Cas d'usageScraping, SERPAPIs, tâches internesApps mobiles

Pour la plupart des cas de R proxy — scraping de prix, suivi SERP, collecte de données e-commerce — les proxys résidentiels offrent le meilleur compromis fiabilité/coût. Consultez notre page de tarification pour les détails.

La stack moderne : configurer req_proxy() dans httr2

La fonction req_proxy() d'httr2 encapsule la configuration du proxy Curl sous-jacent. Vous passez l'URL du proxy, un nom d'utilisateur et un mot de passe. httr2 gère l'authentification Proxy-Authorization automatiquement via libcurl. C'est l'équivalent R de l'option --proxy en ligne de commande.

library(httr2)
library(rvest)

# Configuration du proxy ProxyHat
proxy_url <- "http://gate.proxyhat.com:8080"
proxy_user <- "votre-utilisateur"
proxy_pass <- "votre-mot-de-passe"

# Construire et exécuter la requête
req <- request("https://httpbin.org/ip") |>
  req_proxy(proxy_url, username = proxy_user, password = proxy_pass) |>
  req_user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") |>
  req_headers("Accept-Language" = "en-US,en;q=0.9")

resp <- req |> req_perform()
cat("Statut:", resp_status(resp), "\n")
cat(resp_body_string(resp), "\n")

Une fois la réponse obtenue, rvest prend le relais pour le parsing. La fonction read_html() accepte une chaîne brute, une réponse httr2, ou une URL. Pour extraire des données structurées, on enchaîne html_elements() avec des sélecteurs CSS, puis html_text(), html_attr() ou html_table() :

# Parser le HTML de la réponse
html <- resp_body_string(resp) |> read_html()

# Extraire un tableau HTML
df <- html |>
  html_elements("table") |>
  html_table(trim = TRUE) |>
  .[[1]]

print(head(df))

Ce pattern — request()req_proxy()req_perform()read_html() — est la base de tout pipeline de rvest proxy en R. Le ProxyHat SDK (disponible en Python et Node.js) reproduit exactement ce schéma pour les pipelines multi-langages.

Géociblage et sessions persistantes

ProxyHat encode le géociblage et les sessions directement dans le nom d'utilisateur du proxy. Pas besoin de paramètres supplémentaires : tout passe par l'authentification proxy standard. Pour cibler un pays spécifique, ajoutez country-XX au nom d'utilisateur. Pour une ville, ajoutez city-ville. Pour une session persistante (sticky), ajoutez session-identifiant.

library(httr2)

# Géociblage : Royaume-Uni, Londres
geo_user <- "votre-utilisateur-country-GB-city-london"
req_uk <- request("https://httpbin.org/ip") |>
  req_proxy("http://gate.proxyhat.com:8080",
            username = geo_user, password = "votre-mot-de-passe")

# Session persistante : même IP pour plusieurs requêtes
sticky_user <- "votre-utilisateur-country-GB-city-london-session-order-001"
req_sticky <- request("https://httpbin.org/ip") |>
  req_proxy("http://gate.proxyhat.com:8080",
            username = sticky_user, password = "votre-mot-de-passe")

# Vérifier que l'IP reste la même sur 3 requêtes
for (i in 1:3) {
  resp <- req_sticky |> req_perform()
  cat("Requête", i, ":", resp_body_string(resp), "\n")
}

Les sessions persistantes sont essentielles pour les sites qui maintiennent un état côté serveur (panier, login, pagination séquentielle). Sans session sticky, chaque requête peut arriver depuis une IP différente, ce qui déclenche des alertes anti-bot. Avec une session, l'IP reste stable pendant toute la durée de la session — généralement 10 à 30 minutes selon la configuration. Pour diversifier vos géographies, consultez nos locations disponibles.

SOCKS5 sur le port 1080

Pour les cas où HTTP CONNECT pose problème (pare-feu strict, tunneling UDP), ProxyHat propose SOCKS5 sur le port 1080. La configuration dans httr2 est identique, seul le schéma d'URL change :

library(httr2)

# SOCKS5 sur le port 1080
req_socks <- request("https://httpbin.org/ip") |>
  req_proxy("socks5://gate.proxyhat.com:1080",
            username = "votre-utilisateur-country-DE",
            password = "votre-mot-de-passe") |>
  req_timeout(30)

resp <- req_socks |> req_perform()
cat(resp_body_string(resp), "\n")

SOCKS5 est légèrement plus rapide que HTTP CONNECT car il évite une couche d'encapsulation, mais la différence est marginale (10 à 20 ms). Choisissez SOCKS5 principalement si votre infrastructure l'impose.

Exemple complet : scraper une table paginée en R

Voici un exemple réaliste : scraper une table paginée de 20 pages, en utilisant purrr::map_dfr() pour concaténer les résultats, une rotation de session par page pour distribuer les IP, et req_retry() + req_throttle() pour la résilience. Cette approche httr2 req_proxy est reproductible et production-ready.

library(httr2)
library(rvest)
library(purrr)
library(dplyr)

scrape_page <- function(page_num) {
  # Session unique par page = IP différente à chaque page
  session_id <- paste0("page-", page_num, "-", as.integer(Sys.time()))
  proxy_user <- paste0("votre-utilisateur-country-US-session-", session_id)

  req <- request(paste0("https://example.com/products?page=", page_num)) |>
    req_proxy("http://gate.proxyhat.com:8080",
              username = proxy_user, password = "votre-mot-de-passe") |>
    req_user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") |>
    req_headers(
      "Accept-Language" = "en-US,en;q=0.9",
      "Accept" = "text/html,application/xhtml+xml"
    ) |>
    req_retry(max_tries = 5, backoff = ~ 2^.) |>
    req_throttle(rate = 10 / 60) |>  # 10 requêtes par minute max
    req_timeout(30)

  resp <- req |> req_perform()

  html <- resp_body_string(resp) |> read_html()

  table <- html |>
    html_elements("table.products") |>
    html_table(trim = TRUE) |>
    .[[1]]

  table$page <- page_num
  return(table)
}

# Scraping des 20 pages avec gestion d'erreurs
all_data <- 1:20 |>
  map_dfr(possibly(scrape_page, otherwise = NULL))

cat("Lignes récupérées:", nrow(all_data), "\n")

Quelques points clés sur ce code :

  • req_retry(max_tries = 5, backoff = ~ 2^.) : relance automatiquement les requêtes échouées avec un délai exponentiel (2s, 4s, 8s, 16s, 32s).
  • req_throttle(rate = 10 / 60) : limite à 10 requêtes par minute, soit une requête toutes les 6 secondes, pour respecter le rythme d'un utilisateur humain.
  • purrr::possibly() : wrapper non-bloquant qui renvoie NULL au lieu de planter si une page échoue après tous les retries.
  • map_dfr() : concatène automatiquement les data frames par lignes.

Si une page échoue systématiquement, vous pouvez identifier les lignes NULL et relancer uniquement ces pages avec une session différente. Pour des projets à plus grande échelle, consultez nos guides sur le web scraping et le suivi SERP.

Pages rendues en JavaScript avec read_html_live()

De nombreux sites modernes (React, Vue, Angular) rendent leur contenu côté client. read_html() ne voit que le HTML initial, souvent vide. La fonction read_html_live() de rvest utilise chromote pour lancer un Chrome headless et exécuter le JavaScript avant de capturer le DOM.

library(rvest)

# read_html_live() lance un Chrome headless via chromote
# Le proxy se configure via les flags Chrome
page <- read_html_live("https://example.com/js-app",
  args = c(
    "--proxy-server=http://gate.proxyhat.com:8080",
    "--disable-blink-features=AutomationControlled"
  )
)

# Attendre que le contenu dynamique soit chargé
Sys.sleep(3)

# Extraire les données après rendu JS
products <- page |>
  html_elements(".product-list .product") |>
  html_text2()

cat("Produits trouvés:", length(products), "\n")

Note importante : Chrome ne supporte pas l'authentification proxy inline dans le flag --proxy-server. Pour les proxys authentifiés comme ProxyHat, deux options : (1) utiliser le ProxyHat SDK qui gère l'authentification automatiquement via le DevTools Protocol, ou (2) configurer un relay local (ex. tinyproxy) qui ajoute l'en-tête Proxy-Authorization. Pour les pipelines mixtes Python/Node, le SDK ProxyHat reproduit le même pattern proxy → auth → request que nous utilisons ici en R.

Erreurs courantes et edge cases

Oublier req_user_agent()

Le User-Agent par défaut de httr2 (httr2/1.0.0) est immédiatement identifiable comme un bot. Toujours définir un UA réaliste avec req_user_agent(), et idéalement varier les en-têtes Accept, Accept-Language et Referer pour imiter un navigateur réel.

Timeouts trop courts

Les proxys résidentiels ajoutent de la latence (50 à 200 ms supplémentaires). Un timeout de 5 secondes peut échouer sur des pages lourdes. Utilisez req_timeout(30) au minimum pour les pages complexes.

Ne pas gérer les erreurs 429

Le code 429 (Too Many Requests) indique un rate limiting. req_retry() gère automatiquement les 429 si vous activez is_transient = ~ resp_status(.) == 429. Sans cette configuration, vos requêtes échouent silencieusement.

Mélanger sessions et rotation

Si vous utilisez une session sticky pour une pagination séquentielle, ne changez pas de session en milieu de parcours. Le site verra une IP différente à la page 5, ce qui peut déclencher une vérification anti-bot. Gardez le même session-id pour tout le parcours.

Éthique, conformité et bonnes pratiques

Le scraping de données publiques est légal dans de nombreuses juridictions, mais il doit être pratiqué de manière responsable. Voici les principes à respecter :

  • Robots.txt : consultez toujours le fichier robots.txt du site cible. Le standard est défini par la RFC 9309. Respectez les directives Disallow même si elles ne sont pas techniquement contraignantes.
  • Conditions d'utilisation : lisez les ToS du site. Certaines plateformes interdisent explicitement le scraping automatisé, même pour des données publiques.
  • RGPD : pour les données personnelles de résidents de l'UE, le RGPD s'applique. Ne collectez pas d'informations personnellement identifiables sans base légale, et prévoyez un mécanisme de suppression.
  • Préférez les APIs : si le site propose une API officielle (même payante), c'est presque toujours la meilleure option. Le scraping doit être un dernier recours.
  • Rate limiting respectueux : limitez votre débit à ce qu'un humain pourrait faire. req_throttle() avec 10 requêtes par minute est un bon point de départ.

Points clés à retenir

  • httr2 + rvest est la stack moderne pour le scraping en R. req_proxy() gère l'authentification proxy nativement via libcurl.
  • Géociblage et sessions se configurent directement dans le nom d'utilisateur ProxyHat (user-country-GB-city-london-session-id).
  • Proxys résidentiels : indispensables pour les sites anti-bot. Les IP datacenter sont détectées dans 60 à 80 % des cas selon les sources.
  • Résilience : req_retry() + req_throttle() + purrr::possibly() pour un scraping robuste qui ne plante pas.
  • Pages JS : read_html_live() via chromote, avec proxy configuré via les flags Chrome. L'auth proxy nécessite un relay ou le ProxyHat SDK.
  • Éthique : respectez robots.txt, ToS et RGPD. Préférez toujours les APIs officielles quand elles existent.

FAQ

Qu'est-ce que l'utilisation de proxys en R ?

L'utilisation de proxys en R consiste à router les requêtes HTTP d'un script R — typiquement via httr2 et req_proxy() — à travers un serveur proxy intermédiaire qui masque votre IP de sortie. Cela permet de distribuer les requêtes sur plusieurs adresses IP, d'éviter les blocages anti-bot et de géolocaliser le trafic. Le proxy agit comme un relais entre votre session R et le site cible.

Pourquoi l'utilisation de proxys en R est-elle importante pour les utilisateurs de proxys ?

Sans proxy, toutes vos requêtes partent de la même IP. Les sites modernes détectent les patterns de scraping (volume, fréquence, User-Agent) et bloquent l'IP après quelques dizaines de requêtes. Les proxys résidentiels fournissent des IP de vrais FAI, indiscernables du trafic organique, ce qui maintient un taux de succès élevé même sur des sites protégés par Cloudflare ou Datadome.

Quel type de proxy fonctionne le mieux en R ?

Les proxys résidentiels offrent le meilleur compromis pour le scraping en R : faible risque de blocage, latence acceptable (~200 ms) et coût modéré. Les proxys datacenter sont moins chers mais détectés rapidement par les anti-bots. Les proxys mobiles sont les plus furtifs mais plus coûteux. Pour le suivi SERP et le scraping e-commerce, résidentiel est le choix par défaut.

Comment éviter les blocages avec des proxys en R ?

Combinez plusieurs stratégies : (1) utilisez des proxys résidentiels avec rotation de session par requête, (2) définissez un User-Agent réaliste avec req_user_agent(), (3) limitez le débit avec req_throttle() à 10 requêtes par minute, (4) activez req_retry() avec backoff exponentiel pour les erreurs transitoires, et (5) respectez le fichier robots.txt du site cible.

Prêt à commencer ?

Accédez à plus de 50M d'IPs résidentielles dans plus de 148 pays avec filtrage IA.

Voir les tarifsProxies résidentiels
← Retour au Blog