---
title: "پروکسی Selenium در Python: Chrome، Edge، احراز هویت و SOCKS5"
description: "برای استفاده از پروکسی در Selenium، ⁦--proxy-server⁩ را به ChromeOptions یا EdgeOptions بدهید. احراز هویت با CDP، SOCKS5، Firefox، Java و چرخش IP هم آمده است."
url: https://proxynet.io/fa/blog/selenium
date: 2024-04-23
updated: 2026-09-25
author: "PXNET"
category: "یکپارچه‌سازی"
lang: fa
---

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

اسکریپت 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⁩ اجرا شده‌اند، در برابر یک پروکسی آزمایشی محلی که نام کاربری و رمز می‌خواهد.

> **نکته: پاسخ کوتاه**
>
> آرگومان `--proxy-server=http://host:port` را به `ChromeOptions` (یا `EdgeOptions`) اضافه کنید و درایور را با همین گزینه‌ها راه بیندازید. Chrome نام کاربری و رمزی را که در این نشانی بنویسید نادیده می‌گیرد، پس یا IP سرور خود را در لیست سفید پروکسی ثبت کنید، یا به چالش `407` پروکسی از طریق Chrome DevTools Protocol با تابع کمکی کوتاهی که پایین‌تر آمده پاسخ دهید. Selenium Wire بایگانی شده و Chrome از نسخه 137 به بعد افزونه‌هایی را که از خط فرمان بارگذاری می‌شوند نادیده می‌گیرد، پس دستورالعمل‌های قدیمی دیگر کار نمی‌کنند.

## Selenium چیست؟

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

از مرورگرهای رایج پشتیبانی می‌کند، یعنی Chrome، Edge، Firefox و Safari، و کتابخانه‌های رسمی آن برای Python، Java، C#، Ruby و JavaScript در دسترس‌اند. از نسخه 4.6 به بعد، [Selenium Manager](https://www.selenium.dev/documentation/selenium_manager/) همراه Selenium عرضه می‌شود؛ این ابزار مرورگر نصب‌شده را پیدا می‌کند و درایور مناسب آن را دانلود می‌کند. هنوز میان ابزارها مردد هستید؟ [تفاوت Playwright و Selenium: کدام را انتخاب کنیم؟](/fa/blog/playwright-vs-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: تهیه پروکسی.** سرویس مناسب خود را از [صفحه پروکسی](/fa/proxy) انتخاب کنید. بخش «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⁩](https://www.w3.org/TR/webdriver2/#proxy) برای نشانی پروکسی کلید دارد، اما برای نام کاربری یا رمز هیچ کلیدی ندارد. [مستندات پروکسی Chromium](https://chromium.googlesource.com/chromium/src/+/HEAD/net/docs/proxy.md) هم می‌گوید 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](/fa/blog/proxy-authentication-methods) را ببینید.

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

Chrome و Edge [دامنه Fetch در DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/tot/Fetch/) را در اختیار می‌گذارند. وقتی `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](https://github.com/wkeeling/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: احراز هویت و چرخش](/fa/blog/how-to-use-proxy-with-seleniumbase) را ببینید.

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

| روش | Chrome / Edge | Firefox | رمز | وضعیت در 2026 |
|---|---|---|---|---|
| آرگومان `--proxy-server` | بله | خیر، از ترجیحات شبکه استفاده کنید | خیر | پشتیبانی‌شده |
| شیء `Proxy` | بله | بله | نادیده گرفته می‌شود | پشتیبانی‌شده |
| لیست سفید IP | بله | بله | لازم نیست | پشتیبانی‌شده |
| تابع کمکی CDP | بله | خیر | بله | آزموده‌شده، کار می‌کند |
| `add_auth_handler` در BiDi | در Chrome شکست خورد | خطای پنجره ورود | در تئوری | هنوز قابل اتکا نیست |
| Selenium Wire | import شکست می‌خورد | 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](/fa/blog/socks5-proxy-101) و [تفاوت پروکسی SOCKS و HTTP: کدام را انتخاب کنیم؟](/fa/blog/socks-vs-http-proxy) آمده است؛ [پروکسی SOCKS5](https://proxynet.io/fa/socks5-proxy) در Proxynet روی پورت جداگانه همان گیت‌وی کار می‌کند.

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

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

طرح `https://` در `--proxy-server` خود اتصال به پروکسی را رمزگذاری می‌کند؛ [پروکسی HTTPS](https://proxynet.io/fa/https-proxy) را ببینید.

## چگونه در 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 پروکسی‌های مسکونی را بچرخانیم؟

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

