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

かなり煮詰まっているので、Perl,PHP,Rubyなら助かります。プログラミングを教えて頂きたいです。
当方、スクレイピング・スパイダリングを勉強しています。
本やネットで調べ丸ごと取るならばわかるのですが、どうしてもテーブルから取る方法がわかりません。
以下のブログスペースに例を書きます。ここに投稿しようとして文字数から少し削りすぎてしまいましたが。
<tbody>下の<tr>のひとまとめは日によって増減し、<td>7つにそれぞれ日本語表記があります。
<td>それぞれのデータをそれぞれ変数に収めて、そこからMySQLに書き込み記録していきたいです。
1日1回のチェックなど、先方に迷惑かからないように配慮しつつcron使おうかと考えています。
●Mechanize他、追加モジュールは使わないスタンダードな方向でお願いします。
●煮詰まってるスクレイピング部分だけでもいいのですが、詳細に書かれていれば助かるので追加でポイントを贈ります。

http://freez.hatenablog.jp/entries/2015/06/21


●質問者: FREEz
●カテゴリ:インターネット ウェブ制作
○ 状態 :終了
└ 回答数 : 2/2件

▽最新の回答へ

1 ● a-kuma3
●3000ポイント ベストアンサー

Ruby だと、こんな感じでしょうか。

def treat_data data
 p data
end


txt = ... # 対象ページのデータがまるっと入ってるとして

in_table = in_tbody = in_tr = false
data = []

txt.each_line { |line|
 line.chomp!
 if ! in_table && line =~ %r|<table.*class="lv4"| then
 in_table = true
 elsif line =~ %r|</table>| then
 in_table = false
 elsif in_table && line =~ %r|<tbody>| then
 in_tbody = true
 elsif line =~ %r|</tbody>| then
 in_tbody = false
 elsif in_tbody && line =~ %r|^<tr>| then
 in_tr = true
 elsif in_tr && line =~ %r|</tr>| then
 treat_data data
 data = []
 in_tr = false
 end
 if in_tr && line =~ %r|<td[^>]+>(.*)</td>| then
 data << $1
 end

}

OpenURI とかを使って対象ページの内容を文字列として取り込んだ後の処理です。
行単位で読み進めていって、table や tbody の内側に入っているかを変数に持たせて、その内側にある td を拾っています。

対象のページに table がひとつだけしかないのであれば、以下のような感じでも十分です。

def treat_data data
 p data
end

txt = ...
data = []

txt.each_line { |line|
 line.chomp!
 if line =~ %r|<td[^>]+>(.*)</td>| then
 data << $1
 elsif line =~ %r|</tr>| then
 unless data.empty? then
 treat_data data
 data = []
 end
 end
}





追記です。
TEPCO のページから HTML を持ってきて、テーブルからデータを抜き出すところまでやってみました。
ページの charset が Shift-JIS だったので、UTF-8 への変換を入れています(Ruby はデフォルトの文字コードが UTF-8 なので)。

require 'open-uri'

# get HTML

uri = "http://teideninfo.tepco.co.jp/day/day003-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")


def treat_data data
 data.each_with_index { |x, i|
 puts "#{i} : #{x}"
 }
 puts '-' * 72
end

data = []

txt.each_line { |line|
 line.chomp!
 if line =~ %r|<td[^>]+>(.*)</td>| then
 data << $1
 elsif line =~ %r|</tr>| then
 unless data.empty? then
 treat_data data
 data = []
 end
 end
}





追記です。
rowspan 対策版です。

require 'open-uri'

# 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
 data.each_with_index { |x, i|
 puts "#{i} : #{x}"
 }
 puts '-' * 72
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
}

元の処理ループをあまり変えずに、表の意味的な一行を表すクラスを作って対応してみました。
DB に書き込むということなので、rowspan の指定で TD が抜けているところは、前の行の値を引き継ぎます。
テストは甘いですが、rowspan が 2よりも大きいときや、別の列に rowspan が入ったときにも対処しているつもりです。


FREEzさんのコメント
早速のご返答ありがとうございます。 抜き取ったデータをデータベースに作った同様のテーブルに一つずつ書き込んでいくイメージだったので、なるほど配列ですね。 今は時間がないのですが、早速rubyで試してみます。 MySQLに配列で書き込めなくてはいけないんですね。

