Web Scraping en Python avec un Proxy 4G Français : Le Guide Complet

Vous avez passé des heures à construire votre scraper Python, et pourtant, au bout de quelques dizaines de requêtes, vous tombez sur un mur : 403 Forbidden, 429 Too Many Requests, ou pire, une page CAPTCHA. Le web scraping en Python est un outil puissant — mais les sites web ne l’entendent pas de cette oreille.

La bonne nouvelle ? Il existe une solution élégante, efficace, et souvent sous-estimée : le proxy 4G français. Dans ce guide complet, nous allons voir pourquoi vos scrapers se font bloquer, comment fonctionnent les protections modernes, et surtout comment les contourner proprement avec BeautifulSoup et Scrapy.


1. Pourquoi vos scrapers se font bloquer

Quand vous visitez un site web depuis votre navigateur, vous n’êtes qu’un utilisateur parmi des millions. Mais quand votre script Python envoie 200 requêtes en 30 secondes depuis la même adresse IP, le serveur — ou le pare-feu devant lui — le détecte immédiatement.

Le problème fondamental du web scraping est simple : votre IP vous trahit. Une adresse IP fixe, associée à un datacenter ou à une connexion résidentielle statique, laisse une trace évidente. Les serveurs peuvent :

  • Compter le nombre de requêtes par IP sur une fenêtre de temps
  • Identifier les plages d’adresses appartenant aux hébergeurs cloud (AWS, OVH, DigitalOcean)
  • Analyser les en-têtes HTTP pour détecter des patterns inhabituels
  • Comparer votre comportement à celui d’un utilisateur humain réel

Le résultat : votre IP se retrouve bannie, temporairement ou définitivement. Et recommencer depuis une nouvelle adresse de datacenter ? Elle sera bannie encore plus vite, car ces plages IP sont déjà connues et surveillées.


2. Les solutions anti-scraping modernes

Les protections anti-scraping ont considérablement évolué ces dernières années. Comprendre leurs mécanismes est indispensable pour les contourner efficacement.

Rate limiting

La protection la plus basique : le serveur compte vos requêtes. Au-delà d’un certain seuil (souvent 10-50 requêtes/minute selon le site), il répond avec un 429 Too Many Requests ou vous redirige vers une page d’attente. Certains sites implémentent un rate limiting dynamique qui s’adapte selon la “suspicion” générée par votre comportement.

Fingerprinting navigateur

Des solutions comme Cloudflare, DataDome, ou Imperva vont bien au-delà du simple comptage de requêtes. Elles analysent :

  • L’en-tête User-Agent : est-il cohérent avec un vrai navigateur ?
  • Les en-têtes HTTP complets : ordre, casse, valeurs attendues
  • Les cookies et les tokens de session
  • Le comportement temporel : les humains ne cliquent pas à intervalles réguliers

Ces systèmes construisent un “fingerprint” de votre client. Si ce fingerprint ressemble à un bot plutôt qu’à Chrome 121 sous Windows 11, vous êtes bloqué.

CAPTCHAs et challenges JavaScript

Cloudflare impose souvent un challenge JavaScript avant d’accorder l’accès : votre client doit exécuter du JS pour prouver qu’il est un navigateur légitime. Les bibliothèques requests ou httpx classiques échouent à ce test par nature.

Les reCAPTCHA v3 de Google évaluent un score de 0 à 1 basé sur votre comportement global (historique, mouvements souris, IP…). Un score inférieur à 0.5 déclenche une vérification supplémentaire.

Détection des IPs datacenter

C’est le talón d’Achille des proxies classiques. Des bases de données comme MaxMind, ip-api, ou les renseignements propriétaires de Cloudflare permettent d’identifier en millisecondes si une IP appartient à :

  • Un hébergeur cloud (AWS, Azure, GCP, OVH)
  • Un fournisseur de proxies connu
  • Un réseau Tor ou VPN commercial

Ces IPs sont immédiatement catégorisées comme “non-résidentielles” et traitées avec une méfiance maximale.


3. Pourquoi un proxy 4G est la meilleure solution

Un proxy 4G change radicalement la donne pour une raison précise : l’IP qu’il expose appartient à un opérateur mobile français (Free Mobile, Orange, SFR, Bouygues), pas à un datacenter.

Le mécanisme CGNAT : votre atout secret

