پروکسی Selenium در Python: Chrome، Edge، احراز هویت و SOCKS5

تاریخ انتشار:

17 دقیقه مطالعه

به‌روزرسانی:

PXNET
نویسنده: PXNET
زمینه سیاه با سطرهای محو IP؛ در قابی گوشه‌به‌علاوه: چپ Proxynet، راست ⁨Selenium⁩، ضربدری میانشان و برچسب INTEGRATION
فهرست مطالب

اسکریپت Selenium شما کار می‌کند، اما حالا باید صفحه‌ها را همان‌طور ببینید که یک بازدیدکننده در آلمان می‌بیند، یا کار باید از سروری اجرا شود که سایت مقصد از قبل برایش محدودیت نرخ گذاشته است. پروکسی را اضافه می‌کنید و به‌جای نتیجه، صفحه‌ای خالی می‌گیرید، بی هیچ پیغام خطایی. علت معمولاً رمز است: استاندارد WebDriver هیچ فیلدی برای نام کاربری و رمز پروکسی ندارد، پس user:pass@host:port یا رد می‌شود یا بی‌صدا نادیده گرفته می‌شود.

این راهنما تنظیم پروکسی در Selenium (سلنیوم) را برای Chrome، Edge و Firefox شرح می‌دهد: روش‌های احراز هویتی که امروز کار می‌کنند، SOCKS5، سایت‌های HTTPS، چرخش IP و پیام‌های خطا. همه نمونه‌های Python با ⁦Selenium 4.49⁩، ⁦Chrome 154⁩، ⁦Edge 153⁩ و ⁦Firefox 156⁩ روی ⁦Windows 11⁩ اجرا شده‌اند، در برابر یک پروکسی آزمایشی محلی که نام کاربری و رمز می‌خواهد.

Selenium چیست؟

Selenium مرورگرها را از طریق کد و به‌صورت خودکار کنترل می‌کند. بیشتر برای آزمودن برنامه‌های وب به کار می‌رود، اما برای جمع‌آوری داده از صفحه‌هایی که فقط با JavaScript کامل نمایش داده می‌شوند هم مناسب است. درست مثل یک کاربر، پنجره باز می‌کند، صفحه بار می‌کند، کلیک می‌کند، متن می‌نویسد، فرم می‌فرستد و محتوای صفحه را می‌خواند. کد شما کتابخانه Selenium را فرا می‌خواند، کتابخانه با یک درایور (ChromeDriver، msedgedriver یا geckodriver) حرف می‌زند و درایور از راه پروتکل ⁦W3C WebDriver⁩ مرورگر را می‌گرداند.

از مرورگرهای رایج پشتیبانی می‌کند، یعنی Chrome، Edge، Firefox و Safari، و کتابخانه‌های رسمی آن برای Python، Java، C#، Ruby و JavaScript در دسترس‌اند. از نسخه 4.6 به بعد، Selenium Manager همراه Selenium عرضه می‌شود؛ این ابزار مرورگر نصب‌شده را پیدا می‌کند و درایور مناسب آن را دانلود می‌کند. هنوز میان ابزارها مردد هستید؟ تفاوت Playwright و Selenium: کدام را انتخاب کنیم؟ را ببینید.

پروکسی در Selenium چگونه کار می‌کند؟

در Selenium پروکسی به نشست مرورگر تعلق دارد، نه به یک درخواست تکی:

  1. پروکسی را در گزینه‌های مرورگر می‌گذارید: به شکل آرگومان Chrome یعنی --proxy-server، یا به شکل شیء Proxy (قابلیت proxy در استاندارد WebDriver).
  2. درایور مرورگر را با همین تنظیم راه می‌اندازد و این تنظیم تا driver.quit() روی همه زبانه‌ها اعمال می‌شود.
  3. برای صفحه https:// مرورگر درخواست CONNECT host:443 را به پروکسی می‌فرستد و یک تونل رمزگذاری‌شده باز می‌کند. برای صفحه http:// نشانی کامل را به پروکسی می‌دهد.
  4. اگر پروکسی ورود بخواهد، پاسخ ⁦407 Proxy Authentication Required⁩ برمی‌گرداند. این همان مرحله‌ای است که استاندارد WebDriver پوشش نمی‌دهد.
  5. سایت مقصد IP خروجی پروکسی را می‌بیند. برای پروکسی دیگر، باید مرورگر تازه‌ای راه بیندازید.

