過去のスクレイピング に関する質問に追加で、お伺いしたいです。


https://teideninfo.tepco.co.jp/day/teiden/index-j.html

こちらをスクレイピング をしてきましたが、仕様変更でできなくなりました。

前回、お助け頂き、データをxmlデータを取得できるようにして頂きました。
https://q.hatena.ne.jp/1586292241

その後、
各データを配列に入れてデータベースに入れようとしたけど、ちょっとうまくできません。
gets_text以外の方法がいいのかなと、色々調べているのですが、
これを機に過去のログからスクレイピング を一から勉強しなおそうと考えたけど、他の予定に追われて時間が足りないので教えて貰えないかなと思いました。
xmlに切り替えてから前のやり方で取れなくなったのかな。
方法は問わないので、教えて頂けると助かります。

一応、過去の分を今週の金曜日分までしか収集していないので、また一つ一つ収集しないといけないってことかな、、

どうぞよろしくお願いします。

回答の条件
  • 1人10回まで
  • 登録:
  • 終了:2020/06/17 01:00:06
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。
id:FREEz

質問者から

FREEz2020/07/09 17:11:24

あれ、なんで質問終了でなくてキャンセルになっているんだろう?

回答0件)

回答はまだありません

  • id:tobeoscontinue
    お手数をおかけします。
    5/20で走らせてみましたがエラーは出なかったのですが。
    どういう状況でしょうか。
  • id:FREEz
    お返事ありがとうございます。
    各日付でスクレイピング は問題ないです。それぞれ日付指定すれば動いています。

    おそらく丸ごと日付からのテキストデータなら保存もできるでしょうが、
    配列から各フィールドごとにどのようにデータベースに登録したら良いかな、という点で悩み、
    前やってたようにデータ変数に入れてデータごとに入れる方がいいだろうかと試行錯誤しているところです。
  • id:tobeoscontinue
    https://q.hatena.ne.jp/1473168239での私の回答では
    [発生・復旧時間
    停電地域 都道府県
    [[市区町村,地区,,,]]
    原因
    発生軒数]
    の5個の要素の配列で表していました。

    https://q.hatena.ne.jp/1586292241では
    発生日時,復旧日時,都県名,市区町村名|市区町村名,地区名|地区名|地区名,停電軒数,停電理由,更新日時
    の8個に区切られた文字列で表していました。

    データベースにはどのような内容のものをどういう順で保存しているのでしょうか

    5/20のデータでやってみたらさっそく致命的なバグが見つかってしまいましたorz。
    修正に少しお時間を頂戴します。
  • id:FREEz
    過去にも同じ相談しているためリンク先にもありますが、レコードの項目それぞれを各データ分けて、そのままの順番です。
    むしろ表示されている順番でそれぞれの項目ごとに保存し、日付の順番なので。公式そのままです。
  • id:tobeoscontinue
    段々質問の内容がわからなくなってきましたがhttps://q.hatena.ne.jp/1473168239での私の回答
    の形式になるべく近づける形で書き直してみましたがどうでしょう。
    def _day(d)
    0 < d.size ? d.gsub(/(\d+)\/(\d+)\/(\d+) (\d\d:\d\d)/) {
    sprintf("%d月%d日 %s", $2.to_i, $3.to_i, $4) } : ''
    end

    def tepco_xml(xml)
    doc = REXML::Document.new(xml)
    doc.get_elements('//データ部').map do |e|

    def e.gets_text(name)
    get_elements('./'+name).map {|c| c.text }.join('|')
    end
    def e.chiq_text(name)
    get_elements('./'+name).map {|c| [c.text,
    c.get_elements('../地区部/地区名').map {|d| d.text }.join('、')] }
    end
    [ _day(e.gets_text('発生日時'))+'~'+ # 発生日時>
    _day(e.gets_text('復旧日時')), # 復旧日時>
    e.gets_text('都県部/都県名'), # 都県名>
    e.chiq_text('都県部/市区町村部/市区町村名'), # 市区町村名/地区名>
    e.gets_text('停電軒数'), # 停電軒数>
    e.gets_text('停電理由'), # 停電理由>
    e.gets_text('更新日時') ] if e.has_text? # 更新日時>
    end
    end

    tepco = tepco_xml(tepco_cache("teiden"))
    tepco.each {|info|
    puts info[0]
    puts info[1]
    puts info[2].map {|l| ' '+l[0]+':'+l[1]+"\n" }
    puts info[3]
    puts info[4]
    puts " "
    }
  • id:FREEz
    ありがとうございます。
    とりあえず試してエラー出て試行錯誤して動いています。
    もう少し確認してみますが。まずはご報告まで。
    今、これは指定した日(ページ)からそれぞれinfo[]で指定して取り出す・表示できるってことですよね。
    今振り返ったら、これはindex1ページのみで2ヶ月分遡ることができないんですね。
    前回書いていただいた分のところで、URLのindexやdayをいじるところがあったため、
    繰り返し処理試していますがうまく行かない、、前提で組まれてる感じなんだけどそこを活用できないなぁ、、
  • id:tobeoscontinue
    tepco = tepco_xml(tepco_cache("teiden"))

    tepco = tepco_xml(tepco_cache("teiden","day001"))
    と翌日なら"day001"を翌々日なら"day002"とするだけです。
    面倒なら
    1.upto(60) {|num| days = "day#{'%03d' % num}"
    tepco = tepco_xml(tepco_cache("teiden", days))
    tepco.each {|info|
    puts info[0]
    puts info[1]
    puts info[2].map {|l| ' '+l[0]+':'+l[1]+"\n" }
    puts info[3]
    puts info[4]
    puts " "
    }
    }
    とすればday001からday060まで繰り返します。

    def getopt(fxml=["index"])
    dgt = []
    ARGV.each { |pm| dgt << pm.to_i if pm =~ /^\d+$/
    Dir.glob("*-j.xml") {|f| File.delete(f) } if pm == '-new' }

    return fxml if dgt.size == 0

    s, l = dgt << 1
    fxml.fill(1,60) {|n| "day#{'%03d'%n}"}[s,l]
    end
    getoptは引数を処理するためのメソッドです。
    使い方はスタートと個数を指定します。
    何も指定しないと ["index"]を返します。
    0 10だと["index","day001","day002","day003","day004","day005","day006","day007","day008","day009"]
    1 3だと["day001","day002","day003"]
    という感じです。
    getopt.each {|days|
    tepco = tepco_xml(tepco_cache("teiden", days))
    tepco.each {|info|
    puts info[0]
    puts info[1]
    puts info[2].map {|l| ' '+l[0]+':'+l[1]+"\n" }
    puts info[3]
    puts info[4]
    puts " "
    }
    }
    特定の日を処理したいのならtepco_cache("teiden","day0xx")とその都度変更を加えて
    一回だけ全部したいならuptoを使って
    不定期にあるようであればgetoptを実装したほうが便利かなぁと思います。
  • id:FREEz
    確認したところ、 2020/05/22 16:45:51 の書き込み通り

    def _day(d)
    0 < d.size ? d.gsub(/(\d+)\/(\d+)\/(\d+) (\d\d:\d\d)/) {
    sprintf("%d月%d日 %s", $2.to_i, $3.to_i, $4) } : ''
    end
    以下〜〜〜を書き足す所で、動くのですが、

    44 tepco = tepco_xml(tepco_cache("teiden"))
    45 tepco.each {|info|
    46 puts info[0]
    47 puts info[1]
    の行で以下エラーが出ています。

    :46:in `block in <main>': undefined method `[]' for nil:NilClass (NoMethodError)
    from file名:45:in `each'
    from file名:45:in `<main>'

    色々確認しましたが、ミスがあるわけでもinfoで数が足りていないわけでもなさそうで。
    これに書き換える前はエラーは出ていませんでしたので。
    書き換えたdef _day(d)以下で原因を探っています。

    またこの辺りで、
    「停電履歴情報はありません。」となるとエラーが出ますでしょうか。
  • id:FREEz
    追加で調べていますが、「停電履歴情報はありません。」の場合は
    やはり上記エラーが出ているようです。
    5/1でも同様に確認。今はちょうど001=5/24がそれなので。
    ミスがあるわけでもないので、一番右の更新時間の分のinfoがないからエラーになるのだろうか、、
    またShunteiの方だとうまくいっていない感じですね。同じデザインに見えるけど何か違うのだろうか。
  • id:tobeoscontinue
    > 「停電履歴情報はありません。」となるとエラーが出ますでしょうか。
    この場合、データが無いためnilとなっていました。
    nilを削除するためにtepco_xmlのmapのendの後に.compactを追加して下さい。
    e.gets_text('更新日時') ] if e.has_text? # 更新日時>
    end.compact
    end

    Shunteiの方はどの様な点がうまくいっていない感じなのでしょうか
  • id:FREEz
    どうも、shunteiに切り替えて動かすと表示されませんでした。
    teidenとshunteiを同時に両方やる方法はあるのでしょうか。
  • id:tobeoscontinue
    > shunteiに切り替えて動かすと表示されませんでした。
    5/28~5/21は『瞬時電圧低下履歴情報はありません。』ということでデータが無いので表示されません。
    5/20は
    tepco = tepco_xml(tepco_cache("shuntei","day008"))
    tepco.each {|info|
    puts info[0]
    puts info[1]
    puts info[2].map {|l| ' '+l[0]+':'+l[1]+"\n" }
    puts info[3]
    puts info[4]
    puts " "
    }
    とすると
    5月20日 14:03~
    神奈川県
    川崎市川崎区:
    川崎市幸区:

    と表示されています。
    何日の分がどのようになっているか具体的に示していただけると対処がしやすいです。
  • id:FREEz
    おっしゃる通り、それです。
    一件ずつ見て、
    データがないので表示されないところもエラー出ていない点も確認していたのですが、
    「市」「区」までしか表示されなかったので、途中まで??と感じました。
    teidenの方は右端の更新時間まで全件で表示されていたから、特にそのように思っていました。
  • id:FREEz
    ありがとうございます。
    やはり、shunteiの方だけ「市」で止まっているのか、それより右側の
    「地区」「停電件数」「停電理由」「更新日時」が表示されません。
    teidenの方では表示されるため、この違いはなんだろうなぁ、と確認しています。
    デザインが違うのかな。htmlの方、タグが違うのだろうか、、同じに見えたのだが、、




  • id:tobeoscontinue
    > 「地区」「停電件数」「停電理由」「更新日時」が表示されません。
    瞬時電圧低下履歴情報を見てもらうとわかると思いますが
    発生日時、都県名、市区町村名、更新日時のみです。
    xmlファイルにもデータはありませんでした。
    <データ部>
    <発生日時>2020/05/20 14:03</発生日時>
    <都県部>
    <都県名>神奈川県</都県名>
    <市区町村部>
    <市区町村名>川崎市川崎区</市区町村名>
    <市区町村名>川崎市幸区</市区町村名>
    </市区町村部>
    </都県部>
    <更新日時>2020/05/20 14:10</更新日時>
    </データ部>
    ただこの回だけなのかもしれませんが。
    市区町村名、地区名、停電軒数、停電理由のデータが付加されれば同じように処理されます。
    更新日時は同じようにinfo[5]に入っています。
  • id:FREEz
    なるほど、HP側も確認しつつ結果を見ていたのですが、そういうこともあったわけですね。
    いくつか確認する中で地名があった表示もあったような、、と感じていたため、再度確認してみます。
  • id:FREEz
    やはり、shunteiの方は他は同じでも上記認識できないだけでなく、その後でエラーになります。
    直近で6/7とその数日前まで連日で表示されているので分かりました。
     複数箇所をスクレイピング しても、「市」までしか表示されませんね。
    エラーは以下が表示されました。
    :56:in `<main>': undefined method `tepco_csv' for main:Object (NoMethodError)
    Did you mean? tepco_cache
    tepco_xml

    変数をshunteiに変えただけなのに、となるとやはり公式がどこか違うということでしょうか。
  • id:tobeoscontinue
    > shunteiの方は他は同じでも上記認識できないだけでなく、
    上記認識とは具体的にどのような点かお知らせ下さい。

    > エラーは以下が表示されました。
    > :56:in `<main>': undefined method `tepco_csv' for main:Object (NoMethodError)
    > Did you mean? tepco_cache
    > tepco_xml
    https://q.hatena.ne.jp/1586292241ではcsv形式でデータを返す方式でしたが
    今回の質問でデータベースに入れる部分で上手くいかないということなので
    https://q.hatena.ne.jp/1473168239でのteiden_parseと同じように配列で返すように
    tepco_xmlを変えたコードを5/22にコメントしました。それ以降tepco_csvとの整合性は
    取ってません。undefined methodということなので何処かで使っているのでしょうが
    そのコードは間違っています。現在どのように実装しているのか公開できる部分を示して
    いただけると対処方法がわかると思います。

    > 複数箇所をスクレイピング しても、「市」までしか表示されませんね。
    停電の場合でしょうか、瞬時電圧低下の場合でしょうか
    瞬時電圧低下の場合は6/1のコメントでしたように市区町村名までです。
    「市」まで表示されているものをスクレイピングすると「市」までしか表示されません。
    ということでしょうか。
  • id:FREEz
    お返事ありがとうございます。
    申し訳ありませんでした、エラーに関しては、全体を見返り見直したところ、tepco_csvを使い自分で表示する文を最後に追加していたため、それを省いたら消えエラーはなくなりました。
    また、
    表示されないというのは、こちらも少し勘違いしていたかもしれないのですが、
    「自動復旧等による5分未満の停電」は「5分以上」と一緒にスクレイピングされていますでしょうか。ここの区分けを調べていて、瞬時電圧低下に関しては問題なく機能していました。
  • id:tobeoscontinue
    >「自動復旧等による5分未満の停電」は「5分以上」と一緒にスクレイピングされていますでしょうか。
    データ部は区分けしていないので一緒になっています。
    tepco = tepco_xml(tepco_cache("teiden"))
    p tepco.size
    とすることで配列の個数を表示できるので一緒になっていることを確認できます。

    区別する場合は
    doc.get_elements('//データ部').map do |e|
    の部分を
    doc.get_elements('//停電表示選択[@値="5分以上の停電"]/データ部').map do |e|

    doc.get_elements('//停電表示選択[@値="自動復旧等による5分未満の停電"]/データ部').map do |e|
    とすることでどちらか一方にすることができます。
  • id:FREEz
    ありがとうございます。
    マックの方では順調に動いていて、
    Windowsの方だとエラーになっていますが、恐らくRubyが更新されていないからかと手間取っています。

    C:/RailsInstaller/Ruby2.1.0/lib/ruby/2.1.0/net/http.rb:920:in `connect': SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: tlsv1 alert protocol version (OpenSSL::SSL::SSLError)

    検索したら同様に引っかかっている方々がおられるので、調整していますがかなり大変で。
    どのVerがいいなどはありますでしょうか。

  • id:tobeoscontinue
    https://q.hatena.ne.jp/1586292241の質問で5/4にコメントしているのですが
    SSL_connectのエラーではないでしょうか
    証明書のダウンロードと環境変数の設定はされてますでしょうか
  • id:FREEz
    ありがとうございます。
    証明書もあったのですが、
    どうやらpathとVerを見たところ、Rubyを2カ所に入れているようで、とりあえず環境からまとめたいと思います。
    解らなかったらまた別枠で質問させて頂きます。
    当初の質問に関しては解決できたため、助かりました。
    ありがとうございました。


  • id:FREEz
    ありがとうございます。
    証明書もあったのですが、
    どうやらpathとVerを見たところ、Rubyを2カ所に入れているようで、とりあえず環境からまとめたいと思います。
    解らなかったらまた別枠で質問させて頂きます。
    当初の質問に関しては解決できたため、助かりました。
    ありがとうございました。


  • id:FREEz
    すみませんでした。
    運営に問い合わせて聞いてみたところ、
    回答が0だからキャンセルされていて、回答者でなければ
    報酬は払えないってことでした。

    全く知らず気付きませんでした、途中で回答の方にもお願いしておけばよかった。
    昔の方にポイントを送付できればよかったのだけど、できなくなっていた、、、何かの金融の規制かな。
    また別で質問あげようと思うので、その時は回答の方にもちょっとコメントを残す感じでお願いします。

  • id:tobeoscontinue
    前回の質問の時、ポイントを多くしてもらっているのではないでしょうか。
    また今回の質問は前回の質問で解決すべきだったと思うので前回の延長と
    いうことで理解していただければと思います。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません