Scrapy如何将多级页面爬取到一个item?
How to crawl multiple-level pages to one item in Scrapy?
我找到的所有关于 Scrapy 的例子都在谈论如何爬取单个页面,或者如何爬取多级页面,当每个最深的页面被保存为一个独立的 Item
。但是我的情况有点复杂。
例如网站结构为:
A (List page of books)
--> B (Book summary page)
----> C (Book review pages)
----> D (Book download pages)
因此 Item
的定义如下所示:
class BookItem(scrapy.Item):
name = scrapy.Field()
type = scrapy.Field()
introduction = scrapy.Field()
resources = scrapy.Field() # To be a list of ResourceItem
reviews = scrapy.Field() # To be a list of ReviewItem
# Download pages
class ResourceItem(scrapy.Item):
title = scrapy.Field()
createDate = scrapy.Field()
author = scrapy.Field()
link = scrapy.Field()
# Book reviews
class ReviewItem(scrapy.Item):
title = scrapy.Field()
createDate = scrapy.Field()
author = scrapy.Field()
content = scrapy.Field()
我怎样才能完成 BookItem
的所有字段?我 do 知道我可以写 4 个方法,比如 parse_A()
、parse_B()
、parse_C()
和 parse_D()
,Scrapy 允许它们通过在每个方法的末尾使用 yield scrapy.Request()
成为工作流程。
但是我应该return在最深的方法中,即parse_C()
和parse_D()
?
- 如果我return一个
ResourceItem
或ReviewItem
,会直接保存
- 如果我return上面的方法
BookItem
,未完成的项目也会直接保存
- 如果我return a
Request
for parse_D()
in parse_C()
,同样不行,因为资源可能是空的(也就是说可能有是 B 页面上根本没有 C 的链接)。所以 parse_C()
不会被调用,留下 parse_D()
未被调用,最后 D 字段未填充。
您可以使用 meta
参数传递一些数据(参见 https://docs.scrapy.org/en/latest/topics/request-response.html)。
因此您可以在多个 requests/parse 函数中填充您的项目。
显示逻辑的快速示例:
def parse_summary(self, response):
book_item = # scrape book item here
reviews_url = # extract reviews url
resources_url = # extract resources url
return scrapy.Request(reviews_url, callback=self.parse_reviews, meta={'item': book_item, 'resources_url': resources_url })
def parse_reviews(self, response):
book_item = response.meta.get('item') # get item draft
book_item.reviews = # extract reviews here
resources_url = response.meta.get('resources_url')
return scrapy.Request(resources_url, callback=self.parse_resources, meta={'item': book_item })
def parse_resources(self, response):
book_item = response.meta.get('item') # get item draft
book_item.ressources = # extract ressources here
return book_item # once completed, return the item
希望你明白了(我对代码执行不是很有信心,只是没有测试就写下来了)。
我现在可以自己回答了
只需 yield None
或 省略 return 语句 在 parse_C()
和 parse_D()
将解决问题。
一些解释
Scrapy 不会关闭蜘蛛 只是 因为回调之一 return 什么都没有,但要确保请求队列中也没有新的回调。
因此,由于 parse_B()
在完成产生子页面 C 和 D 的所有请求之前不会 return None
或 Item
,因此工作流不会被打扰了。
我找到的所有关于 Scrapy 的例子都在谈论如何爬取单个页面,或者如何爬取多级页面,当每个最深的页面被保存为一个独立的 Item
。但是我的情况有点复杂。
例如网站结构为:
A (List page of books)
--> B (Book summary page)
----> C (Book review pages)
----> D (Book download pages)
因此 Item
的定义如下所示:
class BookItem(scrapy.Item):
name = scrapy.Field()
type = scrapy.Field()
introduction = scrapy.Field()
resources = scrapy.Field() # To be a list of ResourceItem
reviews = scrapy.Field() # To be a list of ReviewItem
# Download pages
class ResourceItem(scrapy.Item):
title = scrapy.Field()
createDate = scrapy.Field()
author = scrapy.Field()
link = scrapy.Field()
# Book reviews
class ReviewItem(scrapy.Item):
title = scrapy.Field()
createDate = scrapy.Field()
author = scrapy.Field()
content = scrapy.Field()
我怎样才能完成 BookItem
的所有字段?我 do 知道我可以写 4 个方法,比如 parse_A()
、parse_B()
、parse_C()
和 parse_D()
,Scrapy 允许它们通过在每个方法的末尾使用 yield scrapy.Request()
成为工作流程。
但是我应该return在最深的方法中,即parse_C()
和parse_D()
?
- 如果我return一个
ResourceItem
或ReviewItem
,会直接保存 - 如果我return上面的方法
BookItem
,未完成的项目也会直接保存 - 如果我return a
Request
forparse_D()
inparse_C()
,同样不行,因为资源可能是空的(也就是说可能有是 B 页面上根本没有 C 的链接)。所以parse_C()
不会被调用,留下parse_D()
未被调用,最后 D 字段未填充。
您可以使用 meta
参数传递一些数据(参见 https://docs.scrapy.org/en/latest/topics/request-response.html)。
因此您可以在多个 requests/parse 函数中填充您的项目。
显示逻辑的快速示例:
def parse_summary(self, response):
book_item = # scrape book item here
reviews_url = # extract reviews url
resources_url = # extract resources url
return scrapy.Request(reviews_url, callback=self.parse_reviews, meta={'item': book_item, 'resources_url': resources_url })
def parse_reviews(self, response):
book_item = response.meta.get('item') # get item draft
book_item.reviews = # extract reviews here
resources_url = response.meta.get('resources_url')
return scrapy.Request(resources_url, callback=self.parse_resources, meta={'item': book_item })
def parse_resources(self, response):
book_item = response.meta.get('item') # get item draft
book_item.ressources = # extract ressources here
return book_item # once completed, return the item
希望你明白了(我对代码执行不是很有信心,只是没有测试就写下来了)。
我现在可以自己回答了
只需 yield None
或 省略 return 语句 在 parse_C()
和 parse_D()
将解决问题。
一些解释
Scrapy 不会关闭蜘蛛 只是 因为回调之一 return 什么都没有,但要确保请求队列中也没有新的回调。
因此,由于 parse_B()
在完成产生子页面 C 和 D 的所有请求之前不会 return None
或 Item
,因此工作流不会被打扰了。