在无头模式下使用 Firefox 改进 scrapy 和 selenium

Posted

技术标签:

【中文标题】在无头模式下使用 Firefox 改进 scrapy 和 selenium【英文标题】:Improve scrapy and selenium with firefox in headless mode 【发布时间】:2018-07-04 08:04:31 【问题描述】:

我正在抓取一个 javascript 繁重的网站,并且我已经设置了一个 vagrant 实例来检查可行性(1GB RAM)。解析几个 url 后系统崩溃。我无法确定此设置的内存要求和崩溃原因。但是,我让 htop 并行运行,并在系统崩溃之前获得了屏幕截图,附在下面。我怀疑内存不够,但我不知道我需要多少。因此,我正在寻找:

    我的设置的内存要求(Scrapy + selenium + fireofox -headless 崩溃原因 如何改进抓取过程 (scrapy、selenium、firefox)的替代品

SeleniumMiddleWare:

import os, traceback
from shutilwhich import which
from scrapy import signals
from scrapy.http import htmlResponse
from scrapy.utils.project import get_project_settings
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.firefox.options import Options

SELENIUM_HEADLESS = False

settings = get_project_settings()

class SeleniumMiddleware(object):
    driver = None

    @classmethod
    def from_crawler(cls, crawler):
        middleware = cls()
        crawler.signals.connect(middleware.spider_opened, signals.spider_opened)
        crawler.signals.connect(middleware.spider_closed, signals.spider_closed)
        return middleware

    def process_request(self, request, spider):
        if not request.meta.get('selenium'):
            return
        self.driver.get(request.url)

        #if setting new cookies remove old
        if len(request.cookies):
            self.driver.implicitly_wait(1)
            self.driver.delete_all_cookies()

        #add only desired cookies if session persistence is requested
        request_cookies=[]

        if request.meta.get('request_cookies'):
           request_cookies=request.meta.get('request_cookies')

        for cookie in request.cookies:
             if cookie['name'] in request_cookies:
                print ' ---- set request cookie [%s] ---- ' % cookie['name']
                new_cookie=k: cookie[k] for k in ('name', 'value','path', 'expiry') if k in cookie
                self.driver.add_cookie(new_cookie)

        if  request.meta.get('redirect_url'):
            self.driver.get(request.meta.get('redirect_url'))
            self.driver.implicitly_wait(5)

        request.meta['driver'] = self.driver

        return HtmlResponse(self.driver.current_url, body=self.driver.page_source, encoding='utf-8', request=request)

    def spider_opened(self, spider):
        options=Options()
        binary= settings.get('SELENIUM_FIREFOX_BINARY') or which('firefox')
        SELENIUM_HEADLESS=settings.get('SELENIUM_HEADLESS') or False
        if SELENIUM_HEADLESS:
            print " ---- HEADLESS ----"
            options.add_argument( "--headless" )

        firefox_capabilities = DesiredCapabilities.FIREFOX
        firefox_capabilities['marionette'] = True
        firefox_capabilities['binary'] = binary
        try:
            self.driver = webdriver.Firefox(capabilities=firefox_capabilities, firefox_options=options)
        except Exception:
          print " ---- Unable to instantiate selenium webdriver instance ! ----"
          traceback.print_exc()
          os._exit(1)

    def spider_closed(self, spider):
        if self.driver:
            self.driver.close()

【问题讨论】:

请阅读为什么screenshot of HTML or code or error is a bad idea。考虑使用基于格式化文本的相关 HTML、代码试验和错误堆栈跟踪来更新问题。 你初始化了多少个 Firefox 实例? @DebanjanB,我没有其他选择 @DebanjanB,我已将 RAM 增加到 2GB 并且工作正常,可能就是这个问题 好消息!!!请将解决方案添加为未来读者的答案。如果您可以分享您的代码试验,我本可以知道崩溃的原因 【参考方案1】:

def spider_closed(self, spider): 中快速潜入您的代码块会显示您正在使用self.driver.close(),如下所示:

def spider_closed(self, spider):
    if self.driver:
        self.driver.close()

根据关闭webdriver 变体和webbrowser 实例的最佳实践,您应该在tearDown() 中调用quit() 方法。调用quit(),通过发送quit 命令和"flags":["eForceQuit"] 删除当前浏览会话,最后在/shutdownEndPoint 上发送GET 请求。

您可以在How to stop geckodriver process impacting PC memory, without calling driver.quit()?找到详细讨论

因此解决方案是将 self.driver.close() 替换为 self.driver.quit(),如下所示:

def spider_closed(self, spider):
    if self.driver:
        self.driver.quit()

【讨论】:

以上是关于在无头模式下使用 Firefox 改进 scrapy 和 selenium的主要内容,如果未能解决你的问题,请参考以下文章

使用 selenium 在无头模式下运行 Firefox 错误:“选项”对象没有属性“二进制”

selenium.common.exceptions.InvalidSessionIdException通过Python在无头模式下使用GeckoDriver Selenium Firefox(示例代

Python-Selenium:剪贴板功能(ctrl + c)在 Firefox 无头模式下不起作用

Selenium Firefox Python 在无头模式下运行超时初始化驱动程序

Python - Firefox 无头

在无头模式下针对 webkit 渲染引擎测试页面