人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

http://q.hatena.ne.jp/1434818671
http://q.hatena.ne.jp/1436077068

上記質問にて大変助かったのですが、Rubyは動いたけどPHPは動かなかった、、残念。
上記Rubyのa-kuma3さんのご回答の続きで、集めたものをデータベースに書き込むまでがわかりません。
個別の・それぞれのデータ配列を認識して取り出す方法がわかればいいのだけど。
他の方法を使うべきかと模索してるけど、回答が見事で、もったいないから、、

スクレイピング・スパイダリングで1日1回くらい集めたデータをデータベースに保存したいのですが、どうしたらいいのやら。
とりあえずまず保存してから、ノウハウを勉強しようかと思ったのだけど、、
いきなりは難しかったか;;
MYSQLにこだわらず他のでもいいかなとか思い始めて、方向が違うなぁと参っています。
ノコギリとか使うべきなのだろうか、、、
アドバイスをお願いしたいです。


●質問者: FREEz
●カテゴリ:ウェブ制作
○ 状態 :終了
└ 回答数 : 2/2件

▽最新の回答へ

1 ● pogpi
●2500ポイント

日時、都県毎に、tdが七つのデータがあるという仕様だとすると、
次のような感じでどうですか。

token(t1 int,name varchar(200))
hogedata(dtm datetime,t1 int,td1 varchar(2000),…,td7 varchar(2000))

主キーはtokenのt1,hogedataのdtm,t1で、hogedataのt1は外部キー制約を付けるといいでしょう。


FREEzさんのコメント
ご回答ありがとうございます。 ただどうやるのかは、正直わからないです。 いろいろ検索してみるか、、、

pogpiさんのコメント
JRubyを使えば、jdbcでMySQLに接続できますよ。

2 ● a-kuma3
●2500ポイント ベストアンサー

前に書いた回答の rowspan 対策版を DB に書き込むようにしてみました。
DB は、SQLite を使いました。
SQLite を選んだのは、「とりあえず、手軽に始めたい」という印象を受けることと、ぼく自身が一から SQLite を入れて使ったことが無かったので、やってみたかった、というのが理由です。

まず、Ruby スクリプトがこんな感じです。

require 'open-uri'
require 'sqlite3'

# get HTML

uri = "http://teideninfo.tepco.co.jp/day/day002-j.html"


txt = ""
http_options = {}
open(uri, http_options){ |io|
 txt = io.read
}


# encode to UTF-8

txt.force_encoding("Shift_JIS")
txt = txt.encode("UTF-8")



class RowData
 def initialize
 @first_line_mode_ = true
 @data_ = []
 @rows_ = []
 end
 def push data, rows
 if @first_line_mode_ then
 @data_ << data
 @rows_ << rows
 else
 i = @data_.index(nil)
 @data_[i] = data
 @rows_[i] += rows
 end
 end
 def clear
 is_remain = false
 (0...@data_.length).each { |i|
 @rows_[i] -= 1
 if @rows_[i] == 0 then
 @data_[i] = nil
 else
 is_remain = true
 end
 }
 unless is_remain then
 @data_ = []
 @rows_ = []
 @first_line_mode_ = true
 else
 @first_line_mode_ = false
 end
 end
 def to_a
 @data_.dup
 end
 def empty?
 @data_.empty?
 end
end


def treat_data data

 db = SQLite3::Database.new("test.sqlite")
 db.transaction

 # 1カラム目は、<BR> で分離
 t = data[0].split /<BR>/i
 blackout_time = t[0]
 recover_time = t[1]

 # 残りはそのまま保存する
 pref = data[1]
 city = data[2]
 area = data[3]
 blackout_count = data[4]
 blackout_reason = data[5]
 update_time = data[6]

 sql = 'insert into TEPCO(blackout_time, recover_time, pref, city, area, blackout_count, blackout_reason, update_time) values (?, ?, ?, ?, ?, ?, ?, ?);'
 db.execute(sql, [blackout_time, recover_time, pref, city, area, blackout_count, blackout_reason, update_time])

 db.commit
 db.close

end


data = RowData.new

