Skip to content
Advanced / 11 min read

Comment router les proxys Dataimpulse via mitmproxy sur macOS pour le scraping web

Un unique écouteur mitmproxy local transfère chaque scraper, navigateur et émulateur sur macOS vers les proxys résidentiels ou mobiles Dataimpulse via HTTP ou SOCKS5, avec rotation, limitation de débit et inspection TLS optionnelle sous votre contrôle.

macOS SOCKS5 Scraping Web Confidentialité/Anonymat

Aperçu

mitmproxy est un proxy d'interception open source et scriptable qui s'exécute comme un processus macOS normal. En mode upstream, il accepte les connexions des clients locaux sur un port (127.0.0.1:8080) et transfère ce trafic vers un second proxy — ici, votre point de terminaison résidentiel ou mobile Dataimpulse.

L'avantage est la centralisation : vous configurez le proxy une fois, puis n'importe quel navigateur, outil CLI, script Python ou émulateur mobile sur la machine peut être routé via Dataimpulse sans modifier les propres paramètres de proxy de cet outil. Tout passe par un point de passage unique où vous pouvez limiter la concurrence, surveiller les échecs et confirmer quelle IP de sortie vous utilisez réellement.

Dataimpulse est un choix raisonnable pour ce schéma car il propose des points de terminaison résidentiels et mobiles via HTTP et SOCKS5, avec une facturation à l'usage et un large pool d'IP — utile pour la collecte de données par pics et à haut volume, où un engagement mensuel n'est pas nécessaire. Vous pouvez le comparer à d'autres fournisseurs de proxy avant de vous engager.

Quand cette approche est pertinente

Approche Ce que vous configurez Idéal pour
Mode upstream de mitmproxy (ce guide) Un port local pour tous les clients Plusieurs outils à la fois, limitation et journalisation centralisées
Options de proxy par outil (curl -x, proxies= de requests) Chaque outil séparément Un seul script avec un minimum d'éléments à gérer
Gestionnaires de proxy de bureau (par exemple Proxifier) Règles par application Applications GUI qui ignorent les paramètres de proxy système

Ce que vous allez mettre en place

  • Un écouteur mitmproxy local sur 127.0.0.1:8080
  • Une connexion upstream vers Dataimpulse via HTTP ou SOCKS5
  • Interception TLS optionnelle pour les hôtes spécifiques que vous souhaitez inspecter
  • Un addon de régulation de concurrence qui rend la pression des requêtes prévisible
  • Des exemples fonctionnels pour curl, requests, Playwright et un émulateur Android

Prérequis

  • macOS 13 ou version ultérieure avec Homebrew installé
  • Un compte Dataimpulse, ainsi que le nom d'utilisateur, le mot de passe, l'hôte de passerelle et les ports HTTP/SOCKS5 affichés dans votre tableau de bord
  • Python 3.9 ou version ultérieure pour les exemples client (python3 --version)
  • Une certaine aisance avec le Terminal et une compréhension de base des proxys HTTP et de TLS

Comment fonctionne la configuration

  1. mitmproxy écoute sur 127.0.0.1:8080.
  2. Votre client envoie sa requête à mitmproxy au lieu de l'envoyer directement au site cible.
  3. mitmproxy ouvre une connexion vers la passerelle Dataimpulse.
  4. Dataimpulse attribue une IP de sortie depuis son pool.
  5. La réponse revient via mitmproxy jusqu'à votre client.

Deux modes sont importants, et choisir entre eux tôt fait gagner du temps :

  • Pass-through (tunneling) : mitmproxy transfère les octets TLS sans les déchiffrer. Aucune modification de certificat n'est nécessaire nulle part. Activé avec --ignore-hosts '.*'.
  • Interception : mitmproxy termine TLS afin de pouvoir lire ou réécrire les requêtes et les réponses. Nécessite de faire confiance au certificat CA de mitmproxy sur macOS et dans chaque environnement d'exécution client.

Pour du scraping qui a seulement besoin d'une IP de sortie différente, le pass-through est plus simple et plus rapide, et il évite complètement le travail sur les certificats. Activez l'interception uniquement pour les hôtes que vous avez réellement besoin d'inspecter.

