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

it_*_*ure 7 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)
Run Code Online (Sandbox Code Playgroud)

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

使用以下pipelines.py,可以写入item ['author']和item ['quote'] /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
Run Code Online (Sandbox Code Playgroud)

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

Tom*_*art 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
Run Code Online (Sandbox Code Playgroud)

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