Les opérateurs mobiles utilisent le CGNAT (Carrier-Grade Network Address Translation). En pratique, cela signifie qu’une seule adresse IP publique est partagée entre des dizaines, voire des centaines d’abonnés simultanément. Un site web qui reçoit des requêtes depuis l’IP 82.45.123.67 ne peut pas distinguer si elles viennent d’un étudiant qui scrolle sur Instagram, d’un commercial qui consulte LinkedIn, ou de votre scraper Python.

Bloquer cette IP reviendrait à bloquer des centaines d’utilisateurs légitimes. C’est pourquoi les opérateurs anti-scraping ne peuvent pas simplement bannir ces adresses.

IPs 100% authentiques, rotation naturelle

La rotation des IPs n’est pas un mécanisme artificiel inventé par HexaProxy — c’est l’opérateur lui-même (Free, Orange, SFR, Bouygues) qui attribue les IPs via CGNAT à chaque reconnexion. Cette rotation est donc totalement naturelle et indiscernable de celle de millions d’utilisateurs mobiles normaux. Pour aller plus loin sur ce sujet, lisez notre article Proxy rotatif : c’est quoi et pourquoi en utiliser un ?

Résultat : votre trafic de scraping ressemble à du trafic mobile humain authentique. Les systèmes de détection les plus sophistiqués ne peuvent pas le distinguer d’un vrai utilisateur.

Comparaison des types de proxies

TypeDétectabilitéCoûtFiabilité
DatacenterTrès hauteFaibleMoyenne
Résidentiel fixeMoyenneMoyenBonne
4G mobileTrès faibleMoyenExcellente
Résidentiel rotatifFaibleÉlevéVariable

4. Tutoriel — requests + BeautifulSoup avec proxy 4G

Passons à la pratique. Voici comment configurer un proxy 4G avec les bibliothèques Python les plus populaires.

Installation

pip install requests beautifulsoup4 lxml

Configuration basique du proxy

import requests
from bs4 import BeautifulSoup
import time
import random

# Configuration du proxy 4G
PROXY_HOST = "proxy.example.com"
PROXY_PORT = 8080
PROXY_USER = "votre_utilisateur"
PROXY_PASS = "votre_mot_de_passe"

proxies = {
    "http": f"http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}",
    "https": f"http://{PROXY_USER}:{PROXY_PASS}@{PROXY_HOST}:{PROXY_PORT}",
}

# Headers réalistes
headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
    "Accept-Language": "fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7",
    "Accept-Encoding": "gzip, deflate, br",
    "Connection": "keep-alive",
    "Upgrade-Insecure-Requests": "1",
}

def scrape_page(url):
    try:
        response = requests.get(
            url,
            proxies=proxies,
            headers=headers,
            timeout=30
        )
        response.raise_for_status()
        return response.text
    except requests.exceptions.RequestException as e:
        print(f"Erreur lors de la requête : {e}")
        return None

# Exemple : scraper des titres de produits
def scrape_products(base_url, pages=5):
    all_products = []
    
    for page in range(1, pages + 1):
        url = f"{base_url}?page={page}"
        print(f"Scraping page {page}...")
        
        html = scrape_page(url)
        if not html:
            continue
            
        soup = BeautifulSoup(html, "lxml")
        
        # Adapter le sélecteur CSS à votre cible
        products = soup.select(".product-title")
        for product in products:
            all_products.append(product.get_text(strip=True))
        
        # Délai aléatoire entre les requêtes (comportement humain)
        delay = random.uniform(2.0, 5.0)
        print(f"  → {len(products)} produits trouvés. Attente {delay:.1f}s...")
        time.sleep(delay)
    
    return all_products

# Utilisation
if __name__ == "__main__":
    products = scrape_products("https://exemple-site.com/catalogue")
    print(f"\nTotal : {len(products)} produits récoltés")
    for p in products[:10]:
        print(f"  - {p}")

Utilisation avec une Session requests

Pour les scrapers qui nécessitent une authentification ou le maintien de cookies, utilisez un objet Session :

import requests
from bs4 import BeautifulSoup

def create_session(proxy_host, proxy_port, proxy_user, proxy_pass):
    session = requests.Session()
    
    session.proxies = {
        "http": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
        "https": f"http://{proxy_user}:{proxy_pass}@{proxy_host}:{proxy_port}",
    }
    
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1",
        "Accept-Language": "fr-FR,fr;q=0.9",
    })
    
    return session

# Créer la session une fois, réutiliser pour toutes les requêtes
session = create_session("proxy.example.com", 8080, "user", "pass")