a-kuma3さんのコメント
>> MySQLに配列で書き込めなくてはいけないんですね。 << table の一列 (tr) が DB の 1レコードだと思うので、配列とかはあまり意識せずにベタで書けば良いと思います。 格納するDB と table の項目の並びが同じだったら join でくっつけちゃうとかできますし。 >|ruby| def treat_data data sql = "insert into data_table valus (" + data.collect { |e| "\"#{e}\"" }.join(",") + ")" db.query(sql) end ||< Mysql.quote したりとか、トランザクションの単位とか、ちょいちょい考慮することはありますけど。

FREEzさんのコメント
申し訳ないです、 調べながら試して昔perlよりrubyが使いやすいという意見があったことをなるほどと感じています。 テーブルから抜けているかな?とそれぞれ表示させようとして普通に表示させようとしているのですが、エラーではなくnilか[]かになっています。 ひょっとしてrequire 'open-uri'からの連携で読み込めていないのか?と思ったのですが、できればそこからのつなぎを教えて頂けないでしょうか。 「txt = ... # 対象ページのデータがまるっと入ってる 」このtxtで、そのまま'open-uri'を入れた変数を代入したのがまずかったのか、、 もしくはtreat_dataで間違えたのかも、、と狭く考えすぎて煮詰まってしまうので、、 よろしく願いします。

a-kuma3さんのコメント
>> ひょっとしてrequire 'open-uri'からの連携で読み込めていないのか?と思ったのですが、できればそこからのつなぎを教えて頂けないでしょうか。 << 読みこめてないと例外が飛んでくるんで、多分、そこじゃないとは思いますが、一応。 >|ruby| require 'open-uri' uri = "http://q.hatena.ne.jp/" txt = "" http_options = {} # 空っぽなら指定しなくて良い、という話もある open(uri, http_options){ |io| txt = io.read } ||< 取り込めているかどうかは、適宜 puts や p で変数の内容を出力してみれば良いんじゃないかと思います。

FREEzさんのコメント
おっしゃる通りで。まさにそのように確認をしているのですが、dataやURLでは表示されるのにtxtから先になるととたんにnilかエラーでない感じか、、でした。 正規表現のところでnilエラーになることがあると見つけたので、もう少し調べてみたいと思います。 data[]で中身に0.1.2..など入れろとエラーがあって入れたらnilとかもありましたので、以前とほんの少し違うところも見られたので興味深い。 一応ブログ更新して、例ではなくスクレイピングしたいHP先をリンクしてみました。 タグ解読した点では間違いはないと思うので、その辺は大丈夫だと思ったのですが、はてなで試した際も文字コードなど何か他の影響もないかなど不安もあったので。

a-kuma3さんのコメント
回答に追記しました。 TEPCO のページの内容を配列に詰めるところまでやっています。 Ruby はデフォルトの内部コードが UTF-8 なので、ページの Shift-JIS を UTF-8 に変換しています。

FREEzさんのコメント
ありがとうございました、大変助かりました。 予想外な点があったので、試してもらえませんか。 というのも、この情報先はデータが毎日増えるので、このリンク先も毎日ひとつずつURLの数字がずれるんですが。 そのためいろいろな条件で試せる点がいいところですが、条件同じところを探すの点が大変ですね。 市区町村・地区に複数データが当てはまった場合、処理がおかしくなります。 一例ですが、6/28が当てはまっています。 頭では気付いていたけど、そうかプログラムはこう処理するんだなと、、 ちょっと自分でも試してみたんですが、結構難しい、、

a-kuma3さんのコメント
あー、rowspan が指定されたとき。 日時や都県名は引き継ぎたい、ってことですよね。

FREEzさんのコメント
件数が増えてテーブルが増えることがあるように、ここも増えることがある、となると。 しかも2つとは限らないから、もっと地名が増えることもありますから、、 空いてしまっている他の箇所もずれるわけです。なんらでひとつ前と同様に埋めると考えるのかな。 エラーなくしっかり取れているだけに、口惜しいところがあります、、

a-kuma3さんのコメント
rowspan 対策をしたものを、回答に追記しました。 以前のは、表の行を表すのに配列 (Array クラス) を使いましたが、今回のは専用にクラスを作りました。 まっさらのところにデータを突っ込んでいくときは同じですが、rowspan の値も保持するようにしてます。 TR の終端が来て、一行のデータの処理が終わったときに、バッサリと消すのではなく rowspan の値を見て、歯抜けになるようにデータを消してます。 次の行で TD のデータを入れるときには、歯が抜けているところにデータを埋めます。 それぞれの列では、rowspan の値を持っておいて、データを処理するたびに 1 ずつ引くようにして、全部のデータがなくなったら、まっさらな配列を使うようなイメージにしました。

