자격 증명이 올바르더라도 @나 #이 포함된 비밀번호는 직접 조합한 프록시 URL을 망가뜨릴 수 있습니다. 이 문자들은 URL에서 이미 의미가 있으므로 클라이언트가 비밀번호 일부를 호스트 이름이나 프래그먼트로 해석할 수 있습니다.

두 자격 증명 필드를 따로 인코딩하기

다음 예제는 URL의 구조 구분자를 유지하고 사용자 이름과 비밀번호만 인코딩합니다.

from urllib.parse import quote

username = "user@team"
password = "p:a/ss#?"
proxy_url = (
    "http://"
    + quote(username, safe="")
    + ":"
    + quote(password, safe="")
    + "@203.0.113.10:8080"
)

실제 엔드포인트와 자격 증명을 사용하세요. 표시된 주소는 문서용 예제입니다. 빈 safe 인수가 중요합니다. quote는 보통 슬래시를 이스케이프하지 않지만 자격 증명 필드 안의 슬래시는 인코딩해야 합니다.

프록시 URL 전체를 인코딩하지 마세요. 스킴 구분자와 자격 증명·호스트 사이의 @를 인코딩하면 보존하려던 구조가 깨집니다. 이미 인코딩한 비밀번호를 다시 인코딩하는 것도 피하세요.

결과를 Requests에서 사용하기

import requests

response = requests.get(
    "https://example.com/",
    proxies={"http": proxy_url, "https": proxy_url},
    timeout=(5, 15),
)
response.raise_for_status()

요청이 여전히 실패한다면 프록시가 로그인을 거부하는지, 아니면 클라이언트가 더 앞선 파싱이나 연결 단계에서 실패했는지 확인하세요. 407 인증 요구와 잘못된 URL은 다른 실패입니다.

HTTPX는 인증을 분리할 수 있음

HTTPX Proxy 객체는 엔드포인트와 자격 증명을 별도 인수로 받을 수 있습니다.

import httpx

proxy = httpx.Proxy(
    "http://203.0.113.10:8080",
    auth=("user@team", "p:a/ss#?"),
)

with httpx.Client(proxy=proxy, trust_env=False, timeout=15) as client:
    response = client.get("https://example.com/")
    response.raise_for_status()

이렇게 하면 userinfo 부분을 직접 만들 필요가 없습니다. 프록시 연결과 별개로 자격 증명을 암호화하거나 모든 서비스에서 지원하는 인증 방식을 선택해 주는 것은 아닙니다.

무료 목록에 IP와 포트만 있다면 이 예제가 기본 자격 증명을 제공하는 것은 아닙니다. 운영자가 실제 계정을 제공했을 때만 인증을 사용하세요. 자격 증명이 포함된 URL을 공유 로그와 소스 파일에 남기지 마세요.

관련 글