txt.each_line { |line|
 line.chomp!
 if line =~ %r|<td([^>]+)>(.*)</td>| then
 td_attr = $1
 txt = $2
 rowspan = 1
 if td_attr =~ %r|rowspan="(\d+)"| then
 rowspan = $1.to_i
 end
 data.push txt, rowspan
 elsif line =~ %r|</tr>| then
 unless data.empty? then
 treat_data data.to_a
 end
 data.clear
 end
}

前に書いた回答から変えたのは 2ヶ所。

  1. sqlite3 を require する
  2. treat_data メソッドを、DB に書き込むようにする



Ruby で SQLite を使えるようにするまでは、こんな手順です(ぼくがやったのは Windows です)。

  1. http://sqlite.org/download.html から、sqlite シェルと DLL をダウンロード
  2. sqlite-shell-win32-x86-???????.zip と sqlite-dll-win32-x86-???????.zip を解凍して、sqlite3.exe と sqlite3.dll を ruby の bin の場所に置く
  3. gem で sqlite3 をインストールする

gem は、こうです。

d> gem install sqlite3

# 実は、ここでちょっと はまったのですが、本筋とは関係がないので別に書きます

これで、Ruby から SQLite が使えるようになってます。


次に、先のスクリプトを使うためにテーブルを生成します。
とりあえず、データを突っ込めれば良いということで、テーブルは以下のようにしました。

create table TEPCO (
 id integer primary key,
 blackout_time text,
 recover_time text,
 pref text,
 city text,
 area text,
 blackout_count text,
 blackout_reason text,
 update_time text);

プライマリキーは AUTO INCREMENT な ID にしました。
レコードの重複のことはとりあえず考えずに、ガンガン データを追加します。

TEPCO のページでは、発生時刻と復旧時刻が同じ列に改行された表示になってましたが、これは分けておいた方が使いやすいだろうということで、二つに分けました。

残りは、TEPCO のページそのままです。


テーブルを作成するには、コマンドプロンプトから sqlite3 シェルを起動して、create table コマンドを実行します。

d> sqlite3 test.sqlite
SQLite version 3.8.11.1 2015-07-29 20:00:57
Enter ".help" for usage hints.
sqlite> create table TEPCO (id integer primary key, blackout_time text, recover_time text, pref text, city text, area text, blackout_count text, blackout_reason text, update_time text);
sqlite> .tables
TEPCO
sqlite>
sqlite> .exit

sqlite3 コマンドに続けるのが DB の実体となるファイルです。
このファイル名は、データを書き込む Ruby のスクリプトにも記述してあります。

create table でテーブルを作成し、.tables コマンドでテーブルができたことを確認。
.exit コマンドでシェルを抜けます。


これで、先に書いたスクリプトを実行する準備ができました。
実行すると、データがテーブルに書き込まれているはずです。

データの確認は sqlite3 シェルで select * ってやっても良いんですが、SQLite を使うときに便利なツールがあります。
http://sqlitebrowser.org/


FREEzさんのコメント
おおご回答ありがとうございます。助かります。 実は、いろいろ調べて、 def treat_data data data.each_with_index { |x, i| puts "#{i} : #{x}" } puts '-' * 72 end のところがわからないところの要所だと気付いて、{ }の中か外かで処理を加えて調べてデータベースへの処理を試しているところでした。 そのまま追加していいのかが悩みどころでしたが、 そこで知恵熱でダウンしたので、少し参ってペースをおとしていました。 早速また調べていきたいと思います。ありがとうございました。

FREEzさんのコメント
早速試したけど、ダメでしたー、 sqlite3の gem install sqlite3 でエラーでまくったけど、後半エラーないところで作った感じあるのでそのまま進めたらsqlite3認識して、同操作にてコマンドプロンプトからデータベース作れてidもそれぞれ登録してsqlitebrowserから確認していたのですが。 やはり見逃してはいけない部分でした、、、 Rubyプログラム動かす段階でsqlite3のLoadError、requireでsqlite3のところが出てるので検索してこれはもう gem uninstall sqlite3 して最初からやり直しているけど。 最初からやり直して他の方法も試しているのに、sqlite3入れるところでエラーが直らないという、、、これはまいった、、64bitのRuby入れたのがまずかったのか; もっと探してみよう、、、、

