Szybka odpowiedź
Jak używać proxy z użytkownikiem i hasłem w Selenium?
Uruchom mały lokalny forwarder, który dodaje nagłówek Proxy-Authorization i skieruj Chrome na niego przez --proxy-server=http://127.0.0.1:8899. Chrome ignoruje dane uwierzytelniające w tej fladze, a Selenium nie ma przenośnej opcji dla haseł do proxy. CrawlRelay mobilne proxy 4G działają właśnie tak, z gw.crawlrelay.com:7777, z 0,50 USD/GB. Płatne kryptowalutami, bez KYC.
Szybka konfiguracja Selenium
| Dlaczego forwarder | Flaga --proxy-server Chrome nie przyjmuje nazwy użytkownika ani hasła |
|---|---|
| Forwarder | Nasłuchuje na 127.0.0.1:8899, dodaje Proxy-Authorization, przekazuje do gw.crawlrelay.com:7777 |
| Opcja Chrome | --proxy-server=http://127.0.0.1:8899 |
| Rotacja | Każdy nowy tunel CONNECT to nowe połączenie, więc zwykle nowy exit; dodaj ID sesji dla jednego IP |
| Prostsza alternatywa | Playwright pobiera nazwę użytkownika i hasło bezpośrednio |
Jak działa lokalny forwarder?
Akceptuje żądanie proxy z przeglądarki, wstawia jeden nagłówek z Twoimi danymi uwierzytelniającymi, a następnie kopiuje bajty w obu kierunkach. Dla strony HTTPS przeglądarka wysyła CONNECT host:443, brama odpowiada 200 Connection established, a TLS działa end to end między Chrome a witryną. Forwarder nigdy nie widzi treści strony w postaci niezaszyfrowanej.
Ta minimalna wersja obsługuje strony HTTPS, gdzie każde połączenie nosi jeden tunel CONNECT. To obejmuje dziś niemal każdą stronę. Trzymaj go powiązanego z 127.0.0.1, aby żaden inny komputer nie mógł używać Twoich danych.
import asyncio
import base64
import os
UPSTREAM = ("gw.crawlrelay.com", 7777)
USER = os.environ.get("CRAWLRELAY_USER", "USERNAME-country-us")
PASSWORD = os.environ.get("CRAWLRELAY_PASSWORD", "PASSWORD")
AUTH = b"Proxy-Authorization: Basic " + base64.b64encode(("%s:%s" % (USER, PASSWORD)).encode())
async def pipe(reader, writer):
try:
while True:
data = await reader.read(65536)
if not data:
break
writer.write(data)
await writer.drain()
except ConnectionError:
pass
finally:
writer.close()
async def handle(client_reader, client_writer):
try:
head = await client_reader.readuntil(b"\r\n\r\n") # request line and headers from the browser
except asyncio.IncompleteReadError:
client_writer.close()
return
lines = head.split(b"\r\n")
lines.insert(1, AUTH) # add the credentials right after the request line
up_reader, up_writer = await asyncio.open_connection(*UPSTREAM)
up_writer.write(b"\r\n".join(lines))
await up_writer.drain()
await asyncio.gather(pipe(client_reader, up_writer), pipe(up_reader, client_writer))
async def main():
server = await asyncio.start_server(handle, "127.0.0.1", 8899)
async with server:
await server.serve_forever()
if __name__ == "__main__":
asyncio.run(main())Jak skierować Selenium na forwarder?
Uruchom forwarder.py w jednym terminalu, potem uruchom swój skrypt Selenium z lokalnym adresem proxy. Selenium Manager, wbudowany w Selenium 4.6 i nowsze, pobiera odpowiedni ChromeDriver, więc nic więcej nie trzeba instalować.
from selenium import webdriver
from selenium.webdriver.common.by import By
options = webdriver.ChromeOptions()
options.add_argument("--proxy-server=http://127.0.0.1:8899") # the local forwarder
options.add_argument("--headless=new")
driver = webdriver.Chrome(options=options)
try:
driver.set_page_load_timeout(60)
driver.get("https://api.ipify.org")
print("exit IP:", driver.find_element(By.TAG_NAME, "body").text)
finally:
driver.quit()Jak uzyskać jedno IP na sesję Selenium lub nowe IP na każdą stronę?
Forwarder wysyła dowolną nazwę użytkownika, jaką mu podasz, więc zachowanie sesji zależy od tej nazwy:
- Rotacja przy każdym połączeniu: pomiń część dotyczącą sesji (
USERNAME-country-us). Chrome otwiera kilka połączeń na stronę, więc jedna strona może ładować się przez kilka wyjść. - Jedno IP na sesję Selenium: ustaw
CRAWLRELAY_USERnaUSERNAME-country-us-session-run42-ttl-30przed startem forwardera. Każde połączenie wychodzi przez to samo IP do 30 minut; IP może się zmienić wcześniej. - Kilka sesji równocześnie: uruchom jeden forwarder na sesję na różnych lokalnych portach, np. 8899 i 8900, i daj każdemu WebDriver swój port.
A co z selenium-wire lub dodatkami do przeglądarki?
selenium-wire, popularny pakiet, który dodawał uwierzytelnianie proxy przez przechwytywanie ruchu, został archiwizowany przez autora w styczniu 2024 i nie otrzymuje aktualizacji. Dodatek do przeglądarki, który odpowiada na żądanie uwierzytelnienia proxy, też działa, ale musi być zapakowany i załadowany do każdego profilu. Powyższy forwarder nie ma zależności i działa z dowolną przeglądarką sterowaną przez Selenium. W nowych projektach Playwright jest jeszcze prostszy: pobiera nazwę użytkownika i hasło proxy bezpośrednio.
Selenium i proxy: pytania
Dlaczego Chrome pokazuje okno logowania przy moim proxy w Selenium?
Bo proxy żądało danych uwierzytelniających, a Chrome ich nie miał: jego flag --proxy-server przyjmuje tylko host i port. W trybie headless ten sam problem pojawia się jako ERR_TUNNEL_CONNECTION_FAILED. Użyj lokalnego forwardera, który dodaje dane uwierzytelniające, lub przejdź na Playwright, który akceptuje nazwę użytkownika i hasło.
Czy forwarder spowalnia moje scrapowanie?
Raczej nie. Kopiuje bajty między dwoma lokalnymi gniazdami a jednym zdalnym, bez odszyfrowywania czegokolwiek. Czas ładowania strony zależy od proxy rezydencjalnego i od strony docelowej, a nie od forwardera działającego na tej samej maszynie.
Czy mogę użyć Firefox zamiast Chrome z Selenium?
Tak. Ustaw preferencje proxy Firefoxa przez FirefoxOptions: network.proxy.type na 1, a network.proxy.http i network.proxy.ssl na 127.0.0.1 z portem 8899. Trzymaj forwardera na froncie: Firefox pyta o dane uwierzytelniające proxy w dialogu, którego Selenium nie wypełni niezawodnie.
Czy moje hasło jest bezpieczne w forwarderze?
Zostaje na Twoim komputerze dopóki forwarder nasłuchuje na 127.0.0.1, jak w przykładzie. Czytaj je z zmiennych środowiskowych, nigdy nie commituj, i używaj dedykowanego sub-użytkownika z limitem transferu na każdego scrapera, by wyciek hasła nie mógł zassać całego planu.
Daj Selenium wyjście proxy rezydencjalnego
1,50 USD dla 1 GB do testów, 0,50 USD/GB od 50 GB.