Étapes

  1. Installez mitmproxy.

    brew install mitmproxy
    mitmdump --version
    
  2. Exportez vos identifiants Dataimpulse en variables d'environnement afin qu'ils n'apparaissent jamais dans l'historique du shell ou dans des fichiers commités.

    export DI_USER='your-dataimpulse-username'
    export DI_PASS='your-dataimpulse-password'
    export DI_HOST='gateway-host-from-your-dashboard'
    export DI_HTTP_PORT='http-port-from-your-dashboard'
    export DI_SOCKS_PORT='socks5-port-from-your-dashboard'
    export DI_SESSION='scrape-macos-01'
    

    Ajoutez les mêmes lignes à ~/.zshrc si vous voulez qu'elles soient disponibles dans chaque nouveau shell, et confirmez l'hôte et le port sans afficher le mot de passe :

    echo "${DI_HOST}:${DI_HTTP_PORT}"
    
  3. Encodez en pourcentage les identifiants contenant des caractères réservés. Des caractères comme @, :, / ou # dans un mot de passe casseront l'URL upstream. Encodez uniquement la valeur que vous placez dans l'URL.

    python3 -c "import os, urllib.parse; print(urllib.parse.quote(os.environ['DI_PASS'], safe=''))"
    
  4. Démarrez mitmproxy en mode upstream pass-through via HTTP. En mode pass-through, mitmproxy tunnelise le trafic sans le déchiffrer, donc aucune modification de certificat client n'est requise.

    mitmdump \
      --mode "upstream:http://${DI_USER}:${DI_PASS}@${DI_HOST}:${DI_HTTP_PORT}" \
      --listen-port 8080 \
      --ignore-hosts '.*' \
      --set flow_detail=1
    
  5. Vérifiez l'IP de sortie. Laissez mitmproxy s'exécuter dans sa propre fenêtre de terminal et testez depuis une seconde fenêtre.

    curl -s -x http://127.0.0.1:8080 https://api.ipify.org
    echo
    curl -s https://api.ipify.org
    echo
    

    Les deux adresses doivent être différentes. Si elles correspondent, la requête n'atteint pas Dataimpulse — consultez la section de dépannage.

  6. Basculez l'upstream vers SOCKS5 lorsque vous voulez que le proxy résolve le DNS à distance, ce qui est souvent préférable pour les cibles sensibles à la géolocalisation.

    mitmdump \
      --mode "upstream:socks5://${DI_USER}:${DI_PASS}@${DI_HOST}:${DI_SOCKS_PORT}" \
      --listen-port 8080 \
      --ignore-hosts '.*'
    
  7. Activez l'interception uniquement pour les hôtes dont vous avez besoin. --allow-hosts limite le déchiffrement aux hôtes correspondants ; tout le reste reste tunnelisé et intact.

    mitmdump \
      --mode "upstream:http://${DI_USER}:${DI_PASS}@${DI_HOST}:${DI_HTTP_PORT}" \
      --listen-port 8080 \
      --allow-hosts 'example\.com' \
      -s ./gate.py
    
  8. Faites confiance au certificat CA de mitmproxy avant de scraper des hôtes HTTPS via interception. Les fichiers de certificat sont créés lors du premier démarrage de mitmproxy.

    # First run generates ~/.mitmproxy/mitmproxy-ca-cert.pem
    mitmdump --listen-port 8081 &
    sleep 2
    kill %1
    
    sudo security add-trusted-cert -d -r trustRoot \
      -k /Library/Keychains/System.keychain \
      ~/.mitmproxy/mitmproxy-ca-cert.pem
    

    Les environnements d'exécution en ligne de commande ignorent souvent le trousseau macOS, donc pointez-les vers un bundle explicite :

    cat "$(python3 -c 'import certifi; print(certifi.where())')" \
      ~/.mitmproxy/mitmproxy-ca-cert.pem > ~/.mitmproxy/ca-bundle.pem
    
    export REQUESTS_CA_BUNDLE=~/.mitmproxy/ca-bundle.pem
    export NODE_EXTRA_CA_CERTS=~/.mitmproxy/mitmproxy-ca-cert.pem
    
  9. Ajoutez un addon de régulation de concurrence afin qu'une rafale d'un scraper rapide ne submerge pas la passerelle. Enregistrez ceci sous gate.py à côté du répertoire depuis lequel vous lancez mitmproxy.

    # gate.py — cap in-flight requests passing through mitmproxy
    import asyncio
    
    from mitmproxy import http
    
    
    class Gate:
        def __init__(self, limit: int = 8) -> None:
            self._limit = limit
            self._sem: asyncio.Semaphore | None = None
    
        def running(self) -> None:
            self._sem = asyncio.Semaphore(self._limit)
    
        async def request(self, flow: http.HTTPFlow) -> None:
            await self._sem.acquire()
            flow.metadata["gate_held"] = True
    
        def _release(self, flow: http.HTTPFlow) -> None:
            if flow.metadata.pop("gate_held", False):
                self._sem.release()
    
        def response(self, flow: http.HTTPFlow) -> None:
            self._release(flow)
    
        def error(self, flow: http.HTTPFlow) -> None:
            self._release(flow)
    
    
    addons = [Gate(limit=8)]
    

    Chargez-le avec -s ./gate.py. Notez que les addons ne voient que les flux interceptés : si vous exécutez avec --ignore-hosts '.*', les connexions sont tunnelisées et ces hooks ne se déclenchent jamais. Dans ce cas, limitez plutôt la concurrence à l'intérieur de votre scraper.

  10. Pointez vos outils vers l'écouteur local. Pour les outils shell, exportez les variables standard dans le terminal depuis lequel vous scrapez — mais pas dans le terminal qui exécute mitmproxy, pour éviter une boucle de proxy.

    export HTTP_PROXY=http://127.0.0.1:8080
    export HTTPS_PROXY=http://127.0.0.1:8080
    export NO_PROXY=localhost,127.0.0.1
    curl -s https://httpbin.org/ip
    

    Pour un script Python, aucune configuration CA n'est nécessaire tant que vous restez en mode pass-through :

    import requests
    
    LOCAL_PROXY = "http://127.0.0.1:8080"
    proxies = {"http": LOCAL_PROXY, "https": LOCAL_PROXY}
    
    response = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=30)
    response.raise_for_status()
    print(response.json())
    

    Pour un navigateur headless, transmettez le même proxy local au contexte du navigateur :

    from playwright.sync_api import sync_playwright
    
    LOCAL_PROXY = "http://127.0.0.1:8080"
    
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=True, proxy={"server": LOCAL_PROXY})
        page = browser.new_page()
        page.goto("https://httpbin.org/ip", wait_until="domcontentloaded")
        print(page.inner_text("body"))
        browser.close()
    

    Si vous devez aussi scraper un service exécuté sur votre propre machine, Chromium contourne les adresses loopback par défaut. Ajouter args=["--proxy-bypass-list=<-loopback>"] à l'appel de lancement supprime cette exemption.

  11. Capturez le trafic de l'émulateur (facultatif). Les points de terminaison mobiles Dataimpulse fournissent des IP de sortie de qualité opérateur ; ils ne capturent pas eux-mêmes le trafic de l'appareil. Pour router un émulateur via ce pool, pointez l'émulateur vers l'écouteur de l'hôte.

    # Android emulator: 10.0.2.2 is the host machine
    adb shell settings put global http_proxy 10.0.2.2:8080
    adb shell settings get global http_proxy
    
    # Reset when finished
    adb shell settings put global http_proxy :0
    

    Pour le simulateur iOS, ouvrez Réglages, choisissez Wi-Fi, puis Configurer le proxy, Manuel, et définissez le serveur sur 127.0.0.1 au port 8080. Le trafic du simulateur partage la pile réseau du Mac, donc l'interception nécessite que la CA soit également installée dans le simulateur.

  12. Nettoyez lorsque vous avez terminé. Supprimez le certificat d'interception et réinitialisez les paramètres client afin que le trafic non lié cesse de passer par mitmproxy.

    sudo security delete-certificate -c mitmproxy /Library/Keychains/System.keychain
    unset HTTP_PROXY HTTPS_PROXY
    