a-kuma3さんのコメント
gem install したときのエラーというのがちょっと気になりますが、64bit 版の Ruby を使っているのがまずいです。 SQLite のサイトでダウンロードできるのは 32bit 版の DLL です。 64bit プロセスから 32bit の DLL は呼び出せないことはないんですが、ちょっと変わったことをしなくちゃいけないです。 基本、呼び出せない、と思っておいた方が良いと思います。 自分で DLL をコンパイルする、とか、64bit 版の DLL を探す、という方法もありますが、32bit 版の Ruby をインストールするのが手っ取り早いんじゃないかと思います。 Ruby は、実行モジュールがあるところにパスを通すだけで使えるので、64bit 版の Ruby を残したまま 32bit 版をインストールできます。 (おまけ) http://d.hatena.ne.jp/uedako/20130817/1376731209 64bit 版の Ruby は、いろいろと大変だよ、という話。 http://blog.synopse.info/post/2013/03/23/Latest-version-of-sqlite3.dll-for-Windows-64-bit 64bit 版の DLL を落とせるところがないわけではないけれどね(ちょっと古い)、という話。

FREEzさんのコメント
あれ、32bitに完全に切り替えて64bitは環境変数のパス変えて認識しなくして、sqlite3が驚くほど無事に入ったんですけど。 Rubyプログラム動かしたら、LoadErrorになりますね、、 ../ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in'require' となりますね、、-- sqlite3/sqlite3_native(LoadError) 以下も6つくらい似たようなエラー。 データベース作成時にtest.sqliteがUserディレクトリにできたけど、Ruby方面に移動するのですかね、、 聞いたことはあったが、大して考えもせずに他にも64bitで普通のインストール入れていたことあったなぁとドキドキしています。 とりあえず入れ替えたことでデータベースにかかる課題は解決できたのでよかったです、、

a-kuma3さんのコメント
sqlite3.dll を ruby の bin のところ (32bit の方) に入れてますか?

a-kuma3さんのコメント
いや、sqlite3.dll 関係ないですね。 gem でインストールしたところの DLL を使ってる。 試しに DLL (.so) をリネームして動かしたら、以下のようなエラーが出ました。 >|| lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- sqlite3/sqlite3_native (LoadError) from c:/usr/ruby-2.0.0/lib/ruby/site_ruby/2.0.0/rubygems/core_ext/kernel_require.rb:55:in `require' ||< kernel_require.rb:55:in `require': の後に、LoadError の内容が表示されてるはずです。 もし、ぼくと同じで cannot load such file とあるなら、gem でのインストールがうまくいってないと思うんですが。 >> データベース作成時にtest.sqliteがUserディレクトリにできたけど、Ruby方面に移動するのですかね、、 << sqlite3 シェルをどうやって起動しましたか? パラメータに指定する DB のファイル名が相対パスなら、sqlite3.exe を起動したカレントディレクトリになります。 Ruby のスクリプトから DB のファイルが見えていなければ、別のエラーが出ます。 require 'sqlite3' で出ているエラーを取り除いてからの話になりますけど。

FREEzさんのコメント
おっしゃるとおり、エラーは間に cannot load such file 入ってます。 再度確認しましたが、binにsqlite3.def,sqlite3.dll,sqlite3.exe,は入っています。 gemインストールもデータベース作成も上記の通りにやってSuccessと問題なくできました。 ひょっとしてコマンドプロンプトの入力を間違えているのでしょうか。 プロンプトで再度入力するとtest.sqlite3読み込んでTEPCOデータベース確認もできているので消えたわけではなさそうで。 エラー全部は以下です。 gemなんでしょうかね、またやっても成功と出るのですが、、 ruby teiden_tepco.rb C:/Ruby22/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require': ca nnot load such file -- sqlite3/sqlite3_native (LoadError) from C:/Ruby22/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:54:in `require' from C:/Ruby22/lib/ruby/gems/2.2.0/gems/sqlite3-1.3.10-x86-mingw32/lib/s qlite3.rb:6:in `rescue in <top (required)>' from C:/Ruby22/lib/ruby/gems/2.2.0/gems/sqlite3-1.3.10-x86-mingw32/lib/s qlite3.rb:2:in `<top (required)>' from C:/Ruby22/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:128:in `require' from C:/Ruby22/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:128:in `rescue in require' from C:/Ruby22/lib/ruby/2.2.0/rubygems/core_ext/kernel_require.rb:39:in `require' from teiden_tepco.rb:2:in `<main>'

