2017-09-07 13 views
8

quotes.pyはスパイダーファイルです。パイプラインでsqliteにデータを書き込むときにsqlite db curとconを閉じる最も良い方法

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を使用すると、アイテム['author']とアイテム['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 

scrapy crawl quotes sipder実行するために、tempary sqliteのファイルtest.sqllite-journalは常に開かれてcolsed、開かれ、クモの実行時間中に/tmpディレクトリを開こうとした時、連続colsed小さな欠点があります。
私はタスクを完了させるためのより良い方法が欲しいです。
1.すべての項目の後にコミットしませんか?
2.すべてのデータを書き込んで閉じます。

+0

なぜすべてのアイテムの後にコミットしていますか? –

+0

どのように作業プロセスをより合理的にするには? –

答えて

4

個人的に私はすべての項目の後にコミットのあなたのcurrectのアプローチに間違いを参照してください。コミットは論理作業単位を終了する必要があります(また、ロールバックすると、エラーの場合は破棄する必要があります)。私の目では、削られたアイテムは独立しており、コミットが正当なものであるため論理ユニットと考えることができます。 (予期せぬエラーが発生した場合のデータ損失を防止するため、希望通りと言えます。)

もちろん、最後に一度データを保存しておくこともできます。しかしそのためには、その間にそれらをメモリに保存しなければならず、アイテムのサイズや数に応じて、かなりのデータになる可能性があります。しかし、妥協案を選んで、既知のサイズのバッファを使用し、バッファがいっぱいになるとアイテムをコミットすることができます。変更したパイプラインのクラスのこの例を見てください:すべての20の項目の後、彼らはデータベースにコミットしますので

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の項目に設定されています。しかし、そのような設定は(データベース名などと共に)settings.pyに格納するのがベストです。

関連する問題