- **گیت‌وی چرخشی.** با [پروکسی چرخشی](https://proxynet.io/fa/rotating-proxy) IP خروجی در سمت گیت‌وی عوض می‌شود و کد شما یک نشانی را نگه می‌دارد. اتصال‌های بارگذاری یک صفحه ممکن است از IPهای متفاوت خارج شوند: برای فهرست محصولات مشکلی نیست، اما برای فرایند ورود به حساب مشکل‌ساز است.
- **نشست ثابت.** با [پروکسی با نشست ثابت](https://proxynet.io/fa/sticky-proxy) IP به مدت 1 تا 60 دقیقه ثابت می‌ماند. به هر مرورگر نام کاربری نشست خودش را از «Endpoint Generator» بدهید: یک مرورگر، یک نشست، یک IP خروجی.

هر دو حالت با IPهای [پروکسی مسکونی](https://proxynet.io/fa/residential-proxy) کار می‌کنند؛ [چرخش IP چیست و چگونه کار می‌کند؟](/fa/blog/ip-rotation-explained) و [چرخاندن پروکسی در Python: راهنما همراه با کد](/fa/blog/how-to-rotate-proxies-in-python) را ببینید. نوع پروکسی هم به مقصد بستگی دارد: IP مسکونی برای مقصدهایی با بررسی سخت‌گیرانه، [پروکسی دیتاسنتر](https://proxynet.io/fa/datacenter-proxy) برای برداشت‌های سریع از سایت‌های کم‌حساسیت، و [پروکسی ISP](https://proxynet.io/fa/static-isp-residential-proxy) وقتی کاری چندمرحله‌ای باید بیش از 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⁩](/fa/blog/http-429-too-many-requests) می‌انجامند.

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

در مرورگری که از پروکسی عبور می‌کند، یک صفحه نمایش IP مانند `api.ipify.org` را باز کنید و نتیجه را با IP خودتان مقایسه کنید؛ اگر یکی باشند، ترافیک از پروکسی عبور نمی‌کند. ترافیک باید در پنل کاربری شما هم دیده شود. WebRTC همچنان می‌تواند IP محلی را فاش کند؛ [نشت WebRTC و DNS: چیست و چگونه جلوی آن را بگیریم](/fa/blog/webrtc-dns-leak) را ببینید. روال کامل آزمون در [آیا پروکسی کار می‌کند؟ چگونه پروکسی را آزمایش کنیم](/fa/blog/how-to-test-a-proxy) و یک بررسی یک‌خطی در ترمینال در [استفاده از cURL با پروکسی](/fa/blog/curl-proxy) آمده است.

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

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

| پیام | علت | راه‌حل |
|---|---|---|
| صفحه خالی، `driver.title` خالی، بدون استثنا | پروکسی `407` برگرداند و نام کاربری و رمزی فرستاده نشد | IP را در لیست سفید بگذارید یا از تابع کمکی CDP استفاده کنید |
| `ERR_NO_SUPPORTED_PROXIES` (صفحه خطا) | نام کاربری و رمز داخل `--proxy-server` | `user: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 چیست و چگونه رفع می‌شود؟](/fa/blog/max-retries-exceeded-with-url) خوانده‌ایم.

## کاربردها

- **رصد قیمت** در فروشگاه‌هایی که به JavaScript وابسته‌اند، از همان بازاری که در آن می‌فروشید: [رصد قیمت رقبا در فروشگاه اینترنتی](/fa/blog/competitor-price-tracking) و [رصد قیمت](/fa/price-monitoring).
- **بومی‌سازی و QA**: بارگذاری سایت خودتان از چند کشور پیش از انتشار؛ [تست اپلیکیشن](/fa/app-testing) را ببینید.
- **راستی‌آزمایی تبلیغات**: بررسی آگهی‌های خودتان در منطقه‌هایی که برایشان هزینه می‌کنید؛ [راستی‌آزمایی تبلیغات](/fa/ad-verification) را ببینید.
- **جمع‌آوری داده** از صفحه‌هایی که به JavaScript نیاز دارند: [استخراج داده](/fa/data-scraping).

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

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

| نیاز | پیشنهاد |
|---|---|
| سرور با IP ثابت | لیست سفید IP + `--proxy-server`، بدون رمز در کد |
| لپ‌تاپ یا CI runner با IP متغیر | پورت HTTP + تابع کمکی CDP |
| Firefox | ترجیحات شبکه + لیست سفید IP |
| SOCKS5 | `socks5://` در `--proxy-server`، فقط با لیست سفید |
| فرایند ورود به حساب یا پرداخت | نشست ثابت، یک مرورگر برای هر نشست |
| صفحه‌های مستقل زیاد | گیت‌وی چرخشی |
| پروکسی متفاوت برای هر صفحه در یک مرورگر | پروکسی جداگانه برای هر context در Playwright؛ [Playwright چیست و چگونه با پروکسی استفاده می‌شود؟](/fa/blog/playwright-proxy) |

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

### آیا 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](/fa/proxy) انتخاب کنید و مشخصات گیت‌وی را از «Endpoint Generator» بردارید.
