【问题标题】:`How to use a chain of callbacks in scrapy`如何在scrapy中使用回调链
【发布时间】:2015-07-08 09:08:47
【问题描述】:

我正在尝试使用 scrapy 和 selenium webdriver 构建一个爬虫。我正在尝试在parse() 中获取一组网址并将其传递给回调函数parse_url(),该函数再次获取一组不同的网址并将其传递给parse_data()

parse_url 的第一个回调有效,但parse_data 的第二个回调给出AssertionError

即,如果我在没有 parse_data 的情况下运行,它会打印一个 url 列表。但是如果我包含它,我会得到一个断言错误

我有这样的事情

class mySpider(scrapy.Spider):
    name = "mySpider"
    allowed_domains = ["example.com"]
    start_urls = [
        "http://www.example.com/url",
    ]

    def parse(self, response):
        driver = webdriver.firefox()
    driver.get(response.url)
    urls = get_urls(driver.page_source) # get_url returns a list
        yield scrapy.Request(urls, callback=self.parse_url(urls, driver))

    def parse_url(self, url, driver):
        url_list = []
    for i in urls:
    driver.get(i)
    url_list.append( get_urls(driver.pagesource)) # gets some more urls 
    yeild scrapy.Request(urls, callback=self.parse_data(url_list, driver))

    def parse_data(self, url_list, driver):
        data = get_data(driver.pagesource)

这是回溯,

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/scrapy/utils/defer.py", line 45, in mustbe_deferred
    result = f(*args, **kw)
  File "/usr/local/lib/python2.7/dist-packages/scrapy/core/spidermw.py", line 48, in process_spider_input
    return scrape_func(response, request, spider)
  File "/usr/local/lib/python2.7/dist-packages/scrapy/core/scraper.py", line 145, in call_spider
    dfd.addCallbacks(request.callback or spider.parse, request.errback)
  File "/usr/local/lib/python2.7/dist-packages/twisted/internet/defer.py", line 299, in addCallbacks
    assert callable(callback)
AssertionError

【问题讨论】:

  • 另一方面:在我看来,您使用 Selenium 做了很多事情,这也可以使用 Scrapy 完成:从站点中提取 URL(当前您加载站点两次:一次使用Scrapy,然后使用 Selenium)。
  • 网页有动态内容。在实际代码中,我必须向下滚动并让元素加载。因此硒

标签: python firefox selenium scrapy screen-scraping


【解决方案1】:

有两个问题:

  1. 您没有将函数传递给请求。您正在将函数的返回值传递给请求。

  2. Request 的回调函数必须具有签名(self,response)。

动态内容的解决方案在这里:https://stackoverflow.com/a/24373576/2368836

它将消除将驱动程序传递给函数的需要。

所以当产生你的请求时,它应该是这样的......

scrapy.Request(urls, callback=self.parse_url)

如果您真的想在该函数中包含驱动程序,请阅读闭包。

编辑:这是一个关闭解决方案,但由于 GHajba 指出的原因,我认为您应该使用我分享的链接。

   def parse_data(self, url_list, driver):
        def encapsulated(spider, response)
            data = get_data(driver.pagesource)
            .....
            .....
            yield item
    return encapsulated

那么你的请求看起来像

yield scrapy.request(url, callback=self.parse_data(url_list, driver)

【讨论】:

猜你喜欢
  • 2014-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-31
  • 1970-01-01
  • 1970-01-01
  • 2015-07-26
  • 2019-04-24
相关资源
最近更新 更多