# Python Requests 프록시 가이드: 구문, 인증, 회전, 재시도

프록시 딕셔너리는 세 줄의 코드지만, Requests에서의 프록시 오류는 10년간 Stack Overflow를 채웠습니다. 여기 전체 설정 — 구문, 인증, 환경 변수, 회전, 재시도 및 SOCKS5 — 날카로운 모서리가 표시되어 있습니다.

Python Requests는 여전히 스크래핑 및 자동화의 기본 HTTP 클라이언트이며, 프록시에 지시하는 것은 세 줄의 작업입니다: proxies 딕셔너리를 전달하면 모든 요청이 귀하의 IP 대신 프록시의 IP에서 종료됩니다. 그러나 'python requests proxy 작동하지 않음'은 10년 넘게 상위 검색어로 남아 있습니다 — proxies 딕셔너리에 대한 원래 Stack Overflow 질문은 2011년으로 거슬러 올라가며, 상위 답변은 480개 이상의 투표를 받았고 2026년 1월에도 여전히 수정되고 있었습니다. 구문에는 날카로운 모서리가 있습니다: 누락된 스키마는 예외를 발생시키고, https 키 내부의 잘못된 스키마는 SSL 오류를 유발하며, 환경 변수는 코드를 조용히 무시합니다. 이 Python Requests 프록시 가이드는 모든 것을 다룹니다: 구문, 인증, 환경 변수, 회전, 재시도, SOCKS5 및 실제로 발생할 오류들.

## 프록시 딕셔너리: Python Requests 프록시 구문

`proxies` 인수는 프로토콜을 프록시 URL에 매핑합니다. 일반적인 스크래핑을 위해 두 개의 키가 필요합니다 — 하나는 일반 HTTP 대상용, 하나는 HTTPS 대상용 — 그리고 둘 다 일반적으로 동일한 프록시를 가리킵니다:

```python
import requests

proxies = {
    "http": "http://USER:PASS@residentialpremium.quantumproxies.io:8080",
    "https": "http://USER:PASS@residentialpremium.quantumproxies.io:8080",
}

r = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=(5, 30))
print(r.json())  # {'origin': '<proxy exit IP>'}
```

세 가지 규칙은 90%의 설정 실패를 방지합니다:

- **스키마는 필수입니다.** Requests 2.0.0 이후로 `http://` 없는 프록시 URL은 `MissingSchema`를 발생시킵니다. 1.x에서는 `ip:port` 문자열이 작동했지만 2.0이 도입되면서 모든 곳에서 깨졌습니다.
- **`https` 키 내부에 `http://`를 사용하세요.** 키는 대상 프로토콜을 지정하고 값은 프록시에 도달하는 방법을 지정합니다. 프록시는 일반 HTTP를 수용하고 CONNECT 요청을 통해 TLS를 터널링합니다. 거기에 `https://`를 쓰는 것은 `SSLError: UNEXPECTED_EOF_WHILE_READING`의 고전적인 원인입니다.
- **키는 특정 호스트를 대상으로 할 수 있습니다.** `https://api.example.com`과 같은 키는 주어진 프록시를 통해 해당 호스트만 라우팅합니다 — 어려운 도메인을 주거 IP를 통해 보내는 데 유용합니다.

## 프록시 인증: 사용자 이름과 비밀번호

