在Scrapy的异步数据库操作场景中,adbapi的runInteraction方法常用于将爬取到的item数据写入数据库,不少开发者在调用时会遇到item参数无法正确传递到do_insert方法的问题,导致数据写入失败。

runInteraction方法的基本调用逻辑
Scrapy的adbapi是对Twisted异步数据库接口的封装,runInteraction方法的作用是向数据库连接池提交一个交互操作,第一个参数是要执行的具体数据库操作函数(也就是do_insert),后续的可变参数会按顺序传递给这个操作函数。
很多开发者误以为runInteraction只能传递数据库连接对象,或者不知道后续参数的传递规则,才会出现item传不到do_insert的问题。
常见的参数传递错误写法
下面是一段典型的错误代码示例,很多新手会写出类似的逻辑:
import pymysql
from twisted.enterprise import adbapi
class MysqlPipeline:
def __init__(self):
# 创建数据库连接池
self.dbpool = adbapi.ConnectionPool(
'pymysql',
host='127.0.0.1',
port=3306,
user='root',
password='123456',
database='test_db',
charset='utf8'
)
def do_insert(self, cursor, item):
# 插入数据的SQL语句
sql = "INSERT INTO test_table (title, content) VALUES (%s, %s)"
# 错误:这里如果item没传过来,会报参数缺失的错误
cursor.execute(sql, (item['title'], item['content']))
def process_item(self, item, spider):
# 错误写法:只传了do_insert,没把item作为后续参数传递
self.dbpool.runInteraction(self.do_insert)
return item上面的代码中,runInteraction只传入了do_insert函数,没有把item作为参数传递,所以do_insert执行时拿不到item数据,会直接抛出异常。
正确的参数传递方式
runInteraction方法的签名是runInteraction(self, interaction, *args, **kw),其中*args和**kw会全部传递给interaction函数(也就是do_insert)。因此只要把item放在runInteraction的参数中,跟在do_insert后面即可。
正确的代码实现如下:
import pymysql
from twisted.enterprise import adbapi
class MysqlPipeline:
def __init__(self):
# 创建数据库连接池,这里使用127.0.0.1作为数据库地址
self.dbpool = adbapi.ConnectionPool(
'pymysql',
host='127.0.0.1',
port=3306,
user='root',
password='123456',
database='test_db',
charset='utf8'
)
def do_insert(self, cursor, item):
# 插入数据的SQL语句,这里接收cursor和传递过来的item
sql = "INSERT INTO test_table (title, content) VALUES (%s, %s)"
cursor.execute(sql, (item['title'], item['content']))
# 不需要手动提交,adbapi会自动处理事务
def process_item(self, item, spider):
# 正确写法:把item作为第二个参数传递给runInteraction,它会自动传给do_insert
self.dbpool.runInteraction(self.do_insert, item)
return item参数传递的注意事项
- do_insert函数的第一个参数固定是cursor对象,由adbapi自动传入,从第二个参数开始才是我们传递的自定义参数,所以item要作为第二个参数放在runInteraction中
- 如果需要传递多个参数,比如除了item还要传递spider信息,可以写成
self.dbpool.runInteraction(self.do_insert, item, spider),对应的do_insert需要定义为def do_insert(self, cursor, item, spider): - 如果item是Scrapy的Item对象,传递时不需要额外处理,直接作为参数传入即可,adbapi会正确处理对象的传递
验证参数是否传递成功
可以在do_insert方法中添加打印语句验证参数是否传递到位:
def do_insert(self, cursor, item):
# 打印item内容,验证是否传递成功
print("接收到的item数据:", dict(item))
sql = "INSERT INTO test_table (title, content) VALUES (%s, %s)"
cursor.execute(sql, (item['title'], item['content']))运行爬虫后如果能正常打印出item的内容,并且数据成功写入数据库,就说明参数传递是正确的。
ScrapyadbapirunInteractiondo_insertitem参数传递修改时间:2026-05-31 23:41:47