Chrome ترافیک پس‌زمینه خودش (به‌روزرسانی‌ها و سرویس‌های حساب) را هم از پروکسی عبور می‌دهد و در پلنی که بر اساس گیگابایت حساب می‌شود، این ترافیک هم در مصرف شمرده می‌شود.

چگونه در Python از Selenium با پروکسی استفاده کنیم؟

گام 1: نصب Selenium. ⁦Selenium 4.49⁩ به ⁦Python 3.10⁩ یا جدیدتر نیاز دارد:

bash
pip install selenium

گام 2: تهیه پروکسی. سرویس مناسب خود را از صفحه پروکسی انتخاب کنید. بخش «Endpoint Generator» در پنل کاربری Proxynet نشانی گیت‌وی، پورت و نام کاربری‌ای را به شما می‌دهد که کشور، شهر و نشست انتخابی شما را در خود دارد. HTTP و SOCKS5 روی همان گیت‌وی اما با پورت‌های جداگانه کار می‌کنند.

گام 3: آماده کردن درایور. از نسخه 4.6 به بعد، Selenium Manager در نخستین اجرا خودش درایور مناسب را دانلود می‌کند؛ نصب دستی ChromeDriver فقط در نسخه‌های قدیمی‌تر لازم بود. پارامتر executable_path که در آموزش‌های قدیمی می‌بینید هم دیگر وجود ندارد. اگر رایانه برای دسترسی به اینترنت خودش به پروکسی نیاز دارد، متغیر SE_PROXY را برای دانلودهای Selenium Manager تنظیم کنید.

گام 4: راه‌اندازی مرورگر با پروکسی. برای پروکسی‌ای که رمز نمی‌خواهد (لیست سفید IP، که پایین‌تر توضیح داده شده):

python
from selenium import webdriver
from selenium.webdriver.common.by import By

PROXY = "http://pr.proxynet.io:8000"

options = webdriver.ChromeOptions()
options.add_argument(f"--proxy-server={PROXY}")
options.add_argument("--headless")  # remove to watch the browser

driver = webdriver.Chrome(options=options)
try:
    driver.get("https://api.ipify.org/?format=json")
    print(driver.find_element(By.TAG_NAME, "body").text)  # {"ip": "<exit IP>"}
finally:
    driver.quit()

به‌جای pr.proxynet.io:8000 نام میزبان و پورتی را که در پنل Proxynet دارید بگذارید. IP چاپ‌شده باید IP خروجی پروکسی باشد. شیء Proxy در Selenium هم همین کار را انجام می‌دهد (options.proxy = Proxy({"proxyType": ProxyType.MANUAL, "httpProxy": "host:port", "sslProxy": "host:port"})) و در آزمایش ما هر دو روش ترافیک را به یک صورت از پروکسی عبور دادند.

چگونه در Selenium از پروکسی با نام کاربری و رمز استفاده کنیم؟

تعریف پروکسی در استاندارد ⁦W3C WebDriver⁩ برای نشانی پروکسی کلید دارد، اما برای نام کاربری یا رمز هیچ کلیدی ندارد. مستندات پروکسی Chromium هم می‌گوید Chrome از نام کاربری و رمزی که در تنظیمات پروکسی جاسازی شده باشد استفاده نمی‌کند. آرگومانی به نام --proxy-auth هم وجود ندارد، هرچند در برخی آموزش‌های قدیمی آمده است. نتیجه آزمایش‌های ما با پروکسی‌ای که ورود می‌خواهد:

آنچه امتحان کردیمنتیجه
--proxy-server=http://host:port بدون نام کاربری و رمزپروکسی 407 برگرداند؛ هیچ استثنایی (exception) رخ نداد و صفحه خالی ماند
--proxy-server=http://user:pass@host:portصفحه خطای ERR_NO_SUPPORTED_PROXIES، بدون استثنا
user:pass@host:port در شیء Proxyصفحه بار شد، اما Chrome مستقیم و با IP خود ما وصل شد
driver.network.add_auth_handler() در Selenium BiDi، با Chromeپاسخ به چالش با خطای Invalid InterceptionId شکست خورد و سپس زمان انتظار به پایان رسید
Fetch.continueWithAuth در CDP (تابع کمکی پایین)در ⁦Chrome 154⁩ و ⁦Edge 153⁩ کار کرد
پورت بدون ورود (لیست سفید IP)کار کرد

