scrapy mysql django_在Scrapy中使用Django的ORM异步存储数据

本文介绍了如何在Scrapy爬虫项目中利用Django的ORM进行异步数据存储,以避免IO阻塞。通过初始化Django环境并在Scrapy的Pipeline中借助asyncio和ThreadPoolExecutor实现异步存储,显著提高了数据处理效率。对比显示,使用异步存储将原本10分钟的处理时间缩短到了40秒左右。
摘要由CSDN通过智能技术生成

在Scrapy中使用Django的ORM异步存储数据

django的orm可以脱离django使用,只要我们将django的环境舒适化就可以了。

在scrapy中使用

首先我们的创建一个django项目,然后在创建一个scrapy项目。

然后再scrapy中初始化django的环境

一般我们在scrapy的项目的__init__.py里面初始化

import django

import os

import sys

# 将django的项目路径加入到当前的环境

sys.path.insert(0, os.path.dirname(os.getcwd()))

# django项目舒适化

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'djangoProject.settings')

django.setup()

初始化完成之后,我们就可以直接在scrapy中导入django的orm并使用了。

异步存储

因为scrapy是异步的爬虫框架,如果我们在里面直接使用django的orm会有io阻塞的操作。这时候我们就借助asyncio这个包来帮助我们在scrapy中运行同步阻塞的代码。

因为我们scrapy中处理数据都放在pipline中处理,所以我放在pipline中展示

from concurrent.futures import ThreadPoolExecutor

import asyncio

from goods import models

from . import items

class WebspidersPipeline:

'''todo 异步存储'''

# 创建事件循环对象

loop = asyncio.get_event_loop()

# 创建线程池

executor = ThreadPoolExecutor()

# 任务队列

tasks = []

# 处理不同的pipline

async def process_item(self, item, spider):

if isinstance(item, items.GoodsItem):

return self.process_goods_item(item, spider)

elif isinstance(item, items.GoodsSizeItem):

return self.process_goods_size_item(item, spider)

elif isinstance(item, items.GoodsStockItem):

return self.process_goods_stock_item(item, spider)

return item

def process_goods_item(self, item, spider):

'''将保存数据的处理方法加入到任务队列'''

task = self.loop.run_in_executor(self.executor, self.executor_func(models.Goods, item), )

self.tasks.append(task)

return item

def process_goods_size_item(self, item, spider):

task = self.loop.run_in_executor(self.executor, self.executor_func(models.GoodsSize, item), )

self.tasks.append(task)

return item

def process_goods_stock_item(self, item, spider):

task = self.loop.run_in_executor(self.executor, self.executor_func(models.GoodsStock, item), )

self.tasks.append(task)

return item

@staticmethod

def executor_func(model, item):

'''主要作用是将有参数的函数转换为无参数的函数返回,方便run_in_executor方法调用,这个方法它只接受位置传参,不接受关键字传参'''

def func():

return model.objects.create(**item)

return func

def close_spider(self, spider):

'''当爬虫关闭的时候调用这个方法保存数据'''

self.loop.run_until_complete(asyncio.wait(self.tasks))

运行结果

之前直接使用同步的方法存储的时候,2000个请求+数据存储花费了大约10分钟(sqlite3)

后面使用异步存储的时候,使用sqlite3会报错,因为sqlite3是单线程的,我们是一个线程池对象,并发存储会被sqlite3拒绝(database was locked)

后面改用了mysql存储,2000个请求+数据存储花费了大约40s,这个提升量还是很惊人的。

后面分析了一下,在scrapy中使用同步的方式存储会导致scrapy的异步请求会等待同步的存储完成之后才去执行,大量的时间浪费了等待上面。

后面单独执行网络请求部分,没有数据存储,2000个请求花费了大约25s旁边。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值