FREEzさんのコメント
さらに回答ありがとうございました、助かります。 いや当初から見ると思わぬところで随分印象が違うので、相談してよかったなという、、 この部分は完全に予想外でした、それぞれの値を抜ければ普通に付いてくるかなと。 最初の数字の方は処理されていましたからね。 さてどうデータベース書き込み処理に追いつくかな、、と。 データベースの方は、まず最初に空欄で作っておくようにします。 createはなしでinsertから次々に追加で普通に書き込むようにした方がいいかなと。 そこのデータベース有無チェックはなくていいと思うのだが、、こういう時もエラー処理で処理の逃げ道を用意してあげるべきなのでしょうか。 ただ、これ不思議に思った点が、、大体、2か月ほどの期間でデータがあります。 全て確認したところ理由で「調査の結果、特定できず」「調査中」があり、この調査中が判明して原因書かれるようになるなら、これもチェックした方がいいのかな。 古い日付で書き込むようにすれば判明しているからいいと手軽な方に思うのですが、今思えば確かにスクレイピングとしては複数のページを処理の対象とすることが通常なので、どうイメージを持つべきかなと思いまして。 データベースに一度書き込んでこの部分を一致検索する目線に見えるのですが、スクレイピングとしてはこういうやり方は一般的ではないでしょうか。本来は丸ごと取る印象で今回の値ごとにもしてもなかなかなかったので、、 でも思えばクローラは更新で変更データも保存して回るから、身近、、なんでしょうか。

a-kuma3さんのコメント
>> データベースの方は、まず最初に空欄で作っておくようにします。 createはなしでinsertから次々に追加で普通に書き込むようにした方がいいかなと。 そこのデータベース有無チェックはなくていいと思うのだが、、こういう時もエラー処理で処理の逃げ道を用意してあげるべきなのでしょうか。 << データを溜めこんでいくタイプの処理をしたいのであれば、テーブルは存在するのを前提で日々の処理は insert だけで良いと思います。 日々の処理が当日分、もしくは前日分だけを処理するのであれば、日付がプライマリキーであれば重複することはないでしょうから、エラー処理は省いても良いかな、と。 ただ、一日に一回のはずの処理が、二回、三回になることはあります。 コメントで書かれているように、「理由」が更新される、ということもありますし、データを抜くページのレイアウトが変わって処理を見直した後に再取得したいとか。 継続的に使うなら、insert でエラーになったら update か、delete して insert するか、というふうに作っておいた方が良いかもしれません。 >> データベースに一度書き込んでこの部分を一致検索する目線に見えるのですが、スクレイピングとしてはこういうやり方は一般的ではないでしょうか。本来は丸ごと取る印象で今回の値ごとにもしてもなかなかなかったので、、 << スクレイピングのサンプルとしては、一発取って それで終了でしょうが、ページの一部を抜き出すケースも往々にしてあります。 というか、抜いたデータを何らかの目的で使うとしたら、そっちの方が普通かも。 因みに、ぼくは、この人力検索の質問と回答の情報をスクレイピングしてたりします。 質問が投稿されてから、回答がつくまでのタイムラグがありますし、質問が終了してから半年も経ってからベストアンサーをつける人がいたりとか、質問や回答が非公開になって、データが後で抜き出せなくなってしまうとか、それなりに癖があります。 とはいえ、論文を書くような厳密なデータが欲しいわけではないので、以下のような戦略でデータを抜いてます。 - タイマー処理は、一日二回取得<br>運営はのんびりと手で処理してるので、就業前と終業後の2回取得すれば大体のデータは収集できるだろう、と - 速攻で非公開になるような質問や回答もあるので、タイマー処理以外に手で起動しても、整合性が保てるようにする - 対象期間は質問の最大日数の30日(以前は、7日) - それで拾えない分は、思いついたときに手で起動すれば良いと割り切る スクレイピングは、あくまでも道具なので、自分がやりたいことに合わせて機能を変えるとか、使い方を変える、ということで良いと思います。

