2.2 Items (数据项) Scrapy 核心组件:Items (数据项) 详解 在Scrapy爬虫框架中,Items扮演着至关重要的角色,它们定义了我们想要抓取的数据结构。可以将Items视为Python字典的简单容器,用于收集抓取到的数据。与字典相比,Items提供了额外的保护机制,防止不规范的数据填充,并允许声明输出数据的类型。 Items 的作用与优势 数据结构化: Items 预先定义了数据的结构,使得抓取到的数据更加规范和易于管理。 类型检查: Items 可以定义每个字段的数据类型,确保数据的正确性和一致性。 易于处理: Items 使得后续的数据处理、存储和导出更加方便。 减少错误: 通过预定义字段和类型,可以有效减少因拼写错误或数据类型不匹配导致的错误。
在Scrapy爬虫框架中,Items扮演着至关重要的角色,它们定义了我们想要抓取的数据结构。可以将Items视为Python字典的简单容器,用于收集抓取到的数据。与字典相比,Items提供了额外的保护机制,防止不规范的数据填充,并允许声明输出数据的类型。
数据结构化: Items 预先定义了数据的结构,使得抓取到的数据更加规范和易于管理。
类型检查: Items 可以定义每个字段的数据类型,确保数据的正确性和一致性。
易于处理: Items 使得后续的数据处理、存储和导出更加方便。
减少错误: 通过预定义字段和类型,可以有效减少因拼写错误或数据类型不匹配导致的错误。
Items 在 Scrapy 项目中通过 items.py 文件定义。每个 Item 都是 scrapy.Item 类的子类。Item 的字段使用 scrapy.Field 类定义。
示例:
假设我们要抓取一个图书网站,需要提取书名、作者和价格。我们可以在 items.py 文件中定义如下 Item:
# items.py import scrapy class BookItem(scrapy.Item): name = scrapy.Field() author = scrapy.Field() price = scrapy.Field() description = scrapy.Field() image_url = scrapy.Field()
在这个例子中,BookItem 类继承自 scrapy.Item,并定义了四个字段:name、author、price、description、image_url。每个字段都使用 scrapy.Field() 进行声明。scrapy.Field() 实际上只是一个占位符,用于声明字段的存在,它本身并没有实际的功能。
在 Spider 中,我们可以创建 Item 实例,并将抓取到的数据填充到 Item 中。
示例:
# spider.py import scrapy from myproject.items import BookItem class BookSpider(scrapy.Spider): name = "bookspider" start_urls = ['http://books.toscrape.com/'] def parse(self, response): for book in response.css('article.product_pod'): item = BookItem() item['name'] = book.css('h3 a::text').get() item['author'] = 'Unknown' #假设网站没有作者信息,可以设置默认值 item['price'] = book.css('p.price_color::text').get() item['description'] = 'No description available' #设置默认值 item['image_url'] = response.urljoin(book.css('a img::attr(src)').get()) yield item
在这个例子中,我们在 parse 方法中创建了一个 BookItem 实例,并将从网页中抓取到的数据分别赋值给 Item 的各个字段。最后,使用 yield item 将 Item 传递给 Scrapy 引擎,由引擎负责后续的处理(例如,传递给 Item Pipeline)。
Item Pipelines 是 Scrapy 的一个核心组件,负责处理 Spider 提取出的 Items。Item Pipelines 可以执行各种操作,例如:
数据清洗: 清理 Item 中的数据,例如去除空格、转换数据类型等。
数据验证: 验证 Item 中的数据是否符合规范。
数据存储: 将 Item 中的数据存储到数据库、文件或其他存储介质中。
去重: 过滤掉重复的 Item。
示例:
假设我们要将抓取到的图书数据存储到 MongoDB 数据库中。我们可以创建一个 Item Pipeline 来实现这个功能。
# pipelines.py import pymongo class MongoDBPipeline: collection_name = 'books' def __init__(self, mongo_uri, mongo_db): self.mongo_uri = mongo_uri self.mongo_db = mongo_db @classmethod def from_crawler(cls, crawler): return cls( mongo_uri=crawler.settings.get('MONGO_URI'), mongo_db=crawler.settings.get('MONGO_DATABASE', 'items') ) def open_spider(self, spider): self.client = pymongo.MongoClient(self.mongo_uri) self.db = self.client[self.mongo_db] def close_spider(self, spider): self.client.close() def process_item(self, item, spider): self.db[self.collection_name].insert_one(dict(item)) return item
在这个例子中,MongoDBPipeline 类实现了将 Item 存储到 MongoDB 数据库的功能。process_item 方法是 Item Pipeline 的核心方法,它接收一个 Item 和一个 Spider 作为参数,并对 Item 进行处理。在这个例子中,我们将 Item 转换为字典,并将其插入到 MongoDB 数据库中。
要启用 Item Pipeline,需要在 settings.py 文件中进行配置:
# settings.py ITEM_PIPELINES = { 'myproject.pipelines.MongoDBPipeline': 300, } MONGO_URI = 'mongodb://localhost:27017/' MONGO_DATABASE = 'scrapy_db'
ITEM_PIPELINES 是一个字典,键是 Item Pipeline 的类名,值是 Item Pipeline 的优先级。优先级越低,Item Pipeline 越先执行。
Input/Output Processors: 可以为 Item 的字段定义 Input/Output Processors,用于在数据填充和提取时对数据进行处理。例如,可以使用 Input Processor 对抓取到的价格数据进行清洗,去除货币符号和空格,并将其转换为浮点数。
Item Loaders: Item Loaders 提供了一种更方便的方式来填充 Item。Item Loaders 可以自动从网页中提取数据,并将其填充到 Item 的相应字段中。
以下是一个使用 Mermaid 绘制的 Item 处理流程图:
图表解释:
Spider: 负责从网页中抓取数据。
Item: 存储抓取到的数据。
Item Pipeline: 负责处理 Item。
Data Cleaning: 清理 Item 中的数据。
Data Validation: 验证 Item 中的数据。
Data Storage: 将 Item 中的数据存储到数据库或其他存储介质中。
Items 是 Scrapy 框架中用于定义数据结构的重要组件。通过使用 Items,我们可以更好地组织和管理抓取到的数据,并减少因数据类型不匹配或拼写错误导致的错误。Item Pipelines 则提供了强大的数据处理能力,可以对 Item 进行清洗、验证、存储等操作。掌握 Items 的使用,可以有效提升 Scrapy 爬虫的开发效率和数据质量。
为了更全面地展示Item的用法,我们补充一些示例,展示Input/Output Processors以及Item Loaders的使用。
8.1 Input/Output Processors
假设我们需要对BookItem的价格进行处理,去除货币符号并转换为浮点数。
import scrapy from scrapy.loader.processors import MapCompose, TakeFirst def remove_currency(value): return value.replace('£', '').strip() def convert_to_float(value): try: return float(value) except ValueError: return None class BookItem(scrapy.Item): name = scrapy.Field() author = scrapy.Field() price = scrapy.Field( input_processor=MapCompose(remove_currency, convert_to_float), output_processor=TakeFirst() ) description = scrapy.Field() image_url = scrapy.Field()
在这个例子中:
remove_currency 函数用于移除货币符号。
convert_to_float 函数用于将字符串转换为浮点数。
MapCompose 用于将多个函数依次应用于输入值。
TakeFirst 用于从输出列表中取出第一个值。
8.2 Item Loaders
Item Loaders 提供了一种更便捷的方式来填充 Item,尤其是当网页结构比较复杂时。
import scrapy from scrapy.loader import ItemLoader from scrapy.loader.processors import MapCompose, TakeFirst def remove_currency(value): return value.replace('£', '').strip() def convert_to_float(value): try: return float(value) except ValueError: return None class BookItem(scrapy.Item): name = scrapy.Field() author = scrapy.Field() price = scrapy.Field( input_processor=MapCompose(remove_currency, convert_to_float), output_processor=TakeFirst() ) description = scrapy.Field() image_url = scrapy.Field() class BookLoader(ItemLoader): default_output_processor = TakeFirst() class BookSpider(scrapy.Spider): name = "bookspider" start_urls = ['http://books.toscrape.com/'] def parse(self, response): for book in response.css('article.product_pod'): loader = BookLoader(item=BookItem(), selector=book) loader.add_css('name', 'h3 a::text') loader.add_value('author', 'Unknown') #设置默认值 loader.add_css('price', 'p.price_color::text') #loader.add_value('description', 'No description available') #设置默认值 loader.add_css('image_url', 'a img::attr(src)') yield loader.load_item()
在这个例子中:
我们定义了一个 BookLoader 类,继承自 ItemLoader。
loader.add_css 方法用于从 CSS 选择器中提取数据,并将其填充到 Item 的相应字段中。
loader.add_value 方法用于直接设置 Item 的字段值。
loader.load_item() 方法用于返回填充好的 Item。
使用Item Loaders可以使Spider代码更加简洁和易于维护。
希望这些补充示例能够帮助你更深入地理解Items的用法。