我正在尝试这个示例代码
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
就不再起作用了?有人可以用一种简单的方式解释这个吗?
你问为什么第二个代码不起作用,但我不认为你完全理解为什么第一个代码工作:)
第一个代码的for
循环只循环一次。
发生的事情是:
self.parse()
中调用self.start_urls
的URL。self.parse()
从self.urls
获取第一个(也是第一个!)URL,并返回它,退出self.parse()
。self.parse()
再次被调用,这次它从self.urls
返回第二个URL的请求(只有1个请求!),因为之前对self.parse()
的调用已经消耗了它的第一个URL(self.urls
是一个iterator)。最后一步在循环中重复,但它不是for
循环。
您可以将原始代码更改为此代码,它将以相同的方式工作:
def parse(self, response):
try:
return next(self.urls)
except StopIteration:
pass
因为要调用项目/请求它应该是生成器函数。你甚至不能在具有相同“意义”的相同功能中使用yield
和return
,它会提升SyntaxError: 'return' with argument inside generator
。
return
(几乎)相当于提高StopIteration。在这个主题Return and yield in the same function你可以找到非常详细的解释,链接规范。