ردیف سوم همان ردیف خطرناک است: اسکریپت ظاهراً کار می‌کند، در حالی که ترافیک اصلاً از پروکسی عبور نمی‌کند.

راه 1: لیست سفید IP

IP عمومی رایانه‌ای را که اسکریپت روی آن اجرا می‌شود در فهرست مجاز پروکسی ثبت کنید تا پروکسی دیگر رمز نخواهد. آنگاه کد گام 4 بدون تغییر کار می‌کند و نسخه‌های Edge و Firefox هم همین‌طور. Proxynet تا 10 آدرس IP را می‌پذیرد. این روش برای سروری با IP ثابت مناسب است، نه لپ‌تاپی که IP آن مدام عوض می‌شود؛ احراز هویت پروکسی: نام کاربری و رمز یا لیست سفید IP را ببینید.

راه 2: پاسخ به 407 از طریق Chrome DevTools Protocol

Chrome و Edge دامنه Fetch در DevTools Protocol را در اختیار می‌گذارند. وقتی handleAuthRequests روشن باشد، مرورگر درخواستی را که به نام کاربری و رمز نیاز دارد نگه می‌دارد و رویداد Fetch.authRequired را می‌فرستد که مقدار source آن Server یا Proxy است. تابع کمکی زیر فقط به چالش‌های پروکسی پاسخ می‌دهد؛ بسته websocket-client همراه Selenium نصب می‌شود.

python
# proxy_auth.py
import json
import threading
import urllib.request

import websocket  # installed together with selenium (websocket-client)


def attach_proxy_auth(driver, username, password):
    """Answers the tab's proxy 407 challenges over the Chrome DevTools Protocol."""
    caps = driver.capabilities
    vendor = caps.get("goog:chromeOptions") or caps.get("ms:edgeOptions")  # Chrome or Edge
    address = vendor["debuggerAddress"]
    with urllib.request.urlopen(f"http://{address}/json") as resp:
        targets = json.load(resp)
    page = next(t for t in targets if t["type"] == "page")
    ws = websocket.create_connection(page["webSocketDebuggerUrl"], suppress_origin=True)

    counter = {"id": 0}

    def send(method, params=None):
        counter["id"] += 1
        ws.send(json.dumps({"id": counter["id"], "method": method, "params": params or {}}))

    def listen():
        while True:
            try:
                msg = json.loads(ws.recv())
            except Exception:
                return  # the browser was closed
            method = msg.get("method")
            params = msg.get("params", {})
            if method == "Fetch.requestPaused":
                send("Fetch.continueRequest", {"requestId": params["requestId"]})
            elif method == "Fetch.authRequired":
                if params["authChallenge"]["source"] == "Proxy":
                    answer = {"response": "ProvideCredentials",
                              "username": username, "password": password}
                else:
                    answer = {"response": "Default"}  # the site's own login is not ours to answer
                send("Fetch.continueWithAuth", {"requestId": params["requestId"],
                                                "authChallengeResponse": answer})

    send("Fetch.enable", {"handleAuthRequests": True})
    while json.loads(ws.recv()).get("id") != counter["id"]:
        pass  # wait until interception is active before the first driver.get()
    threading.Thread(target=listen, daemon=True).start()
    return ws

برای استفاده از آن، پس از راه‌اندازی درایور فقط یک خط لازم است:

python
from selenium import webdriver
from proxy_auth import attach_proxy_auth

options = webdriver.ChromeOptions()
options.add_argument("--proxy-server=http://pr.proxynet.io:8000")
driver = webdriver.Chrome(options=options)
attach_proxy_auth(driver, "user", "pass")
driver.get("https://api.ipify.org/?format=json")

محدودیت‌ها: تابع کمکی فقط زبانه‌ای را پوشش می‌دهد که به آن وصل شده است، پس پنجره تازه بدون آن شروع می‌شود. با رمز اشتباه، Chrome خطای ERR_TOO_MANY_RETRIES را نشان می‌دهد.

Selenium Wire و افزونه‌های پروکسی چه وضعی دارند؟

