Pythonが便利過ぎて、いろんな作業を自動化しています。
その一環として、ファイルのダウンロードを自動化します。
ただ、そのファイルはZIPなのです。
欲しいのは、そのZIPの中にあるCSVという状況になります。
この記事では、このCSVを取得するまでを解説します。
コピペで利用可能なサンプルコードも載せておきます。
本記事の内容
- 機能の整理
- ファイル保存先(作業場)の準備
- ZIPファイルのダウンロード
- ZIPファイルの解凍
それでは、上記に沿って解説していきます。
機能の整理
「ZIPファイルをダウンロードして解凍する」
この仕様を実現するための機能を洗い出します。
大げさですが、常に機能分解は意識しておくことが重要です。
そうやって、分解した機能は以下。
- ファイル保存先(作業場)の準備
- ZIPファイルのダウンロード
- ZIPファイルの解凍
上記の3つの機能に分解できます。
これらを以下で説明していきます。
ファイル保存先(作業場)の準備
作業場を用意します。
ファイル1つをダウンロードするだけなら、わざわざその必要はありません。
プログラムと同じ階層にファイルも保存すればいいだけです。
でも、本来は保存用のディレクトリを設けるのが正しい姿になります。
そして、今回はダウンロードしたZIPを解凍します。
展開とも言いますね。
そうなると、別途ファイル保存先を用意するべきです。
ということで、最初にファイル保存先を準備することから始めます。
コードにすると、以下のようになります。
Python標準ライブラリで対応できます。
import os import shutil data_dir_path = "./temp/" # 保存先ディレクトリ作成 if os.path.exists(data_dir_path): # 既にある場合は、先に丸ごと削除する shutil.rmtree(data_dir_path) os.mkdir(data_dir_path)
プログラムの説明は、コメントのままです。
上記プログラムにより、作業場(tempディレクトリ)が作成されます。
以上、ファイル保存先(作業場)の準備についての説明でした。
次は、ZIPファイルのダウンロードを確認します。
ZIPファイルのダウンロード
プログラムの確認から、行います。
この部分もPython標準ライブラリで対応できます。
import urllib.error import urllib.request file_url = "https://disclosure.edinet-fsa.go.jp/E01EW/download?uji.verb=W1E62071EdinetCodeDownload&uji.bean=ee.bean.W1E62071.EEW1E62071Bean&TID=&PID=&SESSIONKEY=&downloadFileName=&lgKbn=2&dflg=0&iflg=0&dispKbn=1" save_path = "./temp/download.zip" try: with urllib.request.urlopen(file_url) as download_file: data = download_file.read() with open(save_path, mode='wb') as save_file: save_file.write(data) except urllib.error.URLError as e: print(e)
ダウンロード先に指定しているのは、EDINETで公開されているZIPファイルです。
詳細は、次の記事で説明しています。
上記プログラムを作成すると、tempディレクトリにdownload.zipが保存されます。
tempは、先ほど用意した作業場ですね。
なお、ファイルダウンロードにはエラーが付き物です。
そのため、例外処理も加えています。
エラーを表示するだけですけどね。
以上、ZIPファイルのダウンロードの説明でした。
次は、ZIPファイルの解凍を行っていきます。
ZIPファイルの解凍
ZIPファイルの解凍は、Python標準ライブラリで対応できます。
本当にPythonは便利ですね。
ZIPファイルは、先ほどのdownload.zipファイルを使いましょう。
このZIPファイルには、1つのCSVだけが入っています。
「EdinetcodeDlInfo.csv」というファイルです。
この場合、次のコードで作業場tempに指定したファイルだけを保存できます。
import zipfile with zipfile.ZipFile("./temp/download.zip") as obj_zip: # zipから指定ファイル(第1引数)を取得して、指定ディレクトリ(第2引数)に保存する obj_zip.extract("EdinetcodeDlInfo.csv", "./temp/")
ZIPファイルの中身すべてを保存する場合は、以下のコードになります。
import zipfile with zipfile.ZipFile("./temp/download.zip") as obj_zip: # 指定ディレクトリにすべてを保存する obj_zip.extractall("./temp/")
今回は、EdinetcodeDlInfo.csvファイルだけなので、結果は同じとなります。
tempディレクトリの中にEdinetcodeDlInfo.csvファイルが保存されているはずです。
以上、ZIPファイルの解凍について説明しました。
最後は、一連のコードをすべて結合して動作させてみましょう。
【サンプルコード】ZIPファイルをダウンロードして解凍する
上記のコードを結合します。
そうすると、ZIPファイルをダウンロードして解凍することが可能になります。
import zipfile import urllib.error import urllib.request import os import shutil ZIP_URL = "https://disclosure.edinet-fsa.go.jp/E01EW/download?uji.verb=W1E62071EdinetCodeDownload&uji.bean=ee.bean.W1E62071.EEW1E62071Bean&TID=&PID=&SESSIONKEY=&downloadFileName=&lgKbn=2&dflg=0&iflg=0&dispKbn=1" # 指定URL(第1引数)からファイルを取得して、指定パス(第2引数)に保存する def file_download(url, save_path): try: with urllib.request.urlopen(url) as download_file: data = download_file.read() with open(save_path, mode='wb') as save_file: save_file.write(data) except urllib.error.URLError as e: print(e) if __name__ == "__main__": data_dir_path = "./temp/" zip_file_path = data_dir_path + "download.zip" csv_file_name = "EdinetcodeDlInfo.csv" csv_file_path = data_dir_path + csv_file_name # 保存先ディレクトリ作成 if os.path.exists(data_dir_path): # 既にある場合は、先に丸ごと削除する shutil.rmtree(data_dir_path) os.mkdir(data_dir_path) # zip取得 file_download(ZIP_URL, zip_file_path) if os.path.exists(zip_file_path): with zipfile.ZipFile(zip_file_path) as obj_zip: # zipから指定ファイル(第1引数)を取得して、指定ディレクトリ(第2引数)に保存する obj_zip.extract(csv_file_name, data_dir_path) #obj_zip.extractall(data_dir_path) if os.path.exists(csv_file_path): print(csv_file_path)
上記コードを実行すると、tempディレクトリが同じ階層に作成されます。
tempディレクトリの中身は、以下。
「ZIP_URL」の値と次の部分を変更すれば、上記サンプルコードを汎用的に使えます。
data_dir_path = "./temp/" zip_file_path = data_dir_path + "download.zip" csv_file_name = "EdinetcodeDlInfo.csv" csv_file_path = data_dir_path + csv_file_name
以上、「ZIPファイルをダウンロードして解凍する」についての説明を終わります。