国土数値情報の一括DLツールを作ってみた

[MIERUNE Advent Calendar 2020](https://qiita.com/advent-calendar/2020/mierune) 3日目の記事です。

[国土数値情報](https://nlftp.mlit.go.jp/ksj/)のデータを一括ダウンロードしするスクリプトを作りました。

使い方だけ知りたいよ、って方は[こちら](#ツールの使い方)からお読みください。

※この記事ではコードを一部簡略化しています。ツールの全コードは[GitHubリポジトリ](https://github.com/mits003/mlit-ksj-dl-tool)を参照してください。

# ことの発端
## 国土数値情報APIが消えた
ある日、国土数値情報から大量にファイルをダウンロードしたくなりました。
取得したいデータは都道府県別かつ時系列で大正9年まで提供されている[行政区域](https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N03-v2_4.html)です。1,000以上ファイルが提供されているのですが、これを１つづつダウンロードするのはツラすぎます。

ところが、2020年の夏ごろにUIが変更されると同時にAPIの提供をやめてしまったようです。(2020年11月現在)

ということで、自動で一括ダウンロードするツールを作ることにしました。

# ツールを作る

## ダウンロードを自動化する
まずはブラウザを操作してファイルをダウンロードします。
[selenium](https://www.selenium.dev/)を使って、以下のブラウザ上での操作を自動化します。
1. ダウンロードボタンをクリック
2. モーダルで、はいをクリック

ダウンロードしたファイルはデフォルトのダウンロードフォルダではなく、カレントディレクトリに新しいフォルダを作って保存することにします。

```erb:python
# ファイルをダウンロードする関数
def file_dl(driver_path):
    dl_dir = "../download"

    # Seleniumをあらゆる環境で起動させるChromeオプション
    options = Options()
    options.add_argument('--disable-gpu')
    options.add_argument('--disable-extensions')
    options.add_argument('--proxy-server="direct://"')
    options.add_argument('--proxy-bypass-list=*')
    options.add_argument('--start-maximized')
    options.add_experimental_option("prefs", {
        "download.default_directory": dl_dir})
    # options.add_argument('--headless'); # ※ヘッドレスモードを使用する場合、コメントアウトを外す

    # ブラウザの起動
    DRIVER_PATH = ChromeDriverのパス
    driver = webdriver.Chrome(executable_path=DRIVER_PATH, chrome_options=options)

    # 国土数値情報のダウンロードページにアクセスする
    url = sys.argv[1] # コマンドラインで指定したページのurlを取得する
    driver.get(url)

    # 要素を指定する
    selector = '#menu-button'
    elements = driver.find_elements_by_css_selector(selector)
    print(str(len(elements)) + " zip file is going to be DL")

    # ブラウザの操作
    for i, e in enumerate(elements):
        print(i)
        e.click()
        time.sleep(1)
        Alert(driver).accept()
        time.sleep(2)

    return dl_dir
```

## zipファイルを解凍する
ついでにzipファイルの解凍も自動化しておきます。
それぞれのzipを解凍して得られるshpファイル群は１つのフォルダにまとめることにします。

```erb:python
def extraction(dl_dir):
    extdir_name = 'shp'  # 保存先フォルダ
    extdir_path = pathlib.Path(os.getcwd(), extdir_name)
    extdir_path.mkdir(exist_ok=True)
    ext_dir = str(extdir_path.resolve())
    print(ext_dir)
    zip_files = glob.glob(dl_dir + "/*.zip")
    print(zip_files)
    for z in zip_files:
        with zipfile.ZipFile(z) as existing_zip:
            existing_zip.extractall(ext_dir)

    return ext_dir
```


## 文字コード指定ファイルを作る
国土数値情報で取得できるshpファイルの文字コードは __Shift_JIS__ です。
例えば、QGISでshpファイルを読み込むとOSのデフォルトの文字コードで読み込まれます。そのため、OSの文字コードがUTF-8だと属性テーブルが文字化けしてしまいます。
しかしshpファイルの文字コードを指定するcpgファイルは入っていません。
自作しましょう。

shpファイルと同じ名称のテキストファイルを作成し、__.cpg__ で保存します。

```erb:python
def create_cpg(extent, encoding, ext_dir):
    files = glob.glob(ext_dir + "/*." + shp)

    for f in files:
        basename = os.path.splitext(os.path.basename(f))[0]
        path = os.path.join(ext_dir, basename + ".cpg")
        cpg = open(path, 'w')
        cpg.write("Shift_JIS")
        cpg.close()
```

cpgファイルはこんな感じになります。

```erb:*.cpg
Shift_JIS
```

# ツールの使い方
## ダウンロードツール
1. 必要なライブラリをインストールする

```
$ pip install selenium
```

2. OSに合わせて、[ここ](https://sites.google.com/a/chromium.org/chromedriver/home)からChromeDriverをダウンロードする。
3. ダウンロードしたWebDriverを __mlit-ksj-dl-tool/WebDriver__ に保存する。
4. [国土数値情報ダウンロードサービス](https://nlftp.mlit.go.jp/ksj/)からダウンロードしたいページのURLを取得する。
5. 以下のコマンドを実行する。

```
$ python3 mlit_ksj_dl.py ダウンロードしたいページのURL
```
**mlit-ksj-dl-tool/download** にダウンロードしたzipファイルが、**mlit-ksj-dl-tool/shp** に展開したshpファイル群が保存されます。

# まとめ
国土数値情報から大量のファイルをダウンロードして、いい感じに使えるようにしてみました。
ダウンロードだけするつもりが、あれもこれもと機能を追加したくなってしまうのはなぜなんでしょうか。

ツールはご自由にご利用ください。
https://github.com/mits003/mlit-ksj-dl-tool