مخزن Selenium Wire در 3 ژانویه 2024 بایگانی شد و در یک محیط تازه ⁦Python 3.13⁩ دستور from seleniumwire import webdriver برای ما با خطای ModuleNotFoundError: No module named 'pkg_resources' شکست خورد. افزونه‌های احراز هویت به سوئیچ --load-extension وابسته بودند که نسخه‌های رسمی Chrome از نسخه 137 به بعد آن را نادیده می‌گیرند؛ فقط Chrome for Testing و Chromium هنوز آن را می‌پذیرند. SeleniumBase مقدار proxy="user:pass@host:port" را می‌پذیرد و ورود را خودش انجام می‌دهد؛ پروکسی با SeleniumBase: احراز هویت و چرخش را ببینید.

در Selenium از کدام روش پروکسی استفاده کنیم؟

روشChrome / EdgeFirefoxرمزوضعیت در 2026
آرگومان --proxy-serverبلهخیر، از ترجیحات شبکه استفاده کنیدخیرپشتیبانی‌شده
شیء Proxyبلهبلهنادیده گرفته می‌شودپشتیبانی‌شده
لیست سفید IPبلهبلهلازم نیستپشتیبانی‌شده
تابع کمکی CDPبلهخیربلهآزموده‌شده، کار می‌کند
add_auth_handler در BiDiدر Chrome شکست خوردخطای پنجره وروددر تئوریهنوز قابل اتکا نیست
Selenium Wireimport شکست می‌خوردimport شکست می‌خوردبلهبایگانی‌شده
افزونه احراز هویتفقط Chrome for Testingقالب جداگانهبلهاز نسخه 137 در Chrome از کار افتاده

در Selenium چگونه برای Microsoft Edge پروکسی تنظیم کنیم؟

Edge بر پایه Chromium ساخته شده است، پس EdgeOptions همان آرگومان را می‌پذیرد و Selenium Manager درایور msedgedriver را دانلود می‌کند:

python
from selenium import webdriver

options = webdriver.EdgeOptions()
options.add_argument("--proxy-server=http://pr.proxynet.io:8000")
driver = webdriver.Edge(options=options)

تابع کمکی CDP با Edge هم کار می‌کند؛ با ⁦Edge 153⁩ و پروکسی آزمایشی رمزدار، صفحه از مسیر پروکسی بار شد.

چگونه در Selenium با Firefox پروکسی تنظیم کنیم؟

Firefox آرگومان --proxy-server را نمی‌خواند. ترجیحات شبکه (preferences) آن را تنظیم کنید، یا شیء Proxy را بدهید که geckodriver آن را به همین ترجیحات تبدیل می‌کند. Firefox روی رایانه آزمایشی ما نصب نبود؛ Selenium Manager در نخستین اجرا ⁦Firefox 156⁩ را دانلود کرد.

python
from selenium import webdriver

options = webdriver.FirefoxOptions()
options.set_preference("network.proxy.type", 1)  # 1 = manual configuration
options.set_preference("network.proxy.http", "pr.proxynet.io")
options.set_preference("network.proxy.http_port", 8000)
options.set_preference("network.proxy.ssl", "pr.proxynet.io")  # used for https:// pages
options.set_preference("network.proxy.ssl_port", 8000)
driver = webdriver.Firefox(options=options)

برای SOCKS5، ترجیح‌های network.proxy.socks و network.proxy.socks_port را تنظیم کنید و network.proxy.socks_version را روی 5 بگذارید. در این حالت Firefox نام دامنه را به پروکسی می‌فرستد، چون network.proxy.socks5_remote_dns به‌طور پیش‌فرض روشن است. ترجیح قدیمی‌تر network.proxy.socks_remote_dns که هنوز در بسیاری از آموزش‌ها دیده می‌شود، در ⁦Firefox 156⁩ برای SOCKS5 هیچ اثری نداشت، اما وقتی socks5_remote_dns را روی False گذاشتیم، Firefox نام‌ها را روی رایانه خودمان به IP تبدیل کرد. Firefox هیچ ترجیحی برای نام کاربری و رمز پروکسی ندارد و تابع کمکی CDP هم روی آن کار نمی‌کند. add_auth_handler در Selenium BiDi نام کاربری و رمز ما را فرستاد، اما بارگذاری صفحه به خاطر پنجره ورود پروکسی باز هم با UnexpectedAlertPresentException شکست خورد؛ پس در Firefox از لیست سفید IP استفاده کنید.

