关闭sqlite db cur和con的最佳方法何时使用管道将数据写入sqlite

时间:2017-09-07 02:38:58

标签: sqlite scrapy

quotes.py是蜘蛛文件。

import scrapy    
from project.items import ProjectItem    

class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.toscrape.com']
    start_urls = ['http://quotes.toscrape.com/page/1']

    def parse(self, response):
        item = ProjectItem()
        for quote in response.css('div.quote'):
            item['quote'] = quote.css('span.text::text').extract_first()
            item['author'] = quote.xpath('span/small/text()').extract_first()
            yield item

        next_page = response.css('li.next a::attr("href")').extract_first()
        if next_page is not None:
            yield response.follow(next_page, self.parse)

每个页面中的作者和引用都是在项目中提取的。

使用以下pipelines.py,项目['作者']和项目['引用']可以写入/tmp/test.sqlite

import sqlite3
import json

class ProjectPipeline(object):
    def __init__(self):
        self.db = r'/tmp/test.sqlite'
        self.table = 'data'
        self.con = sqlite3.connect(self.db)
        self.cur = self.con.cursor()
        self.cur.execute("create table {table} (author TEXT,quote  TEXT)".format(table=self.table))

    def __del__(self):
        self.cur.close()
        self.con.close()

    def process_item(self, item, spider):
        self.cur.execute("INSERT INTO {table} VALUES(?,?);".format(table=self.table),(item['author'],item['quote']))            
        self.con.commit()
        return item

在运行sipder scrapy crawl quotes时有一点缺点,临时sqlite文件test.sqllite-journal总是在蜘蛛“#”期间打开/tmp目录时始终打开并进行打开,打开和逐渐打开。运行时间。
我想要一个更好的方法来完成任务 1.不是每个项目后都要承诺吗? 2.打开sqlite只有一次写入所有数据然后关闭它。

1 个答案:

答案 0 :(得分:4)

就个人而言,我认为你在每件物品后提交的最新方法都没有错。提交应该关闭逻辑工作单元(并且回滚,另一方面,应该在发生错误时丢弃它)。在我看来,被删除的项目是独立的,可以被认为是逻辑单元,因此提交是合法的。 (我甚至会说,因为它可以防止意外错误导致数据丢失。)

当然,您可以按照自己的建议进行操作,并在结束时存储所有数据。但为此,你必须在此期间将它们存储在内存中,并且根据项目的大小和数量,它可能是相当多的数据。但是,您可以选择折衷方案并使用已知大小的缓冲区,并在缓冲区已满时提交项目。请查看修改后的管道类的示例:

import sqlite3
import json                                                                                

class ProjectPipeline(object):
    def __init__(self):
        self.db = r'/tmp/test.sqlite'
        self.table = 'data'                                                     
        self.buff = list()                                                      
        self.buff_size = 20                                                     
        self.con = sqlite3.connect(self.db)                                     
        self.cur = self.con.cursor()                                            
        self.cur.execute("create table {table} (author TEXT,quote TEXT)".format(table=self.table))

    def __del__(self):                                                          
        if len(self.buff) > 0:                                                  
            self.cur.executemany("INSERT INTO {table} VALUES(?,?);".format(table=self.table),self.buff)
            self.con.commit()                                                   
        self.cur.close()                                                        
        self.con.close()                                                        

    def process_item(self, item, spider):                                       
        self.buff.append((item['author'],item['quote']))                        
        if len(self.buff) == self.buff_size:                                    
            self.cur.executemany("INSERT INTO {table} VALUES(?,?);".format(table=self.table),self.buff)
            self.con.commit()                                                   
            del self.buff[:]
        return item

缓冲区大小设置为20个项目,因此在每20个项目之后,它们将在数据库中提交。最好的是在settings.py中存储这些设置(以及数据库名称等)。