0
0

Zip格納されたCSVファイルをHTTPレスポンスから直接取り出す

Posted at

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",,,

~ 略 ~

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0