آیا Selenium می‌تواند از پروکسی SOCKS5 استفاده کند؟

بله، بدون رمز: --proxy-server=socks5://host:port. در آزمایش ما Chrome نام دامنه را به‌جای تبدیل محلی، به پروکسی فرستاد؛ مستندات Chromium هم تأیید می‌کند که با SOCKS5، تبدیل نام همیشه در سمت پروکسی انجام می‌شود.

با رمز، خیر: Chromium از احراز هویت SOCKS5 پشتیبانی نمی‌کند و driver.get() خطای net::ERR_SOCKS_CONNECTION_FAILED داد. تابع کمکی CDP هم کمکی نمی‌کند، چون SOCKS اصلاً پاسخ 407 ندارد که بتوان به آن جواب داد. از پورت SOCKS5 با لیست سفید یا از پورت HTTP با تابع کمکی استفاده کنید. توضیح بیشتر در پروکسی SOCKS5 چیست؟ نحوه کار و تفاوت SOCKS4 و SOCKS5 و تفاوت پروکسی SOCKS و HTTP: کدام را انتخاب کنیم؟ آمده است؛ پروکسی SOCKS5 در Proxynet روی پورت جداگانه همان گیت‌وی کار می‌کند.

آیا Selenium از طریق پروکسی با سایت‌های HTTPS کار می‌کند؟

بله. نشانی پروکسی حتی وقتی همه صفحه‌ها https:// هستند طرح http:// را نگه می‌دارد: مرورگر یک تونل CONNECT باز می‌کند و TLS از یک سر تا سر دیگر میان مرورگر و سایت برقرار است، پس پروکسی نام میزبان را می‌بیند اما محتوا را نه. به همین دلیل شیء Proxy علاوه بر httpProxy به sslProxy هم نیاز دارد؛ وقتی فقط httpProxy را گذاشتیم، صفحه‌های https:// ما مستقیم و بدون پروکسی رفتند.

طرح https:// در --proxy-server خود اتصال به پروکسی را رمزگذاری می‌کند؛ پروکسی HTTPS را ببینید.

چگونه در Java پروکسی را با Selenium یکپارچه کنیم؟

Java از همان شیء Proxy استفاده می‌کند. اینجا هم همان قاعده برقرار است: نام کاربری و رمز در آدرس پروکسی نوشته نمی‌شود. نمونه‌های رایجی که user:pass@ را در setHttpProxy می‌گذارند، در آزمایش ما باعث شدند Chrome اصلاً از پروکسی عبور نکند؛ برای همین نسخه زیر به لیست سفید IP تکیه می‌کند. این نسخه System.setProperty("webdriver.chrome.driver", …) را هم ندارد، چون Selenium Manager درایور را پیدا می‌کند. ⁦Selenium 4⁩ به ⁦Java 11⁩ یا جدیدتر نیاز دارد.

java
import org.openqa.selenium.Proxy;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public class SeleniumProxyExample {
    public static void main(String[] args) {
        // No credentials here: the machine's IP is on the proxy's whitelist
        String proxyAddress = "pr.proxynet.io:8000";

        Proxy proxy = new Proxy();
        proxy.setHttpProxy(proxyAddress);
        proxy.setSslProxy(proxyAddress);

        ChromeOptions options = new ChromeOptions();
        options.setProxy(proxy);

        // Selenium Manager finds or downloads the matching ChromeDriver
        WebDriver driver = new ChromeDriver(options);
        try {
            driver.get("https://api.ipify.org/?format=json");
            System.out.println(driver.getPageSource());
        } finally {
            driver.quit();
        }
    }
}

options.addArguments("--proxy-server=http://pr.proxynet.io:8000") معادل آرگومان Python است. این نمونه را بر اساس مستندات Selenium نوشته‌ایم و اجرا نکرده‌ایم، چون روی رایانه آزمایشی فقط ⁦Java 8⁩ نصب است.

چگونه در Selenium پروکسی‌های مسکونی را بچرخانیم؟

