问题描述:用Scrapy来爬取某论坛数据,在数据导入mysql数据库中,一直有个别数据重复插入。
修改之前代码:
class AyncMysqlPipeline(object):
# 初始化数据库连接
def __init__(self):
dbparms = dict(
host='127.0.0.1',
db='jobarticle',
...
)
# 设置连接池
self.dbpool=adbapi.ConnectionPool('MySQLdb',**dbparms)
def do_insert(self,cursor,item):
insert_sql = """
insert into article (title,author)
value (%s,%s)
"""
cursor.execute(insert_sql, (item['title'], item['author']))
def handle_error(self,failure):
print(failure)
def process_item(self,item,spider):
query=self.dbpool.runInteraction(self.do_insert,item)
query.addErrback(self.handle_error)
return item
产生问题原因分析:
由于Scrapy框架是异步框架,Scrapy的Spider的执行速度较快,而Scapy执行数据库操作相对Spider较慢,因此使得Pipeline中的方法调用也较慢,所以当一个Item正在处理的时候,Spider又传来一个新的变量过来,之前的变量的值就会被覆盖
,举个例子,假设Pipline的速率是1M/S,而Spider的速率是3M/S,那么此时的Pipeline就会执行数据库3次,也就应该会有3条重复数据。
解决方法:
在process_item中执行数据插入之前,先对变量进行复制copy,再用复制copy的变量进行操作,通过互斥确保变量不被修改。因此,修正这个问题,我们只需要调整优化下process_item()方法。
解决代码:process_item() - copy.deepcopy(item) ->导入copy包
def process_item(self,item,spider):
#对象拷贝 深拷贝
asynItem = copy.deepcopy(item) #需要导入import copy
query=self.dbpool.runInteraction(self.do_insert,asynItem)
query.addErrback(self.handle_error)
return item