FREEzさんのコメント
なるほど。 ちなみに表示するだけですか?どこかにテキストで保存ですか? 管理がかなり大きそうなので、データベースにして自分一人だけの利用ではないのかな、、 スクレイピングをする人は画像を保存する利用が多そうですが、あくまでデータベースとしてではなくファイル保存が多そうに感じています。 テキストでサイト丸ごとだと本当にざっと取ってくるので、その中から特定の言葉を検索をすることが大変に見えて、今回のように個別に取ってくるように管理上もある程度分ける必要性があると思いました。 googleがそういう検索サービスもやってますが。 大きくなると管理が大変そうですが見やすいような工夫とかがあるのでしょうか? あくまで自分が見やすければいい、という話ではあると思いますけど。

a-kuma3さんのコメント
>> ちなみに表示するだけですか?どこかにテキストで保存ですか? << テキストで保存してます。 欲しいデータだけを抜き出して、タブ区切りのテキストで保存してます。 この質問だと、こんな感じで。 >|| A 1434818671 a-kuma3 a-kuma3 2015/06/21 01:44:31 2015/06/21 10:07:48 500 - - A 1434818671 tezcello tezcello 2015/06/21 01:44:31 2015/06/26 04:08:04 500 - - Q 1434818671 FREEz FREEz 2015/06/21 01:44:31 2015/07/05 01:44:31 500 - - 2 ||< 完了すると、こんな感じのデータになります。 >|| A 1434505406 a-kuma3 a-kuma3 2015/06/17 10:43:26 2015/06/17 11:57:08 100 50 BA A 1434505406 yokosasa よこささくん 2015/06/17 10:43:26 2015/06/17 15:25:36 100 50 - Q 1434505406 Ficus_palmeri Ficus_palmeri 2015/06/17 10:43:26 2015/06/19 09:59:32 100 - BA 2 ||< さすがに10年分をひとつのファイルにすると重たいので、年単位で分割して保存しています。 テキストにしてるのは集計を取ったりしているからです。 こんなことなんかをやるために。 http://q.hatena.ne.jp/1376398836#a1210917 そのまま Excel に取り込んだり、プログラムで加工したり。

FREEzさんのコメント
リンク先の質問内容を見て、なるほどと思いました。 実は数年ぶりにはてなを見ているので、このシステム変更を知らなかった、、 昔から有料の質問しかしてこなかったタイプでして。 質問さえしっかりしていれば回答代はそんなに高くないと思うのだが、、 昔いい加減な回答にP取られて困ったりもしたけど。 無料の質問て反応あるのかと不思議、、13歳以下かな回答させないなんて選択肢もあったから何かあったんだなとは思ったのですが。 Q&Aサイトが増えたからかな、、モバイルユーザーが増えたからかな、、 実におもしろいと思ったのですが、はてなでのこういう集計などは何か狙いがあるのでしょうか? どんなことができているのかが知りたいです。 他のサイトとかもしているのかな、、そう簡単にできるものでもなさそうなのでw

