Scrapy / Python产生并继续处理可能吗?

时间:2019-04-17 16:29:56

标签: python scrapy return yield

我正在尝试此示例代码

from scrapy.spiders import Spider, Request  
import scrapy

class MySpider(Spider):

    name = 'toscrapecom'
    start_urls = ['http://books.toscrape.com/catalogue/page-1.html']

    urls = (
        'http://books.toscrape.com/catalogue/page-{}.html'.format(i + 1) for i in range(50)
    )

    def parse(self, response):
        for url in self.urls:
            return Request(url)

它可以很好地爬行所有页面。但是,如果我在for循环之前生成了一个项目,则它只会抓取第一页。 (如下所示)

from scrapy.spiders import Spider, Request  
import scrapy

class MySpider(Spider):

    name = 'toscrapecom'
    start_urls = ['http://books.toscrape.com/catalogue/page-1.html']

    urls = (
        'http://books.toscrape.com/catalogue/page-{}.html'.format(i + 1) for i in range(50)
    )

    def parse(self, response):
        yield scrapy.item.Item()
        for url in self.urls:
            return Request(url)

但是我可以使用yield Request(url)代替return...,它会将页面从最后一页向后刮到第一页。

我想了解为什么return产生item后不再起作用?有人可以用简单的方式解释吗?

2 个答案:

答案 0 :(得分:1)

您问为什么第二个代码不起作用,但是我认为您不完全理解第一个代码为什么起作用:)

第一个代码的for循环仅循环一次

正在发生的事情是:

    self.parse()中的URL调用
  1. self.start_urls

  2. self.parse()self.urls获取第一个(也是第一个!)URL,然后将其返回,退出self.parse()

  3. 当第一个URL的响应到达时,self.parse()再次被调用,这一次它从self.urls返回对第二个URL的请求(仅一个请求!),因为先前对self.parse()的调用已经消耗了它的第一个URL(self.urlsiterator)。

最后一步在一个循环中重复,但不是for循环执行。

您可以将原始代码更改为此,并且将以相同的方式工作:

def parse(self, response):
    try:
        return next(self.urls)
    except StopIteration:
        pass

答案 1 :(得分:0)

由于要调用项目/请求,因此应为 generator 函数。 您甚至不能在具有相同“含义”的同一函数中使用MyApp::Application.config.session_store :cookie_store, domain: 'something.rootdomain.com' yield,它将引发return

SyntaxError: 'return' with argument inside generator(几乎)等同于提高StopIteration。在本主题Return and yield in the same function中,您可以找到非常详细的说明以及链接说明。