Dépannage

407 Proxy Authentication Required

L'URL upstream manque d'identifiants, ou un caractère réservé dans le mot de passe a cassé l'URL. Réexécutez la commande d'encodage en pourcentage de l'étape 3 et reconstruisez la chaîne --mode avec la valeur encodée.

SSLCertVerificationError, CERT_AUTHORITY_INVALID, ou « unable to get local issuer certificate »

Vous avez activé l'interception mais le client ne fait pas confiance à la CA de mitmproxy. Installez le certificat comme indiqué à l'étape 8, puis définissez les variables de bundle spécifiques à l'environnement d'exécution (REQUESTS_CA_BUNDLE, NODE_EXTRA_CA_CERTS). Sinon, revenez au mode pass-through avec --ignore-hosts '.*' si vous n'avez pas besoin de lire le trafic.

Adresse déjà utilisée

Un autre processus occupe déjà le port. Trouvez-le, puis modifiez --listen-port au lieu de tuer des services non liés.

lsof -nP -iTCP:8080 -sTCP:LISTEN

Toutes les requêtes se bloquent ou expirent

Vous êtes très probablement dans une boucle de proxy : HTTP_PROXY est exporté dans le même shell que celui qui a lancé mitmproxy, donc la propre connexion upstream de mitmproxy est renvoyée vers elle-même. Lancez mitmproxy dans un terminal propre, ou exécutez unset HTTP_PROXY HTTPS_PROXY avant de le démarrer.

Les requêtes réussissent mais l'IP de sortie ne change jamais

Le mode pass-through ne fait rien tourner de lui-même. Le comportement de rotation est déterminé par le type de session que vous avez configuré dans votre tableau de bord et par la façon dont votre client ouvre les connexions. Vérifiez que vous n'épinglez pas une seule session sticky sur toute l'exécution, et contrôlez l'IP de sortie avec la commande de l'étape 5.

L'émulateur ignore le proxy

Sur les émulateurs Android, 127.0.0.1 fait référence à l'émulateur lui-même, pas au Mac. Utilisez 10.0.2.2 et confirmez la valeur avec adb shell settings get global http_proxy.

Les cibles renvoient 403 ou 429

Il s'agit d'une limitation de débit à la destination, pas d'une défaillance du proxy. Réduisez la limite du gate dans gate.py, ajoutez des délais entre les requêtes et assurez-vous que votre scraping respecte les conditions du site et robots.txt.

Résumé

Vous disposez maintenant d'un unique écouteur mitmproxy local sur macOS qui transfère n'importe quel client vers les proxys résidentiels ou mobiles Dataimpulse via HTTP ou SOCKS5, avec un mode pass-through pour une rotation d'IP simple et une interception sélective pour une inspection plus poussée. Les identifiants sont stockés dans des variables d'environnement, la concurrence est plafonnée par un addon, et la confiance dans le certificat peut être ajoutée ou retirée proprement lorsque vous n'avez plus besoin de lire le trafic chiffré.