Scrapy笔记:Scrapy爬取数据在Pipeline数据入库时,偶尔出现数据重复插入的情况

问题描述:用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

猜你喜欢

转载自blog.csdn.net/godot06/article/details/81290553