a-kuma3さんのコメント
「狙い」ってほどのものはないんですけど、プログラムを組むの好きだし、データってただ見てるだけでも楽しいし(統計学は、学生レベルではできます)。 人力検索の集計データは人がやってることの表れなので、人間ウォッチという意味でも面白い。 「どんなことができるのか」の具体例としては、ぱっと思い出したところではこんな感じ。 - 質問数や回答数のトレンドを見て、人力検索の寂れ具合に涙する - 質問の締切間際に滑り込んで、ポイントの均等配分を狙うユーザをあぶりだす - 質問を投げっぱなしの自動終了&均等配分っぷりが分かって、回答する気がなくなる - 月別のポイント獲得数などを見て、このユーザに何があったのかといぶかしがる - 2回目以降に回答を書いた方が、実は BA 率が高いのではないか、と思ったけど、実はそんなこと無かったのが分かる などなど。 人力検索の回答以外では、ダイアリーやハイクなんかの投稿ネタに使ったりしてます。 他のサイト? 駄目です。 数が多すぎます (^^; 質問サイト以外であれば、スクレイピングはたまにやることはありますけど。

FREEzさんのコメント
以前からおかしいと思っていたのですが、これ自動終了だと自動で均等になってしまうのかな、、 前に終わるまで待って配分しようとしてすぐにログインしたが調整できないことがあったので、、 今はできればいいのですが。自分で途中で終了させることに負い目があったので。 今思えばこのままでいいのかどうしようかと焦りもあります。 まぁだからポイントは少なく見積もって質問したのですが。 追加でポイント贈ればいいから方法はあるのだが勝手に決まるのも困る。履歴としてはP贈呈はみえないのかな。 運営しか把握していなそうなことがわかるんですねぇ、かなり面白いな、、、 逆に比較として有料の質問が昔はどれほど多かったのかに興味を持ちました。 ベストアンサーの質問順番の統計までスクレイピングで把握できるとは、、取ってきた後のプログラムでもかなりの工夫ができるんですね。 投稿時間・ポイント配分・自動終了、この辺までは何となく想像付くのですが 個人のポイント獲得数まで月別に見れるのか、、こういうのまでやるとはかなり入れ込んでいますね、、 逆に質問してポイント送ってる側も見れるのかな。コアユーザー動向ですね。 むしろリンクの質問で、個人を指定して質問することができる点に驚きがあり、、いろいろ変わったんだなぁと。 まだそこですw むしろここまでやって頂けたなら MYSQLのデータベースに何か操作して書き込むとしていっそ聞きたいのですが、 投稿前にそれが重複しているかをチェックしてから書き込むにはどうしようか難しいでしょうか。 以前あった理由に限らず値のデータどれでもいいのですが、無難に変わりそうにない日付などで考えています。 完全一致もあることは知っていますが、、他の箇所の変更までこういうので見比べるとは。 あれ、はてなだとどこか変わったはスクレイピングで見比べられるのでしょうか、、

a-kuma3さんのコメント
>> 以前からおかしいと思っていたのですが、これ自動終了だと自動で均等になってしまうのかな、、 << 自動終了だと、均等になります。 いつ閉めて、どう配分するかは質問者の裁量なので、どうぞお好きに。 因みに、この回答のコメント欄は質問が終了しても、その欄の回答者と質問者は書き込みができます。 >> むしろリンクの質問で、個人を指定して質問することができる点に驚きがあり、、いろいろ変わったんだなぁと。 << 個人を指定しての質問は規約違反ですが、回答リクエストが飛ばせるようになりました。 質問欄では IDコールが効かないので、1週間の期限の中で巡回頻度が低い人への通知としては、多少便利かも。 質問の期間が 1ヶ月まで延ばせるようになりましたから、今ではあまり意味をなさないかも。 >> むしろここまでやって頂けたなら MYSQLのデータベースに何か操作して書き込むとしていっそ聞きたいのですが、 投稿前にそれが重複しているかをチェックしてから書き込むにはどうしようか難しいでしょうか。 << 何が「むしろ」か分かりませんが <tt>:-)</tt> プログラム的には、たいして難しくないです。 問題は、「重複と思しきときに、どうしたいか」という仕様的な話です。 停電情報だと、日時と場所がユニークなキーっぽいです。 でも、後で情報が修正されることがあるとしたら、時間や場所は変わらないんでしょうか? 電力供給は監視システムがしっかりしているので、情報として出してから修正されることはないのかもしれません。 もし、重複するデータが取得できてしまったら、どうしたいですか。 上書き? それとも、追加? これは、貯めたデータをどう使いたいか、という本人次第です。 常に追加したいなら、AUTO_INCREMENT な ID をプライマリキーにすれば良いし、更新したいなら ON DUPLICATE KEY を使っても良いし、select count(*) してから、プログラムで insert と update を if 文で分岐しても良いし。 >> あれ、はてなだとどこか変わったはスクレイピングで見比べられるのでしょうか、、 << ぼくが人力検索のデータをマージするときには、質問単位、つまり複数レコードを比較しています。 BA をつけて手動で終了する以外にも、自動終了して、しばらく経ってから BA がついたり、運営によって回答が非公開になったりします。 たとえば、こんな感じのが、 >|| A 1434818671 a-kuma3 a-kuma3 2015/06/21 01:44:31 2015/06/21 10:07:48 500 - - A 1434818671 tezcello tezcello 2015/06/21 01:44:31 2015/06/26 04:08:04 500 - - A 1434818671 hamstar11 ハムスター 2015/06/21 01:44:31 2015/07/05 00:00:00 500 - - Q 1434818671 FREEz FREEz 2015/06/21 01:44:31 2015/07/05 01:44:31 500 - - 3 ||< 自動終了して、 >|| A 1434818671 a-kuma3 a-kuma3 2015/06/21 01:44:31 2015/06/21 10:07:48 500 167 - A 1434818671 tezcello tezcello 2015/06/21 01:44:31 2015/06/26 04:08:04 500 166 - A 1434818671 hamstar11 ハムスター 2015/06/21 01:44:31 2015/07/05 00:00:00 500 166 - Q 1434818671 FREEz FREEz 2015/06/21 01:44:31 2015/07/05 01:44:31 500 - closed 3 ||< となり、BA がついて、 >|| A 1434818671 a-kuma3 a-kuma3 2015/06/21 01:44:31 2015/06/21 10:07:48 500 167 BA A 1434818671 tezcello tezcello 2015/06/21 01:44:31 2015/06/26 04:08:04 500 166 - A 1434818671 hamstar11 ハムスター 2015/06/21 01:44:31 2015/07/05 00:00:00 500 166 - Q 1434818671 FREEz FREEz 2015/06/21 01:44:31 2015/07/05 01:44:31 500 - BA 3 ||< 運営が回答を削除して、こうなる >|| A 1434818671 a-kuma3 a-kuma3 2015/06/21 01:44:31 2015/06/21 10:07:48 500 167 BA A 1434818671 tezcello tezcello 2015/06/21 01:44:31 2015/06/26 04:08:04 500 166 - Q 1434818671 FREEz FREEz 2015/06/21 01:44:31 2015/07/05 01:44:31 500 - BA 2 ||< とか。 質問データは、質問番号がプライマリキーなんですけど、回答は複数つくので ID と順番がキーになります。 でも、回答が削除されると順番が繰り上がります。 質問番号と回答者のID 、回答時刻が一致していたら、ポイントや BA を上書き。 一致していなければ、回答が運営によって削除されたとみなして、ひとつレコードをずらして比較、なんてことをやってます。 今にして思えば、回答のブロックについてる ID を使えばよかったかな、という気もしますけれど <tt>:-)</tt>