پروکسی در طول عمر یک مرورگر ثابت است، پس چرخش یعنی راه‌اندازی مرورگر تازه:

  • گیت‌وی چرخشی. با پروکسی چرخشی IP خروجی در سمت گیت‌وی عوض می‌شود و کد شما یک نشانی را نگه می‌دارد. اتصال‌های بارگذاری یک صفحه ممکن است از IPهای متفاوت خارج شوند: برای فهرست محصولات مشکلی نیست، اما برای فرایند ورود به حساب مشکل‌ساز است.
  • نشست ثابت. با پروکسی با نشست ثابت IP به مدت 1 تا 60 دقیقه ثابت می‌ماند. به هر مرورگر نام کاربری نشست خودش را از «Endpoint Generator» بدهید: یک مرورگر، یک نشست، یک IP خروجی.

هر دو حالت با IPهای پروکسی مسکونی کار می‌کنند؛ چرخش IP چیست و چگونه کار می‌کند؟ و چرخاندن پروکسی در Python: راهنما همراه با کد را ببینید. نوع پروکسی هم به مقصد بستگی دارد: IP مسکونی برای مقصدهایی با بررسی سخت‌گیرانه، پروکسی دیتاسنتر برای برداشت‌های سریع از سایت‌های کم‌حساسیت، و پروکسی ISP وقتی کاری چندمرحله‌ای باید بیش از 60 دقیقه روی همان آدرس بماند.

نمونه کامل: مرورگرهای موازی با تلاش دوباره

این اسکریپت شش صفحه از quotes.toscrape.com را می‌خواند، سایتی تمرینی که صفحه‌هایش با JavaScript ساخته می‌شوند. سه نمونه Chrome را هم‌زمان اجرا می‌کند، در هر تلاش مرورگر تازه‌ای راه می‌اندازد، برای صرفه‌جویی در ترافیک تصویرها را مسدود می‌کند و خطاهای موقت را با تأخیر فزاینده دوباره امتحان می‌کند. خطاهایی که تلاش دوباره درستشان نمی‌کند، از جمله خطاهایی که فقط صفحه خطای Chrome را نشان می‌دهند، کار را فوراً متوقف می‌کنند.

python
import random
import re
import time
from concurrent.futures import ThreadPoolExecutor, as_completed

from selenium import webdriver
from selenium.common.exceptions import TimeoutException, WebDriverException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

from proxy_auth import attach_proxy_auth

PROXY_SERVER = "http://pr.proxynet.io:8000"
PROXY_USER = "user"
PROXY_PASS = "pass"
URLS = [f"https://quotes.toscrape.com/js/page/{n}/" for n in range(1, 7)]
WORKERS = 3  # browsers open at the same time
ATTEMPTS = 3
# A retry will not fix these: check the address, port and credentials first
FATAL = ("ERR_PROXY_CONNECTION_FAILED", "ERR_NO_SUPPORTED_PROXIES",
         "ERR_SOCKS_CONNECTION_FAILED", "ERR_TOO_MANY_RETRIES")


def new_driver():
    options = webdriver.ChromeOptions()
    options.add_argument(f"--proxy-server={PROXY_SERVER}")
    options.add_argument("--headless")
    # Skip images: less traffic through the proxy
    options.add_experimental_option("prefs", {"profile.managed_default_content_settings.images": 2})
    driver = webdriver.Chrome(options=options)
    driver.set_page_load_timeout(30)
    attach_proxy_auth(driver, PROXY_USER, PROXY_PASS)
    return driver


def scrape(url):
    for attempt in range(ATTEMPTS):
        driver = new_driver()  # a fresh browser, and a fresh proxy connection, on every attempt
        try:
            driver.get(url)
            # Some proxy errors open Chrome's error page without raising an exception
            if driver.execute_script("return document.body.className") == "neterror":
                code = re.search(r"ERR_[A-Z_]+", driver.page_source)
                raise WebDriverException(code.group(0) if code else "Chrome error page")
            WebDriverWait(driver, 10).until(
                EC.presence_of_element_located((By.CSS_SELECTOR, "div.quote span.text"))
            )
            quotes = driver.find_elements(By.CSS_SELECTOR, "div.quote span.text")
            return url, [q.text for q in quotes]
        except (TimeoutException, WebDriverException) as exc:
            if any(code in str(exc) for code in FATAL) or attempt == ATTEMPTS - 1:
                raise
            time.sleep(2**attempt + random.random())  # exponential backoff with jitter
        finally:
            driver.quit()


