TL;DR
オープンデータを提供しているサイトから、ZIPファイルに格納されたCSVファイルをダウンロードし、データを取り出す際、ダウンロードしたファイルを一旦保存して処理するアプローチを取りたくなかったので、HTTPレスポンスからストリーム経由で直接データ抽出するアプローチを採用してみました。
HTTPクライアントにはfaradayを採用していますが、通信周りの処理見直しは必要なものの、他のライブラリでも大丈夫だと思います。
他の方の参考になれば幸いです。
留意点
HTTPレスポンスが分割されるケース(チャンク形式)に耐えられるか確認してません。
require 'faraday'
require 'stringio'
require 'zip'
class FetchCsvService
BASE_URL = 'https://www.opendata.metro.tokyo.lg.jp/'
def initialize
@conn = Faraday.new(BASE_URL) do |builder|
builder.request :url_encoded
builder.adapter Faraday.default_adapter
end
end
def fetch
response = @conn.get do |req|
req.url 'gesui/yosanan4.zip'
end
if response.success?
Zip::File.open_buffer(StringIO.new(response.body)) do |files|
files.each do |file|
next unless file.name.end_with?('.csv')
csv = file.get_input_stream.read.encode('utf-8', 'sjis', invalid: :replace, undef: :replace, replace: '').split("\n")
puts "=== " + file.name.encode('utf-8', 'sjis') + " ==="
csv.each do |row|
# ここに具体的な処理を記述
puts row
end
end
end
else
puts "Request failed with status #{response.status}"
puts response.headers
puts response.env.url
response.status
end
end
end
結果
~ 略 ~
建設事業費,,,"180,000",,"180,000",,0,
=== 令和4年度予算要求概要資料CSVファイル/yosanyoukyuR4_08.csv ===
,,,,,,,(単位:千円),
事項1,事項2,4年度見積,3年度予算,増 減,建設事業区分・規模,,区分1,区分2
流域下水道建設費,,"14,500,000","14,500,000",0,管渠工事,2 か所,,
財源内訳,企業債,"894,000","790,000","104,000",水再生センター,7 か所,,
財源内訳,国庫補助金,"8,630,000","8,595,000","35,000",,,,
財源内訳,市町村建設負担金,"2,910,000","2,930,000","-20,000",,,
~ 略 ~