FREEzさんのコメント
今から延長できるわけではないのですよね、また質問すればいいのですが。 重複すれば追加より更新で上書きにしたいです。 ただおっしゃる通り、日付と都道府県くらいで、他は全て変わりうるデータです。 他のデータと比べて一致するか、なわけですよね。 そこまで厳密には、、とは思いますが、いっそ追加にして更新時間から判断して自分で手分けする方が確実ともいえるわけですね。 はてなでの例を踏まえて考えて、思う以上に何か手がないかなと思案しています、、、 今聞いたはてなの例も非常に役立つ例だと思うので、、

a-kuma3さんのコメント
>> 重複すれば追加より更新で上書きにしたいです。 << ということは、何をもって重複と判断するかを決めれば良いわけですね。 つまんで見ているだけですが、発生日時と都県名が同じでも、復旧日時は違ったりしてますので、別扱いでも良いのかも。 というか、貯め込んだデータをどういうふうに扱いたいかで、変わってくる気もします。 今、気が付いたんですけど、TEPCO のページでも情報が上書きで更新されるんですね。 上書きされちゃうので、更新される前のデータも取っておいてニヤニヤしたいとか、一ヶ月分しか残らないのを貯めたいだけだから、最終的な情報だけで良いとか。 ぼくの場合も、さらっと書いてますが、途中、何度か見直してます。 実際にデータを集めてみたら、想定してなかったケースや、後から取りたくなった情報があったりとか。 趣味の範囲であれば、緊急性はあまりないと思いますので、まずは貯めこんでみてから、データを見て考える、というのでも良いように思います。

FREEzさんのコメント
滑り込みで誰か回答してくるのかなぁと様子見ていましたが、特にないな、、 どう変化したか前後比較はいらないですw 最終的な情報があればいい、と言ってしまえばそういうことなわけです。 基本的に、理由以外は全然重視していなかったのですが、確かに復旧日時も考慮要です。 結局どこが変化しないのだろう?と考えると絶対が保証できないスクレイピング同様に全ての値が修正変更はあり得るわけで基軸をどこに置くかを自分で考えないといけないんですよね。 実際面倒なことに、一度復旧し数分後に全く同じで条件でまた起こるってのもあるんです。それを同一に考えないとするなら、日時・場所の一致で第一に考えて理由の変更以外は別物と捉えてもいいように思います。 仮に見分けるなら、更新時間もあるからいっそ上書きせずに追加しておいて人の目で見比べる方が健全でしょうか。 もしくはたいていは変更されると更新日は新しくなるからそこで見比べるか、発生日と更新日の日付がずれるからそこで判断するか。 深く考えるといろいろできると気付きましたが、まぁ自分では今はそこまでは無理だから、理由の訂正だけでいいです。 そもそも追加で書かれていっても問題ない、、実際丸ごと訂正はありえないからそんなに深く考えなくても見分けられるでしょうし。 いろいろやるより必要なことをスクレイピングすべきだなと思えたら、それくらいがちょうどいい気がします。 逆に「理由に限る」としたら容易になる方法もありますでしょうか。

