“http.client.CannotSendRequest:请求已发送”错误

问题描述 投票:0回答:2

这里有一个奇怪的问题。我有一个 24/7 运行的 Python 3 脚本,使用 Selenium 和 Firefox 访问网页,每 5 分钟从下载链接下载一个文件(我不能只使用 urllib 或其他方式下载,因为即使下载文件的链接地址保持不变,文件中的数据不断变化,并且每次重新加载页面时都会有所不同,并且还取决于指定的条件)。该脚本几乎一直运行良好,但我无法摆脱这个偶尔弹出的错误,该错误会终止脚本。错误如下:

Traceback (most recent call last):
  File "/Users/Shared/ROTH_1/Folio/get_F_notes.py", line 248, in <module>
    driver.get(search_url)
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/selenium/webdriver/remote/webdriver.py", line 187, in get
    self.execute(Command.GET, {'url': url})
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/selenium/webdriver/remote/webdriver.py", line 173, in execute
    response = self.command_executor.execute(driver_command, params)
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/selenium/webdriver/remote/remote_connection.py", line 349, in execute
    return self._request(command_info[0], url, body=data)
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/selenium/webdriver/remote/remote_connection.py", line 379, in _request
    self._conn.request(method, parsed_url.path, body, headers)
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/http/client.py", line 1090, in request
    self._send_request(method, url, body, headers)
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/http/client.py", line 1118, in _send_request
    self.putrequest(method, url, **skips)
  File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/http/client.py", line 966, in putrequest
    raise CannotSendRequest(self.__state)
http.client.CannotSendRequest: Request-sent

这是我的脚本中出现问题的部分,具体来说,脚本命中了“除了 ConnectionRefusedError:”部分,并按预期打印出“警告 1:ConnectionRefusedError:搜索页面未加载;现在重试” 。但是,我认为,当循环再次开始并再次尝试“driver.get(search_url)”时,我会收到上述错误。脚本在此时卡住并给出了上述错误。

我对此进行了相当多的研究,脚本似乎可能试图重用第一次尝试中的相同连接。解决方法似乎是创建一个新连接。但这就是我所能收集到的一切,我不知道如何与 Selenium 建立新的连接。你?或者,这里还有其他问题吗?

search_url = 'https://www.example.com/download_page'
loop_get_search_page = 1
while loop_get_search_page < 7:
    if loop_get_search_page == 6:
        print('WARNING: tried to load search page 5 times; exiting script to try again later')
        ##### log out
        try:
            driver.find_element_by_link_text('Sign Out')
        except NoSuchElementException:
            print('WARNING: NoSuchElementException: Unable to find the link text for the "Sign Out" button')
        driver.quit()
        raise SystemExit
    try:
        driver.get(search_url)
    except TimeoutException:
        print('WARNING ', loop_get_search_page, ': TimeoutException: search page did not load; now trying again', sep='')
        loop_get_search_page += 1
        continue
    except ConnectionRefusedError:
        print('WARNING ', loop_get_search_page, ': ConnectionRefusedError: search page did not load; now trying again')
        loop_get_search_page += 1
        continue
    else:
        break
python firefox selenium
2个回答
5
投票

我自己也遇到了这个问题。就我而言,我有另一个线程在侧面运行,它也通过 WebDriver 发出请求。事实证明 WebDriver 不是线程安全。

查看Selenium 在一个浏览器中使用多线程吗? 的讨论以及那里的链接以获取更多上下文。

当我删除另一个线程时,一切都开始按预期工作。

是否有可能每 5m 运行一个新线程?

我知道“创建新连接”的唯一方法是启动 WebDriver 的新实例。如果您执行大量请求,速度可能会变慢,但由于您只每 5 m 执行一次操作,因此它不会真正影响您的吞吐量。只要您在 dl 完成后始终清理 WebDriver 实例,这对您来说可能是一个不错的选择。


0
投票

我也遇到了同样的问题。事实证明,如果

conn.request()
中有异常,其中
conn
http.client.HTTPConnection
的实例(在我的例子中是 DNS 查找失败的主机名),连接对象的内部状态就会发生混乱,下一次对
conn.request
的调用失败,并出现此问题中提到的异常。 (即使实际上没有发送任何请求)。

这是有道理的,并且可能会发生,尽管我没有测试它,如果你对

.request()
进行了两次(成功)调用而没有在中间调用
.response()
,你会得到这个异常。尽管有异常,我没有测试是否可以通过调用
.response()
来清除错误状态,但我没有在文档中看到任何说明这样做的内容。

所以我的解决方法是在出现异常时丢弃连接对象并创建一个新的连接对象。 (在我调查的案例中,原始版本除了 DNS 查找失败之外没有使用任何资源,因此丢弃它并不会造成太大损失。如果它实际上在 TLS 密钥交换上花费了时间和 CPU,那就是另一回事了.这正是我尝试重用连接对象而不是每次都创建一个新连接对象的原因。)。

© www.soinside.com 2019 - 2024. All rights reserved.