# Vérifier l'IP utilisée
ip_check = session.get("https://api.ipify.org?format=json")
print(f"IP visible : {ip_check.json()['ip']}")

5. Tutoriel — Scrapy avec proxy middleware

Scrapy est le framework de scraping Python le plus puissant pour les projets à grande échelle. Voici comment intégrer un proxy 4G.

Création du projet

pip install scrapy
scrapy startproject mon_scraper
cd mon_scraper

Middleware proxy personnalisé

Créez le fichier mon_scraper/middlewares/proxy_middleware.py :

import base64
import logging

logger = logging.getLogger(__name__)

class Proxy4GMiddleware:
    """
    Middleware Scrapy pour router les requêtes via un proxy 4G.
    Supporte l'authentification Basic.
    """
    
    def __init__(self, proxy_url, proxy_user=None, proxy_pass=None):
        self.proxy_url = proxy_url
        self.proxy_auth = None
        
        if proxy_user and proxy_pass:
            credentials = f"{proxy_user}:{proxy_pass}"
            encoded = base64.b64encode(credentials.encode("utf-8")).decode("utf-8")
            self.proxy_auth = f"Basic {encoded}"
        
        logger.info(f"Proxy 4G configuré : {proxy_url}")
    
    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            proxy_url=crawler.settings.get("PROXY_URL"),
            proxy_user=crawler.settings.get("PROXY_USER"),
            proxy_pass=crawler.settings.get("PROXY_PASS"),
        )
    
    def process_request(self, request, spider):
        request.meta["proxy"] = self.proxy_url
        
        if self.proxy_auth:
            request.headers["Proxy-Authorization"] = self.proxy_auth
        
        spider.logger.debug(f"Requête via proxy 4G : {request.url}")

Configuration dans settings.py

# mon_scraper/settings.py

BOT_NAME = "mon_scraper"

# Proxy 4G HexaProxy
PROXY_URL = "http://proxy.example.com:8080"
PROXY_USER = "votre_utilisateur"
PROXY_PASS = "votre_mot_de_passe"

# Activer le middleware
DOWNLOADER_MIDDLEWARES = {
    "mon_scraper.middlewares.proxy_middleware.Proxy4GMiddleware": 350,
    "scrapy.downloadermiddlewares.useragent.UserAgentMiddleware": None,
}

# Comportement humain : délais aléatoires
DOWNLOAD_DELAY = 2
RANDOMIZE_DOWNLOAD_DELAY = True  # Scrapy multipliera par 0.5 à 1.5

# Respecter les limites de concurrence
CONCURRENT_REQUESTS = 4
CONCURRENT_REQUESTS_PER_DOMAIN = 2

# User-Agent réaliste
USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36"

# Activer AutoThrottle pour s'adapter au site
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 1
AUTOTHROTTLE_MAX_DELAY = 10
AUTOTHROTTLE_TARGET_CONCURRENCY = 2.0

# Cookies activés (comportement navigateur)
COOKIES_ENABLED = True

# Respecter robots.txt (recommandé)
ROBOTSTXT_OBEY = True

Spider d’exemple

# mon_scraper/spiders/catalogue_spider.py

import scrapy

class CatalogueSpider(scrapy.Spider):
    name = "catalogue"
    start_urls = ["https://exemple-site.com/catalogue"]
    
    custom_settings = {
        "FEEDS": {
            "produits.json": {
                "format": "json",
                "encoding": "utf8",
                "overwrite": True,
            }
        }
    }
    
    def parse(self, response):
        self.logger.info(f"Scraping : {response.url} (status: {response.status})")
        
        # Extraire les produits
        for produit in response.css(".product-card"):
            yield {
                "nom": produit.css(".product-title::text").get("").strip(),
                "prix": produit.css(".product-price::text").get("").strip(),
                "url": response.urljoin(produit.css("a::attr(href)").get("")),
            }
        
        # Pagination
        page_suivante = response.css("a.next-page::attr(href)").get()
        if page_suivante:
            yield response.follow(page_suivante, callback=self.parse)
    
    def errback(self, failure):
        self.logger.error(f"Échec de la requête : {failure.request.url}")
        self.logger.error(repr(failure))

Lancement du spider

scrapy crawl catalogue -L INFO

6. Bonnes pratiques pour ne jamais se faire bloquer

Même avec un proxy 4G de qualité, quelques bonnes pratiques sont indispensables pour maximiser votre taux de succès.

Rotation des User-Agents

Variez vos User-Agents pour paraître encore plus naturel :

import random

