Snippets

Takehiko NOZAKI 国土地理院 基盤地図情報 数値標高モデル ダウンローダー

Created by Takehiko NOZAKI last modified
# 国土地理院 基盤地図情報 数値標高モデル ダウンローダー

# Copyright (c)2017 Takehiko NOZAKI,
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#

# パラメーター
Param(
[Parameter(Position=0)]
[ValidateSet('5m','10m')]
[string]$Mesh='10m'
)
$Mesh2Param = @{
  '5m'=0;
  '10m'=1;
}

# 定数
$userAgent         = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36'
$baseUrl           = 'https://fgd.gsi.go.jp/download/'
$menuUrl           = [System.Uri]($baseUrl + 'menu.php')           # メニュー画面
$enqueteUrl        = [System.Uri]($baseUrl + 'enquete.php')        # アンケート画面
$loginUrl          = [System.Uri]($baseUrl + 'login.php')          # ログイン画面
$enqresultUrl      = [System.Uri]($baseUrl + 'enqresult.php')      # アンケート結果画面
$mapGisUrl         = [System.Uri]($baseUrl + 'mapGis.php?tab=dem') # ファイル選択画面(数値標高モデル)
$ajaxCityUrl       = [System.Uri]($baseUrl + 'Ajax/city.php')      # 市町村検索
$ajaxListdemUrl    = [System.Uri]($baseUrl + 'Ajax/listdem.php')   # 2次メッシュ検索
$listUrl           = [System.Uri]($baseUrl + 'list.php')           # ダウンロードファイルリスト画面
$dlUrl             = [System.Uri]($baseUrl + 'dl.php')             # ファイルダウンロード
$logoutUrl         = [System.Uri]($baseUrl + 'LogOut.php')         # ログアウト画面

# PowerShellプロセスのカレントディレクトリをシェル内と同期させる
[System.IO.Directory]::SetCurrentDirectory((Get-Location -PSProvider FileSystem).Path)

# TLS1.2を有効にする
if (-not ([Net.ServicePointManager]::SecurityProtocol -band [Net.SecurityProtocolType]::Tls12)) {
	[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
}

# ユーザー名/パスワード入力および保持
try {
  $credencial = Get-Credential
} catch {
  # キャンセルボタン押下
  throw $_
}
# 2次メッシュ重複チェック(県+市町村で検索すると重複が発生する)
$mesh2DEMList = @{}

# ダウンロード済ファイルチェック
#    key  : ファイル名
#    value: サイズ(KB)
$ziplist = @{}
Get-ChildItem '.\' -Filter *.zip | ForEach-Object {
  $ziplist[$_.Name] = [math]::Ceiling($_.Length / 1024)
}

# ログイン
function Session-Login {
  # ログイン画面へ直接遷移はNG、アンケート画面からのリダイレクトが必須
  $login = Invoke-WebRequest $enqueteUrl `
             -Method Get -WebSession $loginSession `
             -UserAgent $userAgent -Headers @{'Referer'=$menuUrl}
  # 認証
  $form = $menu.Forms[0]
  $form.Fields['user_id'] = $credencial.UserName
  $form.Fields['user_pw'] = $credencial.GetNetworkCredential().Password
  $enquete = Invoke-WebRequest $loginUrl `
               -Method Post -Body $form -WebSession $loginSession `
               -UserAgent $userAgent -Headers @{'Referer'=$loginUrl}
  $p = $enquete.ParsedHtml.getElementsByTagName('p')
  # 成功した場合はアンケート画面へ、失敗した場合はログイン画面にエラーメッセージ表示
  if ($p.Length -Ge 2 -And $p[1].innerText -Eq 'ログインエラー') {
    throw 'invalid username or password.'
  }
  # アンケート回答
  $form = $enquete.Forms[0]
  $loginEnd = Invoke-WebRequest $enqresultUrl `
                -Method Post -Body $form -WebSession $loginSession `
                -UserAgent $userAgent -Headers @{'Referer'=$enqueteUrl}
}

