前言:
Item是Scrapy中用于保存爬取到的数据的容器,而Scrapy-Redis在存储Item时带来了一些变化和灵活性。因此,需要把它单独摘出来讲一讲,很重要!
正文:
存储形式
Scrapy-Redis中的Item存储方式可以有多种形式,以下是几种常见的形式及其适用情况:
- 存储为字典形式: 在Scrapy-Redis中,Item可以被转换为字典形式,并以JSON字符串的形式存储到Redis中。这种形式适用于存储结构简单的数据,例如只包含几个字段的Item。字典形式的Item便于存储和解析,并且可以提供较好的可读性。
- 存储为二进制数据(BLOB): Scrapy-Redis还允许将Item以二进制数据的形式存储到Redis中,而不是转换为字典形式。这种形式适用于需要保存复杂结构的Item,包括嵌套的数据结构或二进制数据。将Item存储为二进制数据可以更好地保留其原有的数据结构和格式,但在读取和处理时需要进行适当的解析和转换。
- 存储为Hash结构: Redis中的Hash结构可以用于存储Item数据,其中Item的字段名作为Hash的键,字段值作为Hash的值。这种形式适用于存储字段较多或结构复杂的Item数据。Hash结构的存储方式提供了一种有效的方式来组织和查询Item数据,可以方便地根据字段名进行查找和更新操作。
区别与正常的Scrapy中的Item:
与正常的Scrapy中的Item相比,Scrapy-Redis存储Item的操作范围发生了变化,并引入了更多的灵活性和可扩展性。
- 存储位置: 在正常的Scrapy中,Item通常是通过Pipeline存储到本地文件或数据库中。而在Scrapy-Redis中,Item一般存储到Redis中,以便在分布式环境中实现多个Scrapy进程之间的数据共享和协同工作。
- 存储格式: 在正常的Scrapy中,Item通常是以字典的形式进行存储和传递。而在Scrapy-Redis中,Item可以以多种形式进行存储,包括字典形式、二进制数据形式或Hash结构形式,具体选择取决于数据结构的复杂性和存储需求。
- 存储方式的灵活性: Scrapy-Redis提供了多种存储Item的方式,可以根据具体需求选择最适合的方式。通过灵活的存储方式,可以更好地适应不同类型和结构的数据,提供更大的存储和处理灵活性。
当一个Scrapy-Redis爬虫有多个Item时,可以采取以下几种解决方案:
-
使用单一的Redis Key:将多个Item存储到相同的Redis Key 下。在Pipeline中判断不同的Item类型,根据Item类型的不同,将数据转换成对应的格式存储到Redis中。这种方法适用于Item之间的数据没有强关联性,且数量较少的情况。
-
使用不同的Redis Key:为每个Item类型分别指定不同的Redis Key,将不同类型的Item存储到不同的Key下。在Pipeline中根据Item类型,选择对应的Redis Key 进行存储。这种方法适用于Item之间有明显的区分和逻辑关系,并且数量较多的情况。
-
使用Hash结构存储:将多个Item作为Hash结构的字段存储到Redis中。每个Item类型对应Hash结构的一个字段,字段名为Item类型,字段值为Item数据的序列化形式(如JSON字符串)。通过Hash结构的存储方式,可以方便地组织和管理多个Item,并且保持数据结构的完整性。
针对这些解决方案,需要在Item Pipeline中实现相应的逻辑。根据不同的场景和需求,选择最适合的方案进行实现。同时,在Spider中生成不同类型的Item时,确认将其传递到对应的Pipeline中进行处理和存储。
案例分析:
当一个Scrapy-Redis爬虫有多个不同的Items,并且希望将这些Items最后存储到SQL数据库中,按照表格进行划分,可以按照以下步骤完成:
创建不同类型的Items: 首先,创建5个不同的Items,分别对应于要存储到SQL数据库中的不同表格。确保每个Item都有与之对应的字段,以便正确存储数据。
import scrapy
class ItemA(scrapy.Item):
# Item A的字段
field_a1 = scrapy.Field()
field_a2 = scrapy.Field()
...
class ItemB(scrapy.Item):
# Item B的字段
field_b1 = scrapy.Field()
field_b2 = scrapy.Field()
...
# 定义其他的Items (ItemC, ItemD, ItemE)
编写Pipeline进行数据存储: 创建一个自定义的Pipeline类,用于将爬取到的每个Item存储到相应的表格中。在Pipeline中实现process_item
方法,在该方法中根据Item类型的不同,将数据存储到对应的表格中。
import pymysql
class SQLPipeline(object):
def open_spider(self, spider):
# 初始化连接数据库的操作
self.connection = pymysql.connect(
host='localhost',
user='your_username',
password='your_password',
db='your_database'
)
self.cursor = self.connection.cursor()
def close_spider(self, spider):
# 在爬虫结束时关闭数据库连接
self.cursor.close()
self.connection.close()
def process_item(self, item, spider):
if isinstance(item, ItemA):
self.save_to_table_a(item)
elif isinstance(item, ItemB):
self.save_to_table_b(item)
# 处理其他Items (ItemC, ItemD, ItemE)
def save_to_table_a(self, item):
# 将Item A的数据存储到对应的表格
sql = "INSERT INTO table_a (field_a1, field_a2) VALUES (%s, %s)"
values = (item['field_a1'], item['field_a2'])
self.cursor.execute(sql, values)
self.connection.commit()
def save_to_table_b(self, item):
# 将Item B的数据存储到对应的表格
sql = "INSERT INTO table_b (field_b1, field_b2) VALUES (%s, %s)"
values = (item['field_b1'], item['field_b2'])
self.cursor.execute(sql, values)
self.connection.commit()
# 实现其他的存储方法 (save_to_table_c, save_to_table_d, save_to_table_e)
配置Pipeline: 在Scrapy的配置文件(settings.py)中,将创建的Pipeline类加入到ITEM_PIPELINES
设置中,并根据需要设置其优先级。确保该Pipeline的优先级较高,以便在数据存储时被优先调用。
ITEM_PIPELINES = {
'myproject.pipelines.SQLPipeline': 300,
# 其他的Pipeline
}
启动爬虫: 在主程序中启动爬虫,使用Scrapy提供的CrawlerProcess来创建Crawler实例,并指定要运行的爬虫和相关设置。
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings
from myproject.spiders import MySpider
# 将爬虫和相关设置传递给CrawlerProcess
process = CrawlerProcess(get_project_settings())
process.crawl(MySpider)
process.start()
将Scrapy-Redis爬虫中的多个不同的Items按照表格的形式存储到SQL数据库中。通过自定义Pipeline来处理每个Item并将其存储到相应的表格中,实现数据的持久化存储。