USER_AGENTS = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36",
    "Mozilla/5.0 (iPhone; CPU iPhone OS 17_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.2 Mobile/15E148 Safari/604.1",
    "Mozilla/5.0 (Android 14; Mobile; rv:122.0) Gecko/122.0 Firefox/122.0",
]

def get_random_headers():
    return {
        "User-Agent": random.choice(USER_AGENTS),
        "Accept-Language": random.choice(["fr-FR,fr;q=0.9", "fr-FR,fr;q=0.8,en-US;q=0.7"]),
    }

Délais intelligents

Les humains ne lisent pas à vitesse constante. Simulez un comportement réaliste :

import time
import random

def human_delay(min_sec=1.5, max_sec=4.0):
    """Pause aléatoire imitant le comportement humain."""
    delay = random.uniform(min_sec, max_sec)
    # Parfois plus longue pause (comme si on lisait la page)
    if random.random() < 0.1:  # 10% du temps
        delay += random.uniform(3.0, 8.0)
    time.sleep(delay)

Gestion des erreurs et retry

import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry

def create_resilient_session(proxy_url):
    session = requests.Session()
    session.proxies = {"http": proxy_url, "https": proxy_url}
    
    # Retry automatique sur erreurs réseau (pas sur 4xx/5xx)
    retry_strategy = Retry(
        total=3,
        backoff_factor=2,
        status_forcelist=[500, 502, 503, 504],
    )
    adapter = HTTPAdapter(max_retries=retry_strategy)
    session.mount("http://", adapter)
    session.mount("https://", adapter)
    
    return session

Ne jamais scraper sans respect du site

  • Consultez robots.txt avant de scraper
  • Respectez les CGU : certains sites interdisent explicitement le scraping
  • Limitez votre débit : ne surchargez pas un serveur
  • Évitez les heures de pointe : scraper la nuit génère moins d’impact

7. FAQ — Web Scraping Python et Proxy 4G

Q : Est-il légal de faire du web scraping en France ?

Le web scraping est généralement légal pour les données publiquement accessibles, tant que vous respectez les CGU du site, le RGPD pour les données personnelles, et que vous n’abusez pas des ressources serveur. Pour un usage commercial, consultez un juriste spécialisé.

Q : Quelle est la différence entre un proxy 4G et un proxy résidentiel ?

Un proxy résidentiel utilise les connexions de particuliers (souvent à leur insu). Un proxy 4G utilise des cartes SIM d’opérateurs mobiles dans de vrais téléphones mobiles. Le proxy 4G est plus éthique, plus stable, et offre une rotation IP naturelle via le mécanisme CGNAT de l’opérateur.

Q : Combien de requêtes peut-on envoyer avec un proxy 4G sans se faire bloquer ?

Il n’y a pas de règle universelle. En règle générale, rester sous 30-60 requêtes/minute avec des délais aléatoires donne d’excellents résultats. Le proxy 4G vous donne la marge nécessaire grâce à la légitimité de l’IP.

Q : Scrapy ou requests + BeautifulSoup, que choisir ?

Pour les projets simples ou débutants : requests + BeautifulSoup. Pour les projets à grande échelle, multi-sites, avec crawling profond : Scrapy, qui gère nativement la concurrence, les middlewares, et l’export de données.

Q : Le proxy 4G fonctionne-t-il avec Selenium ou Playwright ?

Oui. Avec Selenium, configurez le proxy dans les options ChromeDriver. Avec Playwright, utilisez le paramètre proxy dans browser.new_context(). Cette combinaison est particulièrement efficace pour contourner les challenges JavaScript de Cloudflare.


Prêt à scraper sans vous faire bloquer ?

Vous avez maintenant tous les outils pour construire un scraper Python robuste et indétectable. La clé, c’est la qualité de votre proxy : une IP mobile française authentique, attribuée par l’opérateur via CGNAT, est infiniment plus efficace qu’un proxy datacenter ou même la plupart des proxies résidentiels.

💬 Une question sur votre projet ? Contactez-nous directement sur WhatsApp : Discuter avec HexaProxy

Essayez HexaProxy gratuitement →

HexaProxy vous fournit des proxies 4G français avec IPs Free Mobile, Orange, SFR et Bouygues — les opérateurs les plus difficiles à bloquer pour les sites français. Configuration en 2 minutes, compatible avec tous les frameworks Python.

Prêt à essayer HexaProxy ?

Commencez avec des proxys mobiles 4G français premium dès aujourd'hui.

Commencer