Scrapy高并发数据库写入

前言

爬虫过程中不可缺少的环节就是数据存储,一般来说这些数据首选是保存到数据库中。但是数据库写的方式是同步写入,能不能像 request 请求那样遇到这种 I/O 操作就去执行其他任务呢?答案是可以的。

Scrapy异步写入

Scrapy 是基于 Twisted 库实现的爬虫框架,而 Twisted 库已经为我们准备好了异步写入数据库的方法,配置也很简单,在 pipelines.py 里定义一个类,并实现这几个方法就好。

from twisted.enterprise import adbapi

import pymysql
import pymysql.cursors

# Twisted高并发的mysql插入
class MysqlTwistedPipeline(object):
    def __init__(self, dbpool):
        self.dbpool = dbpool

    @classmethod
    def from_settings(cls, settings):
    	# 数据库配置
		pass

    def process_item(self, item, spider):
        # 使用Twisted将mysql插入变成异步执行
		pass

    def handle_error(self, failure, item, spider):
        # 处理异步插入的异常
		pass

    def do_insert(self, cursor, item):
        # 执行具体插入
		pass

函数解释

from_settings, 类方法, 从字面意思也不难理解,它的功能就是定义一个连接池,传入两个参数: settingscls 并返回一个连接池对象供数据库读写时调用。具体实现代码如下:

@classmethod
def from_settings(cls, settings):
    # 数据库配置
    dbparms = dict(
        host=settings["MYSQL_HOST"],  # 数据库Host
        database=settings["MYSQL_DBNAME"],	# 数据库名
        user=settings["MYSQL_USER"],	#数据库用户名
        password=settings["MYSQL_PASSWORD"],	#数据库密码
        charset='utf8', # 使用的字符集
        cursorclass=pymysql.cursors.DictCursor,	# 将游标类型设置为字典形式
        use_unicode=True # 使用unicode格式
    )
    dbpool = adbapi.ConnectionPool("pymysql", **dbparms) 
    return cls(dbpool) 返回一个

数据库配置的字段名不能随便乱起,在 pymysql.connections 有定义规则:
connections.py
clscls 主要用在类方法定义,而 self 则是实例方法。
普通的实例方法,第一个参数需要是 self ,它表示一个具体的实例本身。
如果用了 staticmethod ,那么就可以无视这个 self ,而将这个方法当成一个普通的函数使用。
而对于 classmethod ,它的第一个参数不是self,是cls,它表示这个类本身。

settings 可以理解为我们工程的 settings.py 文件对象,我们在函数传入 settings 参数,这样才可以在其他文件里调用 settings.py 里的内容,通过字典的方式可以调用参数,比如下面这四个:
settings.py中定义
这是数据库的配置,我在 settings.py 的最下方有如下定义,下面这些参数名可以自己起,方便使用即可

MYSQL_HOST = "host"
MYSQL_DBNAME = "dbname"
MYSQL_USER = "username"
MYSQL_PASSWORD = "password"

process_item, 数据库的写入就是在该函数下操作的,异步逻辑就是在它下面实现的:

def process_item(self, item, spider):
    # 使用Twisted将mysql插入变成异步执行
    query = self.dbpool.runInteraction(self.do_insert, item)  # 该方法会把我们的函数变为异步的,返回一个 query 对象,第一个就是执行函数,第
    															二个item就是我们要写入的数据
    query.addErrback(self.handle_error, item, spider)  # 异步处理出错时执行, 第一个是错误处理函数,

do_insert, 这个就是我定义的写入函数,名字随意,而且自动帮我们 commit

def do_insert(self, cursor, item):
    # 执行具体插入
    insert_sql = """
        insert into table(column1,column2,column3) values ("%s", "%s", "%s")
    """
    data = (item["字段一"], item["字段二"], item["字段三"])
    cursor.execute(insert_sql % data)

handle_error, 异常处理,名字随意,4个参数,第一个是对象本身,第二个就是具体failure,第三个是item,第四个是当前spider,后面两个参数可以忽略,那上方 query.addErrback(self.handle_error) 就可以这样了

 def handle_error(self, failure, item, spider):
     # 处理异步插入的异常
     print(failure)

最后我们把这个类在 settings.py 中声明,我的工程名是 douban

ITEM_PIPELINES = {
   'douban.pipelines.MysqlTwistedPipeline': 1,
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值