a-kuma3さんのコメント
>> 仮に見分けるなら、更新時間もあるからいっそ上書きせずに追加しておいて人の目で見比べる方が健全でしょうか。 << データにどのようなバリエーションがあるか、と、それをどのように使いたいかによります。 「人の目で見比べる」じゃないと、最初に想定できないことはあります。 でも、一度、パターンが分かってしまえば、プログラムで対応できることもあります。 エラーが出てなくても、想定通りにデータを収集できてないかもしれません。 特に、上書きだと、収集したデータを見ただけでは分からないかも。 自動的にできることはプログラムに任せる、で良いとは思います。 でも、プログラムが期待通りに処理できているかどうかの確認は大切だと思います。 #趣味の範囲だと、ボチボチやれば、ってかんじですけれど。

FREEzさんのコメント
一晩考えて、完全に考え直しました。 変更されたら、全て追加で登録していきたいと思います。 変化がわかるのはすばらしい。 もっとシンプルに求めて、シンプルに考えないといけないと思い詰めると考えすぎてしまうため、改めました。 http://q.hatena.ne.jp/1436077068 新たに質問したため、よろしくお願いします。

質問者から

今は基本的にはPerlで試していますが、RubyやPHPでもわかりますし、そちらに切り替えてもいいので広く教えて頂きたいです。
C++やJavaもいいのですが、今回はスクリプト言語を想定しています。
Pythonは全く触れたことがないです。Pythonでもできるとはわかるので、これを機に学ぶのもアリかもしれませんが。


2 ● tezcello
●200ポイント

> 広く教えて頂きたいです
では PHPで書いてみます。
やっている事は先の方と同じですが...

try {
 // DB に接続
 $dbh = new PDO($dsn, $user, $password);
 // エラー時は例外を投げるようにしておくべきでしょうね(省略)

 // プリペアドステートメントの発行
 $sth = $dbh->prepare('INSERT INTO ... (略)');

 $src = '....'; // 目的のテーブルを含む取得したデータ

 // 抜き出したいデータ部分を特定
 // ソース中の最初の tbody 部だと仮定
 // テーブルが例示の一つだけなら $tbody = $src でもOKでしょう
 $pos1 = strpos($src, "<tbody>\n<tr>\n") + 13;
 $pos2 = strpos($src, "</tr>\n</tbody>", $pos1);

 // 目的部分を抜き出し
 $tbody = substr($src, $pos1, $pos2-$pos1);

 // 1行毎に分解して各列データを取り出す
 foreach(explode("</tr>\n<tr>", $tbody) as $row) {
 if (preg_match_All('!<td[^>]*>(.*)</td>!', $row, $mch)) {
 // ここでプリペアドステートメントを実行する
 // 指定したSQL に依るが例えばこんな感じ
 $sth->execute($mch[1]);
 }
 }
} catch (PDOException $e) {
 echo 'Connection failed: ' . $e->getMessage();
}

FREEzさんのコメント
ご返答ありがとうございます。 phpのスクレイピングも確認をしたことはありますが、イメージと違うので戸惑いました。 今回はデータベースがあるからでしょうね。表示するだけならもう少しわかりやすいのだろう、、 詰まっているのが分解して取り出すこととそれを個別にデータベースに書き込むことなので、理屈が理解できて助かります。 しかし思えば一例をあげたことも必要な部分だけだったので、そのHPを自分が紹介した方が全体が見えて回答者に対してよかったかなと、言語別に全体を比較する方がみなが理解できてよかったかなと一考しています。

質問者から

これ延長できないのか、、残念だなぁ、、、


関連質問

●質問をもっと探す●



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