&引用;未能解码来自木偶的响应;Python/Firefox无头抓取脚本中的消息

&引用;未能解码来自木偶的响应;Python/Firefox无头抓取脚本中的消息,python,selenium,firefox,web-scraping,geckodriver,Python,Selenium,Firefox,Web Scraping,Geckodriver,你好,我已经在这里和谷歌上做了很多搜索,还没有找到解决这个问题的方法 情况是: 我有一个Python脚本(2.7),它循环遍历许多URL(例如,想想Amazon页面,抓取评论)。每个页面都有相同的HTML布局,只需抓取不同的信息。我将Selenium与无头浏览器结合使用,因为这些页面具有需要执行的javascript来获取信息 我在本地机器(OSX 10.10)上运行此脚本。Firefox是最新的v59。Selenium版本为3.11.0,使用geckodriver v0.20 这个脚本在本地没

你好,我已经在这里和谷歌上做了很多搜索,还没有找到解决这个问题的方法

情况是:

我有一个Python脚本(2.7),它循环遍历许多URL(例如,想想Amazon页面,抓取评论)。每个页面都有相同的HTML布局,只需抓取不同的信息。我将Selenium与无头浏览器结合使用,因为这些页面具有需要执行的javascript来获取信息

我在本地机器(OSX 10.10)上运行此脚本。Firefox是最新的v59。Selenium版本为3.11.0,使用geckodriver v0.20

这个脚本在本地没有任何问题,它可以运行所有的URL,并在没有问题的情况下刮取页面

现在,当我把脚本放在我的服务器上时,唯一的区别是它是Ubuntu 16.04(32位)。我使用了适当的geckodriver(仍然是v0.20),但其他一切都是一样的(Python 2.7,Selenium 3.11)。它似乎随机使无头浏览器崩溃,然后所有的
browservjt.get('url…')
都不再工作

错误消息显示:

消息:未能解码来自木偶的响应

任何进一步的selenium页面请求都会返回错误:

消息:尝试在不建立连接的情况下运行命令


要显示一些代码:

创建驱动程序时:

    options = Options()
    options.set_headless(headless=True)

    driver = webdriver.Firefox(
        firefox_options=options,
        executable_path=config.GECKODRIVER
    )
driver
作为参数
browservebj
传递给脚本函数,然后用于调用特定页面,加载后传递给BeautifulSoup进行解析:

browserObj.get(url)

soup = BeautifulSoup(browserObj.page_source, 'lxml')

错误可能指向正在使浏览器崩溃的BeautifulSoup行

这可能是什么原因造成的,我能做些什么来解决这个问题


编辑:添加指向相同对象的堆栈跟踪:

Traceback (most recent call last):
  File "main.py", line 164, in <module>
    getLeague
  File "/home/ps/dataparsing/XXX/yyy.py", line 48, in BBB
    soup = BeautifulSoup(browserObj.page_source, 'lxml')
  File "/home/ps/AAA/projenv/local/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 670, in page_source
    return self.execute(Command.GET_PAGE_SOURCE)['value']
  File "/home/ps/AAA/projenv/local/lib/python2.7/site-packages/selenium/webdriver/remote/webdriver.py", line 312, in execute
    self.error_handler.check_response(response)
  File "/home/ps/AAA/projenv/local/lib/python2.7/site-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
    raise exception_class(message, screen, stacktrace)
WebDriverException: Message: Failed to decode response from marionette
回溯(最近一次呼叫最后一次):
文件“main.py”,第164行,在
getLeague
文件“/home/ps/dataparsing/XXX/yyy.py”,第48行,在BBB中
soup=BeautifulSoup(browservebj.page_来源“lxml”)
文件“/home/ps/AAA/projenv/local/lib/python2.7/site packages/selenium/webdriver/remote/webdriver.py”,第670行,在第页的源代码中
返回self.execute(Command.GET_PAGE_SOURCE)['value']
文件“/home/ps/AAA/projenv/local/lib/python2.7/site packages/selenium/webdriver/remote/webdriver.py”,第312行,在execute中
self.error\u handler.check\u响应(响应)
文件“/home/ps/AAA/projenv/local/lib/python2.7/site packages/selenium/webdriver/remote/errorhandler.py”,第242行,在check_响应中
引发异常类(消息、屏幕、堆栈跟踪)
WebDriverException:消息:未能解码来自木偶的响应


