You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Scrapy Playwright配置动态代理?遇超时错误求解决

Scrapy Playwright 动态代理配置超时问题解决

问题背景

给Scrapy Playwright配置动态代理时,发现scrapy-proxy-pool和Scrapy Playwright兼容性不佳,于是基于proxyscrape自行实现代理轮换,但始终遇到代理连接超时错误,报错net::ERR_TIMED_OUT。

原代码

import scrapy
from scrapy_playwright.page import PageMethod
from proxyscrape import create_collector

collector = create_collector('proxy', 'http')

class ProxySpider(scrapy.Spider):
    name = 'proxy'
    
    PLAYWRIGHT_LAUNCH_OPTIONS = {
        "headless": False,
        "timeout": 100 * 1000,  # 20 seconds
    
    }
    
    def start_requests(self):
        proxy = collector.get_proxy()
        print("Proxy --> http://"+proxy.host+":"+proxy.port)
      
        yield scrapy.Request("http://httpbin.org/get", meta={
            "playwright": True,
            "playwright_context_kwargs": {
                "java_script_enabled": True,
                "ignore_https_errors": True,
                "proxy": {
                    "server": "http://"+proxy.host+":"+proxy.port,
                },
            },
            })       
    
    def parse(self,response):
        print(response.text)

错误日志

File "/home/sappy/.virtualenvs/121-server/lib/python3.10/site-packages/scrapy_playwright/handler.py", line 297, in _download_request                                                                                                                                       
result = await self._download_request_with_page(request, page, spider)                                                             
File "/home/sappy/.virtualenvs/121-server/lib/python3.10/site-packages/scrapy_playwright/handler.py", line 331, in _download_request_with_page                                                                                                                              
response = await page.goto(url=request.url, **page_goto_kwargs)                                                                    
File "/home/sappy/.virtualenvs/121-server/lib/python3.10/site-packages/playwright/async_api/_generated.py", line 9162, in goto         
await self._impl_obj.goto(                                                                                                         
File "/home/sappy/.virtualenvs/121-server/lib/python3.10/site-packages/playwright/_impl/_page.py", line 494, in goto                   
return await self._main_frame.goto(**locals_to_params(locals()))                                                                   
File "/home/sappy/.virtualenvs/121-server/lib/python3.10/site-packages/playwright/_impl/_frame.py", line 147, in goto                  
await self._channel.send("goto", locals_to_params(locals()))                                                                       
File "/home/sappy/.virtualenvs/121-server/lib/python3.10/site-packages/playwright/_impl/_connection.py", line 44, in send              
return await self._connection.wrap_api_call(                                                                                       
File "/home/sappy/.virtualenvs/121-server/lib/python3.10/site-packages/playwright/_impl/_connection.py", line 419, in wrap_api_call   
return await cb()                                                                                                                  
File "/home/sappy/.virtualenvs/121-server/lib/python3.10/site-packages/playwright/_impl/_connection.py", line 79, in inner_send       
result = next(iter(done)).result()                                                                                                 
playwright._impl._api_types.Error: net::ERR_TIMED_OUT at http://httpbin.org/get                                                      
=========================== logs ===========================                                                                        
navigating to "http://httpbin.org/get", waiting until "load"                                                                        
============================================================

问题原因

  1. 免费代理可用性极低:proxyscrape获取的免费代理多为临时资源,大部分已失效或被目标站点封禁,直接使用必然触发超时。
  2. 缺少代理预验证:未在使用前测试代理连通性,直接发起请求导致无效代理浪费时间。
  3. 超时配置不全:仅设置了Playwright启动超时,未配置页面跳转超时,也没有代理失败后的重试逻辑。

修复方案

1. 增加代理预验证逻辑

使用前先测试代理是否能正常访问目标站点,过滤失效代理。

2. 完善超时与重试配置

给Playwright页面跳转、Scrapy请求分别添加超时和重试规则。

3. 添加失败重试机制

代理超时后自动获取新代理并重试请求。

修改后的代码

import scrapy
import requests
from scrapy_playwright.page import PageMethod
from proxyscrape import create_collector
from scrapy.utils.retry import get_retry_request

collector = create_collector('proxy', 'http')

def is_proxy_valid(proxy):
    """验证代理是否可用"""
    proxy_url = f"http://{proxy.host}:{proxy.port}"
    try:
        # 5秒超时测试httpbin连通性
        response = requests.get(
            "http://httpbin.org/get",
            proxies={"http": proxy_url, "https": proxy_url},
            timeout=5
        )
        return response.status_code == 200
    except:
        return False

class ProxySpider(scrapy.Spider):
    name = 'proxy'
    # 配置Scrapy重试规则
    custom_settings = {
        "RETRY_TIMES": 3,
        "RETRY_HTTP_CODES": [500, 502, 503, 504, 408, 429],
    }
    
    PLAYWRIGHT_LAUNCH_OPTIONS = {
        "headless": False,
        "timeout": 100 * 1000,
    }
    
    def start_requests(self):
        yield self.get_request_with_valid_proxy()
    
    def get_request_with_valid_proxy(self):
        """循环获取可用代理并生成请求"""
        proxy = None
        # 最多尝试5次获取可用代理
        for _ in range(5):
            proxy = collector.get_proxy()
            if is_proxy_valid(proxy):
                print(f"使用有效代理 --> http://{proxy.host}:{proxy.port}")
                break
        else:
            self.logger.error("未找到可用代理")
            return
        
        return scrapy.Request(
            "http://httpbin.org/get",
            meta={
                "playwright": True,
                "playwright_context_kwargs": {
                    "java_script_enabled": True,
                    "ignore_https_errors": True,
                    "proxy": {
                        "server": f"http://{proxy.host}:{proxy.port}",
                    },
                },
            },
            errback=self.errback,
        )
    
    def parse(self, response):
        print(response.text)
        # 如需持续爬取,可在此生成新请求
        # yield self.get_request_with_valid_proxy()
    
    async def errback(self, failure):
        """请求失败回调,切换新代理重试"""
        self.logger.error(f"请求失败: {failure.value}")
        # 生成重试请求并替换为新代理
        yield self.get_request_with_valid_proxy()

额外建议

  • 免费代理稳定性差,生产环境建议改用付费代理服务,这类代理池的可用性和稳定性远高于免费资源。
  • 可将验证通过的代理缓存,避免重复验证,提升爬取效率。

内容的提问来源于stack exchange,提问作者saprative

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 20:15:07