with ThreadPoolExecutor(max_workers=WORKERS) as pool:
    futures = [pool.submit(scrape, url) for url in URLS]
    for future in as_completed(futures):
        try:
            url, quotes = future.result()
            print(f"{url}: {len(quotes)} quotes")
        except Exception as exc:
            print("failed:", str(exc).splitlines()[0])

هر شش صفحه در حدود 22 ثانیه، هر کدام 10 نقل‌قول برگرداندند؛ یک پورت بسته همه کارها را با net::ERR_PROXY_CONNECTION_FAILED متوقف کرد و یک رمز اشتباه با ERR_TOO_MANY_RETRIES. مقدار WORKERS را معقول نگه دارید: هر کدام یک Chrome کامل است و نشست‌های موازی بیش از حد به خطای ⁦429 Too Many Requests⁩ می‌انجامند.

چگونه مطمئن شویم Selenium واقعاً از پروکسی استفاده می‌کند؟

در مرورگری که از پروکسی عبور می‌کند، یک صفحه نمایش IP مانند api.ipify.org را باز کنید و نتیجه را با IP خودتان مقایسه کنید؛ اگر یکی باشند، ترافیک از پروکسی عبور نمی‌کند. ترافیک باید در پنل کاربری شما هم دیده شود. WebRTC همچنان می‌تواند IP محلی را فاش کند؛ نشت WebRTC و DNS: چیست و چگونه جلوی آن را بگیریم را ببینید. روال کامل آزمون در آیا پروکسی کار می‌کند؟ چگونه پروکسی را آزمایش کنیم و یک بررسی یک‌خطی در ترمینال در استفاده از cURL با پروکسی آمده است.

خطاهای رایج پروکسی در Selenium و راه رفع آن‌ها

پیام‌ها همان‌طور که در آزمایش‌های ما ظاهر شدند. کدهای Chrome یا در متن استثنا می‌آیند (unknown error: net::ERR_…) یا فقط در صفحه خطا.

پیامعلتراه‌حل
صفحه خالی، driver.title خالی، بدون استثناپروکسی 407 برگرداند و نام کاربری و رمزی فرستاده نشدIP را در لیست سفید بگذارید یا از تابع کمکی CDP استفاده کنید
ERR_NO_SUPPORTED_PROXIES (صفحه خطا)نام کاربری و رمز داخل --proxy-serveruser:pass@ را از آرگومان حذف کنید
net::ERR_PROXY_CONNECTION_FAILEDروی آن میزبان و پورت چیزی گوش نمی‌دهدنشانی، پورت و فایروال را بررسی کنید
net::ERR_TUNNEL_CONNECTION_FAILEDپروکسی نتوانست تونل را باز کنداول میزبان مقصد و بعد پروکسی را بررسی کنید
net::ERR_SOCKS_CONNECTION_FAILEDپروکسی SOCKS5 رمز می‌خواهدپورت HTTP با تابع کمکی، یا لیست سفید
ERR_TOO_MANY_RETRIES (صفحه خطا)پروکسی نام کاربری و رمز تابع کمکی را نپذیرفتنام کاربری و رمز را دوباره کپی کنید
TypeError: WebDriver.__init__() got an unexpected keyword argument 'executable_path'کد نوشته‌شده برای ⁦Selenium 3⁩آن را حذف کنید؛ Selenium Manager درایور را پیدا می‌کند
… unexpected keyword argument 'chrome_options'همان مشکل، با نام قدیمی‌تراز options= استفاده کنید
Timed out receiving message from rendererبارگذاری صفحه هیچ‌وقت تمام نشدپروکسی را بررسی کنید، سپس دوباره امتحان کنید

خطاهای اتصال در کلاینت‌های HTTP ساده Python را سطر به سطر در خطای Max Retries Exceeded With URL چیست و چگونه رفع می‌شود؟ خوانده‌ایم.

کاربردها

پروکسی جایی را که درخواست از آن می‌آید عوض می‌کند، نه آنچه سایت اجازه می‌دهد: robots.txt و شرایط استفاده سایت را بخوانید، نرخ درخواست را پایین نگه دارید و اگر API رسمی وجود دارد آن را ترجیح دهید. پروکسی خودکارسازی را هم پنهان نمی‌کند؛ مرورگری که زیر کنترل WebDriver است، همان‌طور که استاندارد می‌خواهد، مقدار navigator.webdriver را true گزارش می‌کند.