注意:此脚本用于处理Chrome。因为服务器是32位服务器,所以我只能使用chromedriver v0.33,它只支持ChromeV60-62。目前Chrome是v65,在DigitalOcean上,我似乎没有一个简单的方法恢复到旧版本——这就是为什么我一直使用Firefox。

我仍然不知道为什么会发生这种情况,但我可能已经找到了解决办法。我在一些文档中读到可能存在竞争条件(关于什么,我不确定,因为不应该有两个项目竞争相同的资源)

我更改了抓取代码以执行此操作:

import time

browserObj.get(url)

time.sleep(3)

soup = BeautifulSoup(browserObj.page_source, 'lxml')
没有具体原因说明为什么我选择了3秒,但自从添加此延迟后,我没有收到任何要刮取的URL列表中的
消息:未能解码来自木偶的响应


更新日期:2018年10月

六个月后,这仍然是一个问题。Firefox、Geckodriver、Selenium和PyVirtualDisplay都已更新至其最新版本。这个错误不断地自发地重复出现,没有规律:有时有效,有时无效


解决此问题的方法是将服务器上的RAM从1 GB增加到2 GB。自增长以来,没有出现过这种失败

对于在Docker容器中运行selenium webdriver时遇到此问题的任何其他人,请修复


如果OP通过将服务器RAM升级到2Gb来解决物理机器的问题,我想这也会影响物理机器,但这可能是巧合。

这背后可能存在的真正问题是DOM尚未加载,而您正在触发下一页的搜索。这就是为什么
睡眠(3)
在大多数情况下都能工作的原因。正确的解决方法是使用wait类

这是一个使用Nextcloud的wait函数的示例测试用例。它来自我的docker selenium firefox python图像:

请注意如何围绕任何
单击
获取
调用调用
wait
类。基本上,这可以利用selenium在页面加载时更改
HTML
标记的ID这一事实。wait函数检查新ID是否与旧ID不同,如果不同,则DOM已加载

import time
from selenium.webdriver import Firefox
from selenium.webdriver.firefox.options import Options
from selenium.webdriver.common.keys import Keys

class wait(object):

    def __init__(self, browser):
        self.browser = browser

    def __enter__(self):
        self.old_page = self.browser.find_element_by_tag_name('html')

    def page_has_loaded(self):
        new_page = self.browser.find_element_by_tag_name('html')
        return new_page.id != self.old_page.id

    def __exit__(self, *_):
        start_time = time.time()
        while time.time() < start_time + 5:
            if self.page_has_loaded():
                return True
            else:
                time.sleep(0.1)
        raise Exception('Timeout waiting for page load.')

def test():
    try:
        opts = Options()
        opts.headless = True
        assert opts.headless  # Operating in headless mode
        browser = Firefox(options=opts)
    except Exception as e:
        print("  -=- FAIL -=-: Browser setup - ", e)
        return

    # Test title
    try:
        with wait(browser):
            browser.get('https://nextcloud.mydomain.com/index.php/login')
        assert 'Nextcloud' in browser.title
    except Exception as e:
        print("  -=- FAIL -=-: Initial load - ", e)
        return
    else:
        print("  Success: Initial load")

    try:
        # Enter user
        elem = browser.find_element_by_id('user')
        elem.send_keys("MYUSER")

        # Enter password
        elem = browser.find_element_by_id('password')
        elem.send_keys("MYPASSWORD")

        # Submit form
        elem = browser.find_element_by_id('submit')
        with wait(browser):
            elem.click()

        # Check title for success
        assert 'Files' in browser.title
    except Exception as e:
        print("  -=- FAIL -=-: Login - ", e)
        return
    else:
        print("  Success: Login")

    print("  Finished.")

print("Testing nextcloud...")
test()
导入时间
从selenium.webdriver导入Firefox
从selenium.webdriver.firefox.options导入选项
从selenium.webdriver.common.keys导入密钥
类等待(对象):
定义初始化(自我,浏览器):
self.browser=浏览器
定义输入(自我):
self.old_page=self.browser.find_element_by_tag_name('html'))
def页面已加载(自):
新建页面=self.browser。通过标签名称(“html”)查找元素
返回新的页面id!=self.old_page.id
定义uuu退出uuu(自我,*uu):
开始时间=time.time()
while time.time()firefox_binary='/home/user/Downloads/old_firefox/firefox/firefox'
Message: failed to decode response from marionette
DEBUG   <- 500 Internal Server Error {"value":{"error":"unknown error","message":"Failed to decode response from marionette","stacktrace":...}...}
--memory 1024mb --shm-size 2g
--memory 1024mb