0

ruby スクリプトを使用して Sqlite3 データベースに大量の情報を挿入しようとしています。これを行うために 250 db_prepare_location.execute を実行した後、次のように動作を停止します。

.rvm/gems/ruby-1.9.2-p290/gems/sqlite3-1.3.6/lib/sqlite3/statement.rb:67:in `step': unable to open database file (SQLite3::CantOpenException)
    from /Users/ashley/.rvm/gems/ruby-1.9.2-p290/gems/sqlite3-1.3.6/lib/sqlite3/statement.rb:67:in `execute'
    from programs.rb:57:in `get_program_details'
    from programs.rb:22:in `block in get_link'
    from /Users/ashley/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/csv.rb:1768:in `each'
    from /Users/ashley/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/csv.rb:1202:in `block in foreach'
    from /Users/ashley/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/csv.rb:1340:in `open'
    from /Users/ashley/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/csv.rb:1201:in `foreach'
    from programs.rb:20:in `get_link'
    from programs.rb:63:in `<module:Test>'
    from programs.rb:15:in `<main>'

そして、ここに私のコードがあります:

require 'net/http'
require 'json'
require 'nokogiri'
require 'open-uri'
require 'csv'
require 'sqlite3'
require "bundler/setup"
require "capybara"
require "capybara/dsl"

Capybara.run_server = false
Capybara.default_driver = :selenium
Capybara.current_driver = :selenium

module Test
  class Tree
    include Capybara::DSL

    def get_link
      CSV.foreach("links.csv") do |row|
        link = row[0]
        get_details(link)
      end
    end

    def get_details(link)
      db = SQLite3::Database.open "development.sqlite3"
      address = []
      address_text = []
      visit("#{link}")
      name = find("#listing_detail_header").find("h3").text
      page.find(:xpath, "//div[@id='listing_detail_header']").all(:xpath, "//span/span").each {|span| address << span }
      if address.size == 4
        street_address = address[0].text
        address.shift
        address.each {|a| address_text << a.text }
        city_state_address = address_text.join(", ")
      else
        puts link
        street_address = ""
        city_state_address = ""
      end
      if page.has_css?('.provider-click_to_call')
        find(".provider-click_to_call").click
        phone_number = find("#phone_number").text.gsub(/[()]/, "").gsub(" ", "-")
      else
        phone_number = ""
      end
      if page.has_css?('.provider-website_link')
        website = find(".provider-website_link")[:href]
      else
        website = ""
      end
      description = find(".listing_details_list").find("p").text
      db_prepare_location = db.prepare("INSERT INTO programs(name, city_state_address, street_address, phone_number, website, description) VALUES (?, ?, ?, ?, ?, ?)")
      db_prepare_location.bind_params name, city_state_address, street_address, phone_number, website, description
      db_prepare_location.execute
    end
end


test = Test::Tree.new
test.get_link
end

ここでの問題は何ですか?それを修正するにはどうすればよいですか? 追加情報が必要な場合はお知らせください。

4

1 に答える 1

3

ファイル記述子が不足している可能性があります。を呼び出すたびget_detailsに、SQLite データベースを開きます。

db = SQLite3::Database.open "development.sqlite3"

ただし、明示的に閉じることはありません。db代わりに、すべての をクリーンアップし、すべてのファイル記述子を閉じるために、ガベージ コレクターに依存しています。データベースを開くたびにファイル記述子を割り当てる必要があり、データベースを閉じるとファイル記述子が解放されます。get_detailsGC がクリーンアップできるよりも速く呼び出している場合、ファイル記述子が不足し、後続のSQLite3::Database.open呼び出しが失敗します。

db.closeの最後に追加してみてくださいget_details

おそらく、準備されたステートメントも閉じる必要があるため、db_prepare_location.close前にdb.close次のことを行う必要があります。

def get_details
  #...
  db_prepare_location.close
  db.close
end

はい、Ruby にはガベージ コレクションがありますが、それはリソースを手動で管理する必要がないという意味ではありません。

別のオプション (DGM が示唆していた) は、コンストラクターでデータベースへの接続を開くことです。

def initialize
  @db = SQLite3::Database.open "development.sqlite3"
end

SQLite3::Database.open次に、通話をドロップして代わりにget_details使用@dbします。db.closeもうインは必要ありget_detailsませんが、それでもdb_prepare_location.closeコールが必要です。

于 2012-07-26T02:15:39.243 に答える