1586292241 情報元の仕様が変わりエラーとなったスクレイピングを再度動かせるようにして欲しい。Ruby。


久しく質問させて頂きます。
以下関係する過去の質問。
リンク先でも表記され下に行くほど古い質問です。
https://q.hatena.ne.jp/1473168239
https://q.hatena.ne.jp/1455811321
https://q.hatena.ne.jp/1443599941
https://q.hatena.ne.jp/1441975146
https://q.hatena.ne.jp/1434818671
http://q.hatena.ne.jp/1436077068

関連するURL。
https://teideninfo.tepco.co.jp/day/teiden/index-j.html
https://teideninfo.tepco.co.jp/day/shuntei/index-j.html

最近エラーを出すようになりご相談させて頂きたいです。
というのも元の仕様が変わったためで、日付が変わるごとにURLもカウントアップし日付ごとのURLでそれぞれ結果を表示していた仕様が、日付選択後も同一のURLでそれぞれ日付ごとの結果を表示する仕様になったためです。
この場合、どのようにスクレイピングすれば良いのだろう?とお教え頂きたいです。
今回のエラー結果は質問本文が500文字以内のためここに書けず、画像添付します。
必要であれば実行ファイルも添付します。
お手間おかけしますが、
どうぞよろしくお願いします。

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

ベストアンサー

id:tobeoscontinue No.1

回答回数220ベストアンサー獲得回数59

ポイント2000pt

XMLファイルが準備されたようでindex.htmlからjavascriptを使ってXMLファイルを読み込み表示をしているようです。
直接XMLファイルを読み込むことでhtmlをパースするよりは楽になりました。
XMLファイルはindex-j.htmlがindex-j.xmlとなっています。ファイルは日付ではなく当日、前日、前々日となっていて60日分は遡れるようです。

nokogiriが何故かダメだったので今回はrexmlです。

require "rexml/document"
require "open-uri"

def tepco_cache(path, day='index')
  cache_file = path+'-'+day+'-j.xml'
  file_path = File.exist?(cache_file) ? cache_file : "https://teideninfo.tepco.co.jp/day/"+path+"/"+day+"-j.xml"
  xml = open(file_path).read
  open(cache_file, 'w').write(xml) if file_path[0] == 'h'
  return xml
end

# def tepco_cache(path, day='index')
#   open("https://teideninfo.tepco.co.jp/day/"+path+"/"+day+"-j.xml").read
# end

def tepco_csv(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
   [ e.gets_text('発生日時'),			    # 発生日時
     e.gets_text('復旧日時'),                # 復旧日時
     e.gets_text('都県部/都県名'),           # 都県名
     e.gets_text('都県部/市区町村部/市区町村名'),   # 市区町村名
     e.gets_text('都県部/市区町村部/地区部/地区名'),  # 地区名
     e.gets_text('停電軒数'),				# 停電軒数
     e.gets_text('停電理由'),				# 停電理由
     e.gets_text('更新日時') ].join(',') if e.has_text? # 更新日時
  end.join("\n")
end

print tepco_csv(tepco_cache("teiden"))
print tepco_csv(tepco_cache("shuntei"))

tepco_cacheは一度ネットから落としたら次回はローカルから読み込むためのものです。そんなもの必要ないというのであれば注釈にあるように変更すれば毎回ネットから落とせます。日付が変わってもファイル名は同じなので新しい日付の場合はファイルを消すか移動させてください。

tepco_csvはxmlファイルを読み込んでcsvの文字列で返します。
市区町村名、地区名は複数あるので|で区切っています。
一つしか無い場合はget_textでいいのですが復旧日時など無い場合にエラーが出るので助長ですがgets_textにしています。
if e.has_text? は4/11のようにデータ部の中身が無い場合の対処でこれが無いと
,,,,,,,,のようなcsv文字列が返ることになります。
データ部は5分以上の停電と自動復旧等による5分未満の停電の二つがあるのですが区別していません。

他8件のコメントを見る
id:tobeoscontinue

バグが見つかってしまいました。すいませんorz。
現象は市区町村名が複数ある場合に地区名がどちらに対応しているのかわからないというものです。
5/20のファイルでは早川町と身延町があるのですが地区名が
雨畑|大島|榑坪|高住|笹走|塩之上|千須和|初鹿島|保|薬袋|粟倉|江尻窪|遅沢|中山|梨子|平須|福原|古長谷|身延七面山参道|身延|矢細工
となり区切りがわかりません。そこで市区町村名/地区名と前に市区町村名を付加し
早川町/雨畑|早川町/大島|早川町/榑坪|早川町/高住|早川町/笹走|早川町/塩之上|早川
町/千須和|早川町/初鹿島|早川町/保|早川町/薬袋|身延町/粟倉|身延町/江尻窪|身延町/遅沢|身延町/中山|身延町/梨子|身延町/平須|身延町/福原|
身延町/古長谷|身延町/身延七面山参道|身延町/身延|身延町/矢細工
と修正します。新たにchiq_textを追加しました。

def tepco_csv(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.get_elements('../../市区町村名')[0].text+'/'+c.text }.join('|')
end
[ e.gets_text('発生日時'), # 発生日時>
e.gets_text('復旧日時'), # 復旧日時>
e.gets_text('都県部/都県名'), # 都県名>
e.gets_text('都県部/市区町村部/市区町村名'), # 市区町村名>
e.chiq_text('都県部/市区町村部/地区部/地区名'), # 地区名>
e.gets_text('停電軒数'), # 停電軒数>
e.gets_text('停電理由'), # 停電理由>
e.gets_text('更新日時') ].join(',') if e.has_text? # 更新日時>
end.join("\n")
end

2020/05/21 18:35:34
id:FREEz

わざわざありがとうございます。確認しました。。

2020/05/25 19:29:54

その他の回答1件)