인증된 프록시는 URL에 포함된 HTTP 기본 인증을 사용합니다: `http://USER:PASS@host:port`. 비밀번호에 `@`, `:` 또는 `/`가 포함된 경우, `urllib.parse.quote(password, safe="")`로 먼저 URL 인코딩하세요 — 인코딩되지 않은 특수 문자는 URL을 잘못된 위치에서 분할하여 죽은 프록시처럼 보이는 인증 실패를 초래합니다. `407 Proxy Authentication Required` 응답은 프록시 자체가 귀하를 거부했음을 의미합니다: 잘못된 자격 증명 또는 등록되지 않은 주소에서 호출된 IP 화이트리스트 계획. 두 경우 모두 [407 문제 해결 가이드](https://quantumproxies.io/blog/fix-407-proxy-authentication-required)에서 해부됩니다. 일회성 스크립트를 넘어서는 경우, 프록시를 `Session`에 첨부하세요 — 연결 풀링, 쿠키 지속성 및 모든 것을 구성할 수 있는 한 장소를 얻을 수 있습니다.

```python
import requests

session = requests.Session()
session.proxies = {
    "http": "http://USER:PASS@residentialpremium.quantumproxies.io:8080",
    "https": "http://USER:PASS@residentialpremium.quantumproxies.io:8080",
}
session.headers.update({"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"})

r = session.get("https://httpbin.org/ip", timeout=(5, 30))
print(r.status_code, r.json())
```

## 환경 변수와 trust_env

Requests는 또한 환경에서 프록시 설정을 읽습니다 — curl 및 대부분의 Unix 도구가 존중하는 동일한 변수들: `HTTP_PROXY`, `HTTPS_PROXY`, `ALL_PROXY` 및 `NO_PROXY` (제외할 호스트의 쉼표 목록, 예: `localhost,127.0.0.1,.internal`). 이는 Requests를 내부적으로 사용하는 타사 라이브러리를 코드에 손대지 않고 프록시하는 가장 깔끔한 방법입니다. 우선 순위는 명시적이 암시적을 이깁니다: 호출 시 `proxies=` 인수가 승리하고, 그 다음은 `session.proxies`, 그 다음은 환경입니다. 관련 도구 두 가지는 알아둘 가치가 있습니다: `session.trust_env = False`는 모든 환경 조회를 끕니다 — 회사 프록시 변수가 스크래퍼를 납치할 때의 해결책입니다 — 그리고 `urllib.request.getproxies()`는 Requests가 기대하는 딕셔너리 형태로 OS 수준의 프록시 설정을 반환합니다 (macOS 및 Windows 시스템 구성 포함).

![같은 두 키짜리 proxies 딕셔너리가 세 번의 루프 반복을 회전 게이트웨이의 CONNECT 터널로 보내고, httpbin.org/ip는 매번 다른 origin을 보고합니다: 출구 IP A, B, C. 카드 요약: 딕셔너리는 경로를 고르고, 터널은 대상까지 TLS를 실어 나르며, 게이트웨이는 호출마다 새 출구 IP를 제공합니다.](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1785335141/blog/generated/qp-b9-001-diag1.png)
*딕셔너리는 경로를 선택하고, 게이트웨이는 종료 IP를 제공합니다. 요청별 회전으로, 동일한 두 줄의 구성으로 매 호출마다 새로운 IP를 얻을 수 있습니다.*

## 회전: 하나의 게이트웨이가 프록시 목록을 이깁니다

전통적인 회전 레시피 — IP 목록을 로드하고, 요청별로 `random.choice()`를 사용하고, 죽은 것을 제거하는 — 더 이상 구축할 필요가 없는 기계입니다. 회전 게이트웨이는 서버 측에서 이를 수행합니다: 하나의 엔드포인트를 구성하면 공급자가 매 요청마다 풀에서 새로운 종료 IP를 할당합니다. [회전 주거 프록시](https://quantumproxies.io/rotating-proxies)를 통해 그 풀은 200개 이상의 국가에 걸쳐 90M+ 가구 IP로 구성되어 있어, 천 개의 요청이 천 개의 다른 방문자로 보입니다, 회전 로직 한 줄 없이:

```python
import requests

proxies = {
    "http": "http://USER:PASS@residentialpremium.quantumproxies.io:8080",
    "https": "http://USER:PASS@residentialpremium.quantumproxies.io:8080",
}

for _ in range(3):
    r = requests.get("https://httpbin.org/ip", proxies=proxies, timeout=(5, 30))
    print(r.json()["origin"])  # a different exit IP on each iteration
```

흐름이 여러 요청에 걸쳐 있을 때 — 로그인, 장바구니 추가, 결제 — 요청별 회전은 세션을 깨뜨립니다. 스티키 세션이 이를 해결합니다: 프록시 사용자 이름의 세션 매개변수가 설정된 창 동안 하나의 종료 IP를 고정한 다음 회전합니다. 동일한 엔드포인트, 문자열 하나의 변경. 간단한 루프를 넘어서 확장하는 경우, [httpx 또는 aiohttp를 사용한 비동기 Python](https://quantumproxies.io/blog/python-async-scraping-httpx-aiohttp-proxies)이 처리량을 곱하고, [Scrapy의 미들웨어 시스템](https://quantumproxies.io/blog/scrapy-rotating-proxy-middleware)은 회전, 재시도 및 차단 처리를 프레임워크 구성으로 제공합니다.

## 나쁜 종료를 견디는 재시도 및 시간 초과

프리미엄 풀조차도 때때로 느리거나 죽어가는 종료를 제공합니다, 따라서 프로덕션 코드는 두 가지 보호 장치가 필요합니다: 각 요청에 대한 시간 초과 (Requests는 기본적으로 영원히 기다립니다) 및 백오프가 있는 자동 재시도. 시간 초과는 `(connect, read)` 튜플을 사용합니다 — 도달할 수 없는 프록시에 대해 빠르게 실패하고, 느린 페이지 읽기를 허용합니다. 재시도는 urllib3를 통해 전송 계층에서 마운트됩니다:

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

retry = Retry(
    total=4,
    backoff_factor=1,  # exponential backoff between attempts
    status_forcelist=[429, 500, 502, 503, 504],
    allowed_methods=["GET", "HEAD"],
)

session = requests.Session()
session.mount("http://", HTTPAdapter(max_retries=retry))
session.mount("https://", HTTPAdapter(max_retries=retry))
session.proxies = {
    "http": "http://USER:PASS@residentialpremium.quantumproxies.io:8080",
    "https": "http://USER:PASS@residentialpremium.quantumproxies.io:8080",
}

r = session.get("https://httpbin.org/ip", timeout=(5, 30))
```

회전 게이트웨이와 함께 이 조합은 조용히 강력합니다: 각 재시도는 자동으로 다른 종료 IP를 통해 이동하므로, 하나의 불안정한 주소가 연속으로 네 번 요청을 실패하게 할 수 없습니다.

## Requests와 함께하는 SOCKS5 프록시

SOCKS 지원은 추가 기능입니다: `pip install requests[socks]`로 설치하세요. 그런 다음 딕셔너리 구문은 동일합니다 — 스키마만 변경됩니다. `socks5h://`를 `socks5://`보다 선호하세요: `h`는 DNS 해석을 프록시로 밀어내어, 실제 네트워크에서의 DNS 누출을 방지하고 종료 위치에서 지리적으로 제한된 호스트 이름을 해석합니다. 모든 QuantumProxies 계획은 동일한 게이트웨이에서 HTTP와 [SOCKS5 프록시](https://quantumproxies.io/socks5-proxies)를 모두 노출하므로, 프로토콜 전환은 스키마 교체이지 새로운 구매가 아닙니다:

```python
proxies = {
    "http": "socks5h://USER:PASS@residentialpremium.quantumproxies.io:1080",
    "https": "socks5h://USER:PASS@residentialpremium.quantumproxies.io:1080",
}
```

![다섯 가지 Python Requests 프록시 실수와 각각의 결과: 스킴이 없으면 MissingSchema, https 키에 https://를 쓰면 SSLError, 인코딩하지 않은 비밀번호는 407, SOCKS는 requestssocks 추가 패키지가 필요하고, 타임아웃이 없으면 끝없이 기다립니다. 카드 요약: 세 가지 규칙으로 설정 실패의 90%를 막을 수 있습니다.](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1785335141/blog/generated/qp-b9-001-diag2.png)
*다섯 가지 실수가 대부분의 실패를 유발합니다: 누락된 스키마, https 키에 https://, 인코딩되지 않은 비밀번호, 누락된 SOCKS 추가 기능, 그리고 시간 초과 없음.*

## 일반적인 Python Requests 프록시 오류, 해독됨

- **MissingSchema** — 프록시 URL에 `http://`가 없습니다. Requests 2.0.0 이후로 필수입니다.
- **ProxyError: Cannot connect to proxy** — 잘못된 호스트 또는 포트, 또는 죽은 프록시. curl로 엔드포인트를 확인한 후 코드를 비난하세요.
- **SSLError / UNEXPECTED_EOF_WHILE_READING** — 보통 `https` 키 내부의 `https://`. 값의 스키마를 `http://`로 설정하세요.
- **407 Proxy Authentication Required** — 잘못된 자격 증명, 비밀번호의 인코딩되지 않은 특수 문자, 또는 화이트리스트에 없는 소스 IP.
- **ConnectTimeout / ReadTimeout** — 느린 종료 또는 느린 대상. `timeout=(5, 30)`을 설정하고 재시도가 새 IP로 회전하도록 하세요.
- **curl에서는 프록시가 작동하지만 Python에서는 실패** — 환경 변수가 딕셔너리를 무시하고 있습니다. `session.proxies`를 출력하고 `trust_env = False`를 시도하세요.

스택 추적과 그 근본 원인을 더 깊이 탐색하려면, [Requests에서 ProxyError, SSLError 및 ConnectTimeout 디버깅](https://quantumproxies.io/blog/python-requests-proxyerror-fix)을 참조하세요.

## 자주 묻는 질문

### Python Requests에서 프록시를 어떻게 사용하나요?

`http` 및 `https` 키가 포함된 `proxies` 딕셔너리를 모든 요청 메서드에 전달하세요: `requests.get(url, proxies={...})`. 각 값은 스키마를 포함한 전체 프록시 URL이며, 자격 증명은 `http://user:pass@host:port`로 포함됩니다. 동일한 딕셔너리를 `Session`에 첨부하여 모든 요청에 자동으로 적용하세요.

### 왜 내 Python Requests 프록시가 작동하지 않나요?

네 가지 일반적인 용의자를 순서대로 확인하세요: 프록시 URL에 `http://` 스키마가 누락된 경우, `https` 키 내부에 `https://`가 사용된 경우, URL 인코딩되지 않은 비밀번호의 특수 문자, 그리고 코드보다 환경 변수가 우선하는 경우. 동일한 자격 증명을 curl로 테스트하세요 — curl이 성공하면 문제는 딕셔너리에 있습니다.

### Python Requests는 SOCKS5 프록시를 지원하나요?

예, 추가 종속성을 `pip install requests[socks]`로 설치한 후 지원합니다. `socks5h://` 스키마를 proxies 딕셔너리에 사용하여 DNS 해석이 프록시 측에서 이루어지도록 하세요 — 일반 `socks5://` 스키마는 로컬에서 호스트 이름을 해석하여 DNS 쿼리를 누출하고 지리적으로 타겟팅된 스크래핑을 방해할 수 있습니다.

### 환경 변수로 프록시를 어떻게 설정하나요?

전체 프록시 URL로 `HTTP_PROXY` 및 `HTTPS_PROXY`를 내보내고, 선택적으로 제외할 호스트에 대해 `NO_PROXY`를 설정하세요. Requests는 이를 자동으로 감지하여, Requests를 기반으로 구축된 타사 라이브러리도 프록시합니다. 코드가 환경을 완전히 무시하도록 하려면, `session.trust_env = False`를 설정하세요.

그것이 전체 도구 키트입니다: 두 개의 키 딕셔너리, URL에 자격 증명, 한 번 마운트된 재시도, 그리고 코드 대신 게이트웨이에서 처리되는 회전. 구문으로 해결할 수 없는 한 가지는 IP 품질입니다 — 완벽하게 구성된 데이터센터 프록시도 주거 종료가 통과할 때 차단됩니다. 깨끗한 코드와 깨끗한 IP를 결합하면 Requests는 놀랍도록 큰 작업량을 처리할 것입니다.

[첫 시도에 작동하는 주거 프록시를 얻으세요](https://quantumproxies.io/residential-proxies)