راهنمای انتخاب

نیازپیشنهاد
سرور با IP ثابتلیست سفید IP + --proxy-server، بدون رمز در کد
لپ‌تاپ یا CI runner با IP متغیرپورت HTTP + تابع کمکی CDP
Firefoxترجیحات شبکه + لیست سفید IP
SOCKS5socks5:// در --proxy-server، فقط با لیست سفید
فرایند ورود به حساب یا پرداختنشست ثابت، یک مرورگر برای هر نشست
صفحه‌های مستقل زیادگیت‌وی چرخشی
پروکسی متفاوت برای هر صفحه در یک مرورگرپروکسی جداگانه برای هر context در Playwright؛ Playwright چیست و چگونه با پروکسی استفاده می‌شود؟

پرسش‌های متداول

آیا Selenium می‌تواند از پروکسی با نام کاربری و رمز استفاده کند؟

نه از راه گزینه‌های استاندارد، چون این گزینه‌ها فیلدی برای نام کاربری و رمز ندارند. در Chrome و Edge تابع کمکی DevTools همین نوشته به 407 پروکسی پاسخ می‌دهد؛ در هر مرورگری هم لیست سفید IP نیاز به رمز را از میان برمی‌دارد.

آیا Selenium Wire در 2026 هنوز کار می‌کند؟

این کتابخانه در 3 ژانویه 2024 بایگانی شد و در یک محیط تازه ⁦Python 3.13⁩ برای ما import نشد، چون به pkg_resources وابسته است که نسخه‌های فعلی setuptools دیگر آن را همراه ندارند. از تابع کمکی یا لیست سفید استفاده کنید.

چگونه بدون بستن مرورگر پروکسی را عوض کنیم؟

پروکسی هنگام شروع نشست ثابت می‌شود: driver.quit() را فراخوانی کنید و درایور تازه‌ای راه بیندازید. برای IP تازه در هر صفحه درون یک مرورگر، از گیت‌وی چرخشی استفاده کنید، یا از Playwright که برای هر context پروکسی جداگانه می‌پذیرد.

آیا پروکسی در حالت headless کار می‌کند؟

بله. --proxy-server و تابع کمکی CDP با --headless و بدون آن یکسان رفتار می‌کنند؛ همه نمونه‌های این نوشته در حالت headless اجرا شدند.

آیا در Selenium می‌توان از پروکسی SOCKS5 با احراز هویت استفاده کرد؟

در Chrome و Edge نه، چون از احراز هویت SOCKS5 پشتیبانی نمی‌کنند؛ ⁦Firefox 156⁩ هم به پروکسی ما فقط روش بدون رمز را پیشنهاد داد. SOCKS5 را با لیست سفید به کار ببرید، یا پورت HTTP را با رمز.

چرا سایت هنوز IP واقعی من را نشان می‌دهد؟

معمولاً پروکسی اصلاً اعمال نشده است: نام کاربری و رمز داخل شیء Proxy باعث می‌شود Chrome مستقیم وصل شود، و شیء Proxy بدون sslProxy صفحه‌های https:// را بدون پروکسی رها می‌کند. اگر IP درست است اما موقعیت نادرست به نظر می‌رسد، نشت WebRTC را آزمایش کنید.

خلاصه

Selenium پروکسی را یک بار برای هر نشست مرورگر تنظیم می‌کند: --proxy-server برای Chrome و Edge، و ترجیحات شبکه یا شیء Proxy برای Firefox. برای احراز هویت از لیست سفید IP استفاده کنید یا در Chrome و Edge از تابع کمکی DevTools که به 407 پاسخ می‌دهد؛ Selenium Wire و افزونه‌هایی که از خط فرمان بارگذاری می‌شوند به بن‌بست رسیده‌اند. SOCKS5 فقط بدون رمز کار می‌کند و چرخش یعنی یک مرورگر برای هر IP یا نشست. وقتی راه‌اندازی آماده شد، پلن خود را از صفحه پروکسی Proxynet انتخاب کنید و مشخصات گیت‌وی را از «Endpoint Generator» بردارید.

پرسش از ChatGPTپرسش از Claude