# ログアウト
function Session-Logout {
  $logout = Invoke-WebRequest $logoutUrl `
              -Method Get -WebSession $loginSession `
              -UserAgent $userAgent -Headers @{'Referer'=$menuUrl}
}

# 市町村検索
function Get-Cities {
  Param($pref)
  $postdata = @{
    'pref'=$pref;
  }
  $ajaxCity = Invoke-WebRequest $ajaxCityUrl  `
                -Method Post -Body $postdata -WebSession $loginSession `
                -UserAgent $userAgent -Headers @{'Referer'=$mapGisUrl}
  return $ajaxCity.Content -Split ','
}

# 2次メッシュ検索
function Get-Mesh2DEMs {
  Param($pref, $city)
  $postdata = @{
    'mesh'=$Mesh2Param[$Mesh];
    'ab[a]'=1;'ab[b]'=1;
    'pref'=$pref;
    'citys[]'=$city;
  }
  $ajaxListdem = Invoke-RestMethod $ajaxListdemUrl `
                   -Method Post -Body $postdata -WebSession $loginSession `
                   -UserAgent $userAgent -Headers @{'Referer'=$mapGisUrl}
  return $ajaxListdem.list
}

# ダウンロードファイル検索
function Get-Lists {
  Param($mesh2DEM)
  function Get-Del {
    Param($col)
    if (-Not ($col.getElementsByTagName('input')[0].id -Match '^chk(\d+)$')) {
      throw 'HTML parse error.'
    }
    return $Matches[1]
  }
  function Get-DLFile0 {
    Param($col)
    return $col.getElementsByTagName('input')[0].value
  }
  function Get-DLFile0Size {
    Param($col)
    return [int]$col.innerText
  }
  function Get-SelListId {
    Param($col)
    if (-Not ($col.getElementsByTagName('input')[0].outerHtml `
      -Match 'onclick=\"download\(this, (\d+),\d+\);\"')) {
      throw 'HTML parse error.'
    }
    return $Matches[1]
  }
  $postdata = @{
    'data'=0;'fmt'=1;
    'mapFlg'=1;
    't1'=0;'t2'=0;'t3'=0;'t4'=0;'t5'=0;
    't6'=0;'t7'=0;'t8'=0;'t9'=0;'t10'=0;
    'dem_mesh'=$Mesh2Param[$Mesh];
    'tab'=1;
    'mesh5_A'=1;'mesh5_B'=1;'mesh10_A'=1;'mesh10_B'=1;
    'fromDate'='10000000';'untilDate'='99991231';
    'mesh2'=$null;'mesh2Old'=$null;'mesh2DEM'=$mesh2DEM;
    'map'=0;
    'fromY'=$null;'fromM'=$null;'fromD'=$null;
    'untilY'=$null;'untilM'=$null;'untilD'=$null;
    'pref'=$null;
    'textfield2'=$null;
  }
  # ダウンロードファイルリスト画面へ遷移
  $list = Invoke-WebRequest $listUrl -WebSession $loginSession `
            -Method Post -Body $postdata `
            -UserAgent $userAgent -Headers @{'Referer'=$mapGisUrl}
  $files = @()
  $table = $list.ParsedHtml.getElementById('selectList')
  $rows = $table.getElementsByTagName('tr')
  # ヘッダ1行飛ばし
  for ($i = 1; $i -Lt $rows.Length; $i++) {
    $cols = $rows[$i].getElementsByTagName('td')
    # メタデータ、申請書類は無視
    if ($cols[2].innerText -Ne '基盤地図情報(数値標高モデル)') {
      break
    }
    $file = @{
      'del'=(Get-Del -col $cols[0]);
      'DLFile0'=(Get-DLFile0 -col $cols[1]);
      'DLFile0Size'=(Get-DLFile0Size -col $cols[6]);
      'selListId'=(Get-SelListId -col $cols[7]);
    }
    $files += $file
  }
  return $files
}

# ファイルダウンロード
function Download-Files {
  Param($DLFile0, $selListId)
  $postdata = @{
    'selListId'=$selListId;
    'demmap'=1;
    'data'=0;
    'tab'=1;
    'selMetaName'=$null;
    'DLFile0'=$DLFile0;
  }
  Invoke-WebRequest $dlUrl `
    -Method Post -Body $postdata -WebSession $loginSession `
    -UserAgent $userAgent -Headers @{'Referer'=$listUrl} `
    -OutFile $DLFile0
}

# ダウンロード済ファイルをリストから削除
function Delete-Lists {
  Param($delfile)
  $postdata =@{
    'delfile'=($delfile -Join ',');
    'data'=0;
    'fmt'=1;
    'mapFlg'=1;
    'tab'=1;
    'pageflg'=0;
    'page'=$null;
    't1'=0;'t2'=0;'t3'=0;'t4'=0;'t5'=0;
    't6'=0;'t7'=0;'t8'=0;'t9'=0;'t10'=0;
  }
  $list = Invoke-WebRequest $listUrl -WebSession $loginSession `
            -Method Post -Body $postdata `
            -UserAgent $userAgent -Headers @{'Referer'=$listUrl}
}

# メニュー画面へ遷移
$menu = Invoke-WebRequest $menuUrl `
          -Method Get -SessionVariable loginSession `
          -UserAgent $userAgent
try {
  Session-Login
  # ファイル選択画面(数値標高モデル)へ遷移
  $form = $menu.Forms[0]
  $form.Fields['fmt'] = '1'
  $form.Fields['data'] = '1'
  $mapGis = Invoke-WebRequest $mapGisUrl `
    -Method Post -Body $form -WebSession $loginSession `
    -UserAgent $userAgent -Headers @{'Referer'=$menuUrl}
  # 都道府県
  $mapGis.ParsedHtml.getElementById('dem_pref').getElementsByTagName('option') | Where {
    $_.value -ne ''
  } | ForEach-Object {
    $pref = $_.value
    Write-Host $pref
    # 市町村
    Get-Cities -pref $pref | ForEach-Object {
      $city = $_
      Write-Host ('    {0}' -F $city)
      # 2次メッシュ
      Get-Mesh2DEMs -pref $pref -city $city | ForEach-Object {
        $mesh2DEM = $_.code
        Write-Host ('        {0}' -F $mesh2DEM)
        # 重複2次メッシュ除外
        if (-Not $mesh2DEMList.ContainsKey($mesh2DEM)) {
          # ダウンロードファイルリスト
          $delfile = @()
          Get-Lists -mesh2DEM $mesh2DEM | ForEach-Object {
            $delfile += $_.del
            $DLFile0 = $_.DLFile0
            $DLFile0Size = $_.DLFile0Size
            $selListId = $_.selListId
            Write-Host ('            {0}({1}): {2}' -F ($DLFile0, $DLFile0Size, $selListId))
            # ダウンロード済ファイル除外
            $needDownload = $true
            if ($ziplist.ContainsKey($DLFile0)) {
              if ($ziplist[$DLFile0] -Eq $DLFile0Size) {
                Write-Host '              file exists, skipping...'
                $needDownload = $false
              }
            }
            if ($needDownload) {
              # ファイルダウンロード
              Download-Files -DLFile0 $DLFile0 -selListId $selListId
            }
          }
          # ダウンロードファイルリストのクリア
          Delete-Lists -delfile $delfile
          $mesh2DEMList[$mesh2DEM] = 1
        } else {
          Write-Host ('            {0} duplicated, skipping...' -F $mesh2DEM)
        }
      }
    }
  }
} finally {
  Session-Logout
}

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.