id:tobeoscontinue No.1

回答回数220ベストアンサー獲得回数59ここでベストアンサー

ポイント2000pt

XMLファイルが準備されたようでindex.htmlからjavascriptを使ってXMLファイルを読み込み表示をしているようです。
直接XMLファイルを読み込むことでhtmlをパースするよりは楽になりました。
XMLファイルはindex-j.htmlがindex-j.xmlとなっています。ファイルは日付ではなく当日、前日、前々日となっていて60日分は遡れるようです。

nokogiriが何故かダメだったので今回はrexmlです。

require "rexml/document"
require "open-uri"

def tepco_cache(path, day='index')
  cache_file = path+'-'+day+'-j.xml'
  file_path = File.exist?(cache_file) ? cache_file : "https://teideninfo.tepco.co.jp/day/"+path+"/"+day+"-j.xml"
  xml = open(file_path).read
  open(cache_file, 'w').write(xml) if file_path[0] == 'h'
  return xml
end

# def tepco_cache(path, day='index')
#   open("https://teideninfo.tepco.co.jp/day/"+path+"/"+day+"-j.xml").read
# end

def tepco_csv(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
   [ e.gets_text('発生日時'),			    # 発生日時
     e.gets_text('復旧日時'),                # 復旧日時
     e.gets_text('都県部/都県名'),           # 都県名
     e.gets_text('都県部/市区町村部/市区町村名'),   # 市区町村名
     e.gets_text('都県部/市区町村部/地区部/地区名'),  # 地区名
     e.gets_text('停電軒数'),				# 停電軒数
     e.gets_text('停電理由'),				# 停電理由
     e.gets_text('更新日時') ].join(',') if e.has_text? # 更新日時
  end.join("\n")
end

print tepco_csv(tepco_cache("teiden"))
print tepco_csv(tepco_cache("shuntei"))

tepco_cacheは一度ネットから落としたら次回はローカルから読み込むためのものです。そんなもの必要ないというのであれば注釈にあるように変更すれば毎回ネットから落とせます。日付が変わってもファイル名は同じなので新しい日付の場合はファイルを消すか移動させてください。

tepco_csvはxmlファイルを読み込んでcsvの文字列で返します。
市区町村名、地区名は複数あるので|で区切っています。
一つしか無い場合はget_textでいいのですが復旧日時など無い場合にエラーが出るので助長ですがgets_textにしています。
if e.has_text? は4/11のようにデータ部の中身が無い場合の対処でこれが無いと
,,,,,,,,のようなcsv文字列が返ることになります。
データ部は5分以上の停電と自動復旧等による5分未満の停電の二つがあるのですが区別していません。

他8件のコメントを見る
id:tobeoscontinue

バグが見つかってしまいました。すいませんorz。
現象は市区町村名が複数ある場合に地区名がどちらに対応しているのかわからないというものです。
5/20のファイルでは早川町と身延町があるのですが地区名が
雨畑|大島|榑坪|高住|笹走|塩之上|千須和|初鹿島|保|薬袋|粟倉|江尻窪|遅沢|中山|梨子|平須|福原|古長谷|身延七面山参道|身延|矢細工
となり区切りがわかりません。そこで市区町村名/地区名と前に市区町村名を付加し
早川町/雨畑|早川町/大島|早川町/榑坪|早川町/高住|早川町/笹走|早川町/塩之上|早川
町/千須和|早川町/初鹿島|早川町/保|早川町/薬袋|身延町/粟倉|身延町/江尻窪|身延町/遅沢|身延町/中山|身延町/梨子|身延町/平須|身延町/福原|
身延町/古長谷|身延町/身延七面山参道|身延町/身延|身延町/矢細工
と修正します。新たにchiq_textを追加しました。

def tepco_csv(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.get_elements('../../市区町村名')[0].text+'/'+c.text }.join('|')
end
[ e.gets_text('発生日時'), # 発生日時>
e.gets_text('復旧日時'), # 復旧日時>
e.gets_text('都県部/都県名'), # 都県名>
e.gets_text('都県部/市区町村部/市区町村名'), # 市区町村名>
e.chiq_text('都県部/市区町村部/地区部/地区名'), # 地区名>
e.gets_text('停電軒数'), # 停電軒数>
e.gets_text('停電理由'), # 停電理由>
e.gets_text('更新日時') ].join(',') if e.has_text? # 更新日時>
end.join("\n")
end

2020/05/21 18:35:34
id:FREEz

わざわざありがとうございます。確認しました。。

2020/05/25 19:29:54
id:chsm No.2

回答回数33ベストアンサー獲得回数5

見れているように見えますが。

id:FREEz

質問者から

FREEz2020/05/12 17:34:58

ご回答ありがとうございます。大変助かります。

また申し訳なかったです。お待たせいたしました。

WindowsUPDATEによる異常、回復できず故障、からようやく戻すことができました。

至急見させて頂きます。

が、朝早くて夜に対応できていないので、明日また、、

コメントはまだありません

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

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

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

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