a-kuma3さんのコメント
32bit 版をインストールしたディレクトリは C:\Ruby22 ということで間違いないです? Ruby は 2.2.0 をインストールしたんですね。 sqlite3 の DLL (.so) は、以下のパスから読み込もうとします。 >|| (Ruby のインストールディレクトリ)\lib\ruby\ gems\(Ruby のバージョン)\gems\sqlite3-1.3.10-x86-mingw32\ lib\sqlite3\(Ruby のバージョン 上ふたつ)\sqlite3_native.so ||< (長いので、改行入れました) つまり、id:FREEz さんの環境では、以下のファイルを Load しようとします。 >|| C:\Ruby22\lib\ruby\gems\2.2.0\gems\ sqlite3-1.3.10-x86-mingw32\lib\sqlite3\2.2\sqlite3_native.so ||< gem でインストールした先を見てもらえれば分かりますが、1.8 ? 2.1 までしかディレクトリがありません。 というわけで、ライブラリがロードできんわ、というエラーが出ます。 Ruby は、2.0 もしくは 2.1 を使ってください(もちろん、32bit 版で)。 # 多分、後、もうちょっとです <tt>:-)</tt>

FREEzさんのコメント
最初からやり直してみようと、OnRailsを入れてみました。 Ruby2.1.0で、よく見たら他のところでもSqlite3の設定に必要とされていたファイルも含めて最初から入っていて、便利ぽいなぁと思いました。 ただsqlite3のインストールでエラーが出たのですが、これも入っているようで、、 試しにプログラムを稼働したら動いて書き込まれました。 たださらに試してもう一度やったら追加で同じデータが書き込まれたので、なるほど書き込み設定はしていないから当然と、sqlitebrowserで消してから再度試したら、エラーになりました。 そんなに急いで2連続で動かしてはいなかったのですが、、 C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/sqlite3-1.3.10-x86-mingw32/ lib/sqlite3/statement.rb:108:in `step': database is locked (SQLite3::BusyExcepti on) from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/sqlite3-1.3.10 -x86-mingw32/lib/sqlite3/statement.rb:108:in `block in each' from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/sqlite3-1.3.10 -x86-mingw32/lib/sqlite3/statement.rb:107:in `loop' from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/sqlite3-1.3.10 -x86-mingw32/lib/sqlite3/statement.rb:107:in `each' from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/sqlite3-1.3.10 -x86-mingw32/lib/sqlite3/database.rb:158:in `to_a' from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/sqlite3-1.3.10 -x86-mingw32/lib/sqlite3/database.rb:158:in `block in execute' from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/sqlite3-1.3.10 -x86-mingw32/lib/sqlite3/database.rb:95:in `prepare' from C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/sqlite3-1.3.10 -x86-mingw32/lib/sqlite3/database.rb:134:in `execute' from teiden_tepco.rb:85:in `treat_data' from teiden_tepco.rb:107:in `block in <main>' from teiden_tepco.rb:95:in `each_line' from teiden_tepco.rb:95:in `<main>' database is locked (SQLite3::BusyExcepti とあるから、データベースが一時的に非稼働になったように感じたのですが、、 少し置いたら戻るのでしょうか、なんか動いた気もするのですが。 連続で動かした程度でエラーが出ているのか、、OnRailsの事情か、、、 もしくはsqlite3の事情なのか、、 今からでもOnRailsやめておいた方がいいでしょうか?この辺は同じですかね。 例えばMYSQLへの書き込みなどでは連続に処理でエラーなかたtので不可思議に思っているところがあります。

a-kuma3さんのコメント
>> C:/RailsInstaller/Ruby2.1.0/lib/ruby/gems/2.1.0/gems/sqlite3-1.3.10-x86-mingw32/lib/sqlite3/statement.rb:108:in `step': database is locked (SQLite3::BusyException) << "database is locked" ってありますから、他のプロセスがつかんじゃってるんですね、きっと。 sqlitebrowser で削除すると、DB のファイルを更新モードでつかみっぱなしになっちゃうんだと思います。 sqlitebrowser を終了させてから実行すれば、このエラーは出ないと思います。
関連質問

●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