使用Python进行Web Scraping:仅本地正常,其他环境均返回403错误
问题排查与解决方案
针对本地运行正常、Docker/其他机器执行返回403的问题,以下是具体排查方向和修复方案:
1. 补全请求头,避免指纹识别
目标网站可能会检测请求头的完整性,仅设置User-Agent不足以模拟正常浏览器请求。建议在代码中补充常见标准请求头:
def request_with_proxy(url, headers={}): # 补全通用请求头 default_headers = { 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', 'Accept-Language': 'en-US,en;q=0.5', 'Accept-Encoding': 'gzip, deflate, br', 'Connection': 'keep-alive', 'Upgrade-Insecure-Requests': '1' } default_headers.update(headers) # 添加随机User-Agent default_headers["User-Agent"] = user_agent_rotator.get_random_user_agent() # 代理配置(原代码保持不变) try: proxy_url = f'http://{os.environ["PROXY_USER"]}:{os.environ["PROXY_PASSWORD"]}@p.webshare.io:80' proxies = { 'http': proxy_url, 'https': proxy_url } except: raise TypeError("MISSING PROXY ENVIRONMENT VARIABLES PROXY_USER AND PROXY_PASSWORD") # 使用Session复用连接,减少异常指纹 session = requests.Session() session.headers.update(default_headers) session.proxies.update(proxies) # 重试逻辑 for _ in range(ATTEMPTS): try: response = session.get(url, timeout=TIMEOUT) print(response.status_code) return response except Exception as e: print(e) session.close()
2. 统一TLS/SSL版本
Python Slim镜像默认的OpenSSL版本可能较旧,与目标网站的TLS兼容性存在差异。修改Dockerfile更新SSL组件:
FROM python:3.10.12-slim # 设置时区(匹配目标网站所在地区,德国站用Europe/Berlin) ENV TZ=Europe/Berlin RUN apt-get update -y && \ apt-get install -y postgresql postgresql-contrib openssl tzdata && \ rm -rf /var/lib/apt/lists/* && \ pip install --no-cache-dir -r requirements.txt && \ rm -rf /root/.cache && \ apt-get autoremove -y ENV PYTHONUNBUFFERED=1 CMD ["python", "main.py"]
同时在请求中强制指定TLS1.2+版本:
import ssl from requests.adapters import HTTPAdapter from urllib3.poolmanager import PoolManager class TLSAdapter(HTTPAdapter): def init_poolmanager(self, *args, **kwargs): ctx = ssl.create_default_context() ctx.set_ciphers('DEFAULT@SECLEVEL=1') ctx.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1 kwargs['ssl_context'] = ctx return super(TLSAdapter, self).init_poolmanager(*args, **kwargs) # 在session中挂载适配器 session.mount('https://', TLSAdapter())
3. 验证User-Agent有效性
检查容器中生成的User-Agent是否与本地一致,部分旋转库在容器环境下可能生成异常UA(如过旧或非标准格式)。可以临时打印UA对比:
ua = user_agent_rotator.get_random_user_agent() print(f"Using UA: {ua}")
若存在差异,建议更换更稳定的UA库(如fake_useragent),或手动维护常用浏览器UA列表。
4. 排查代理连接细节
虽然代理仪表盘显示连接正常,但需确认:
- 代理是否传递了容器的异常特征(如hostname),可在Dockerfile中设置常规主机名:
ENV HOSTNAME=desktop-abc123 - 本地与容器的代理连接是否存在Keep-Alive差异,使用Session复用连接可减少此类问题
5. 对比请求指纹
用curl在本地和容器中分别发送请求,对比完整请求头和响应:
# 本地执行 curl -v -x http://PROXY_USER:PROXY_PASSWORD@p.webshare.io:80 https://kleinanzeigen.de -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36" # 容器内执行(先进入容器) docker exec -it <container_id> bash curl -v -x http://PROXY_USER:PROXY_PASSWORD@p.webshare.io:80 https://kleinanzeigen.de -A "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36"
重点对比Accept、Accept-Encoding、Connection等头字段,以及TLS握手信息。
内容的提问来源于stack exchange,提问作者HCook886
相关产品推荐
相关产品推荐

