Scrapy在" __ init __"之后没有调用任何其他函数

时间:2016-10-27 02:04:43

标签: python python-2.7 selenium scrapy scrapy-spider

操作系统:Ubuntu 16.04 Stack - Scrapy 1.0.3 + Selenium 我对scrapy很新,这听起来很基本,但在我的蜘蛛中,只有" init "正在被执行。之后的任何代码/函数都没有被调用,蜘蛛就停止了。

class CancerForumSpider(scrapy.Spider):
    name = "mainpage_spider"
    allowed_domains = ["cancerforums.net"]
    start_urls = [
        "http://www.cancerforums.net/forums/14-Prostate-Cancer-Forum"
    ]

    def __init__(self,*args,**kwargs):
        self.browser=webdriver.Firefox()
        self.browser.get("http://www.cancerforums.net/forums/14-Prostate-Cancer-Forum")
        print "----------------Going to sleep------------------"
        time.sleep(5)
        # self.parse()

    def __exit__(self):
        print "------------Exiting----------"
        self.browser.quit()

    def parse(self,response):
        print "----------------Inside Parse------------------"
        print "------------Exiting----------"
        self.browser.quit()

蜘蛛获取浏览器对象,打印"进入睡眠状态"然后停下来。它不会进入解析函数。

enter image description here

以下是运行日志的内容:

  

----------------里面的init ----------------   ----------------去睡觉------------------

2 个答案:

答案 0 :(得分:2)

您需要解决或注意一些问题:

  1. 您在__init__方法期间没有调用super(),因此不会发生任何继承的类初始化。 Scrapy不会做任何事情(比如调用它的parse()方法),因为所有这些都是在scrapy.Spider中设置的。

  2. 修复上述问题后,Scrapy将调用您的parse()方法,但不会在您获取Selenium的网页上进行操作。它将不知道这一点,并将重新获取网址(基于start_urls)。这两个来源很可能会有所不同(通常很大)。

  3. 您将以自己的方式使用Selenium绕过几乎所有Scrapy的功能。所有Selenium的get()都将在Scrapy框架之外执行。不会应用中间件(cookie,限制,过滤等),也不会使用您期望的数据填充任何预期/创建的对象(如requestresponse)。

  4. 在你解决所有这些问题之前,你应该考虑几个更好的选择/替代方案:

    • 创建一个处理所有“Selenium”相关功能的下载中间件。让它在到达下载程序之前拦截request个对象,填充新的response个对象并将其返回以供蜘蛛处理。
      这不是最佳选择,因为您正在有效地创建自己的下载程序,并使Scrapy短路。您必须重新实现下载程序通常考虑的任何所需设置的处理,并使它们与Selenium一起使用。
    • Ditch Selenium并使用Splash HTTP和scrapy-splash中间件来处理Javascript。
    • Ditch Scrapy一起使用Selenium和BeautifulSoup。

答案 1 :(得分:1)

当您必须抓取大量网页时,Scrapy非常有用。当加载JS后需要拥有DOM源时,Selenium通常可用于抓取。如果这是你的情况,有两种主要的方法来结合Selenium和Scrapy。一种是编写下载处理程序,就像你可以找到的here

代码如下:

# encoding: utf-8
from __future__ import unicode_literals

from scrapy import signals
from scrapy.signalmanager import SignalManager
from scrapy.responsetypes import responsetypes
from scrapy.xlib.pydispatch import dispatcher
from selenium import webdriver
from six.moves import queue
from twisted.internet import defer, threads
from twisted.python.failure import Failure


class PhantomJSDownloadHandler(object):

    def __init__(self, settings):
        self.options = settings.get('PHANTOMJS_OPTIONS', {})

        max_run = settings.get('PHANTOMJS_MAXRUN', 10)
        self.sem = defer.DeferredSemaphore(max_run)
        self.queue = queue.LifoQueue(max_run)

        SignalManager(dispatcher.Any).connect(self._close, signal=signals.spider_closed)

    def download_request(self, request, spider):
        """use semaphore to guard a phantomjs pool"""
        return self.sem.run(self._wait_request, request, spider)

    def _wait_request(self, request, spider):
        try:
            driver = self.queue.get_nowait()
        except queue.Empty:
            driver = webdriver.PhantomJS(**self.options)

        driver.get(request.url)
        # ghostdriver won't response when switch window until page is loaded
        dfd = threads.deferToThread(lambda: driver.switch_to.window(driver.current_window_handle))
        dfd.addCallback(self._response, driver, spider)
        return dfd

    def _response(self, _, driver, spider):
        body = driver.execute_script("return document.documentElement.innerHTML")
        if body.startswith("<head></head>"):  # cannot access response header in Selenium
            body = driver.execute_script("return document.documentElement.textContent")
        url = driver.current_url
        respcls = responsetypes.from_args(url=url, body=body[:100].encode('utf8'))
        resp = respcls(url=url, body=body, encoding="utf-8")

        response_failed = getattr(spider, "response_failed", None)
        if response_failed and callable(response_failed) and response_failed(resp, driver):
            driver.close()
            return defer.fail(Failure())
        else:
            self.queue.put(driver)
            return defer.succeed(resp)

    def _close(self):
        while not self.queue.empty():
            driver = self.queue.get_nowait()
            driver.close()

假设您的刮刀被称为&#34;刮刀&#34;。如果你把上面提到的代码放在一个名为handlers.py的文件中,那就是&#34; scraper&#34;文件夹,然后您可以添加到settings.py:

DOWNLOAD_HANDLERS = {
    'http': 'scraper.handlers.PhantomJSDownloadHandler',
    'https': 'scraper.handlers.PhantomJSDownloadHandler',
}

另一种方法是编写下载中间件,如here所述。下载中间件的缺点是阻止某些关键功能开箱即用,例如缓存和重试。

在任何情况下,在Scrapy蜘蛛的初始化时启动Selenium webdriver都不是常用的方法。