Python爬虫:Scrapy使用adbapi提高存储数据库效率
运行环境 Runtime environment
1 2 3 4
| 操作系统: Windos10 IDE: pycharm 2021.3.1 x64 语言: python v3.9.1 框架: Scrapy
|
背景
Scrapy 是一个高性能的异步采集框架,采集速度非常快,但是数据库入库受限于数据库本身的原因,一直是个瓶颈。
在某些爬虫项目下,我们需要每次执行一条插入语句,就立即调用commit方法更新数据库。
如果爬取时间太长,中途可能被迫中断,这样程序就不能执行close_spider中的commit。
但如果在insert_db中直接加入commit,又会使程序执行变得很慢。
这里就可以使用Twisted中提供的以异步方式多线程访问数据库的模块adbapi,可以显著提供程序访问数据库的效率。
要点
adbapi.ConnectionPool方法
可以创建一个数据库连接池对象,其中包括多个连接对象,每个连接对象在独立的线程中工作。
adbapi只是提供了异步访问数据库的编程框架,再其内部依然使MySQLdb这样的库访问数据库。
dbpool.runInteraction(insert_db,item)
以异步方式调用insert_db函数,dbpool会选择连接池中的一个连接对象在独立线程中调用insert_db,
其中参数item会被传给insert_db的第二个参数,传给insert_db的第一个参数是一个Transaction对象,
其接口与Cursoru游标对象类似,
可以调用execute方法执行SQL语句,insert_db执行后,连接对象会自动调用commit方法
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| import scrapy import pymysql from itemadapter import ItemAdapter from twisted.enterprise import adbapi
class MysqlSpiderBasePipeline: def __init__(self, dbpool, item_tabla_map): self.dbpool = dbpool
@classmethod def from_crawler(cls, cralwer): db_parmars = { 'host': cralwer.settings['MYSQL_HOST'], 'user': cralwer.settings['MYSQL_USER'], 'passwd': cralwer.settings['MYSQL_PWD'], 'db': cralwer.settings['MYSQL_DB'], 'port': cralwer.settings['MYSQL_PORT'], 'charset': cralwer.settings['MYSQL_CHARSET'] } dbpool = adbapi.ConnectionPool('pymysql', **db_parmars) return cls(dbpool)
def process_item(self, item, spider): query = self.dbpool.runInteraction( self.insert_data_to_mysql, item ) query.addErrback( self.insert_err, item ) return item
def insert_err(self, failure, item): print(failure, '失败')
def insert_data_to_mysql(self, cursor, item): pass
class SpiderPipeline(MysqlSpiderBasePipeline): def insert_data_to_mysql(self, cursor, item): sql, data = item.get_update_sql() cursor.execute(sql, data)
|
总结
Scrapy 异步 更新 或 插入, 都能有效提高入库效率。
但是这对数据库本身的性能也有要求,如果数据库本身性能不行,
那也是逼着Scrapy”八车道”变成”两车道”,入库时常太长了,
还可能导致数据库游标cursor超时断开,出现 pymysql.err.InterfaceError: (0, ‘’) 的报错。
出现的原因是没有连接到数据库,或者数据库在爬虫的过程中断开了。