我正在尝试使用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
这里有什么问题,我该怎么办才能修复它?如果需要其他信息,请与我们联系。
答案 0 :(得分:3)
您可能正在运行文件描述符。每次调用get_details
时,都会打开SQLite数据库:
db = SQLite3::Database.open "development.sqlite3"
但你从未明确地关闭它;相反,您依靠垃圾收集器来清理所有db
并关闭所有文件描述符。每次打开数据库时,都需要分配文件描述符,关闭数据库会释放文件描述符。如果您以比GC更快的速度调用get_details
,那么您将用完文件描述符,后续的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
来电。