メモ:国土数値情報のウェブページから各データの説明のURLをrvestとstringrで抜き出す

国土数値情報APIはzipファイルのURLを返してくれるんですけど、それがどういうデータかは教えてくれません。

library(dplyr, warn.conflicts = FALSE)
library(kokudosuuchi)
#> このサービスは、「国土交通省 国土数値情報(カテゴリ名)」をもとに加工者が作成
#> 以下の国土数値情報ダウンロードサービスの利用約款をご確認の上ご利用ください:
#> 
#> http://nlftp.mlit.go.jp/ksj/other/yakkan.html

# prefCodeが3で、年が2000-2010の河川のデータ
d <- getKSJURL("W05", prefCode = 3, fiscalyear = 2000:2010)
glimpse(d)
#> Observations: 1
#> Variables: 9
#> $ identifier  <chr> "W05"
#> $ title       <chr> "河川"
#> $ field       <chr> "国土(水・土地)"
#> $ year        <chr> "2007"
#> $ areaType    <chr> "3"
#> $ areaCode    <chr> "3"
#> $ datum       <chr> "1"
#> $ zipFileUrl  <chr> "http://nlftp.mlit.go.jp/ksj/gml/data/W05/W05-07/W...
#> $ zipFileSize <chr> "10.42MB"

どういうデータか書いてあるページには、国土数値情報のウェブページから飛べます。

国土数値情報ダウンロードサービス

とりあえずリンクを全部抜き出してみるとこんな感じ。

library(rvest)
library(dplyr, warn.conflicts = FALSE)

page <- read_html("http://nlftp.mlit.go.jp/ksj/index.html")

a_nodes <- page %>%
  html_nodes(css = "td > a")

d <- tibble::tibble(url  = html_attr(a_nodes, "href"),
                    name = html_text(a_nodes))

d
#> # A tibble: 113 x 2
#>                                         url                          name
#>                                       <chr>                         <chr>
#>  1 http://nlftp.mlit.go.jp/ksj-e/index.html                       ENGLISH
#>  2                       api/about_api.html                       Web API
#>  3                               index.html GML(JPGIS2.1)シェープファイル
#>  4                jpgis/jpgis_datalist.html                 XML(JPGIS1.0)
#>  5                        gmlold/index.html GML(JPGIS2.1)シェープファイル
#>  6                    old/old_datalist.html                      テキスト
#>  7           gml/datalist/KsjTmplt-C23.html                        海岸線
#>  8           gml/datalist/KsjTmplt-P23.html                  海岸保全施設
#>  9      gml/datalist/KsjTmplt-W09-v2_2.html                          湖沼
#> 10           gml/datalist/KsjTmplt-W07.html                  流域メッシュ
#> # ... with 103 more rows

この、gml/datalist/KsjTmplt-C23.htmlとかgml/datalist/KsjTmplt-P23.htmlとかが、それぞれC23P23のデータの説明ページになっています。これは、

gml/datalist/KsjTmplt-識別子.html

というフォーマットになっていると思いきや、gml/datalist/KsjTmplt-W09-v2_2.htmlのようにトリッキーなものもあって一筋縄ではいきません。

library(stringr)

str_extract(d$url, "KsjTmplt-.*\\.html") %>%
  purrr::discard(is.na) %>%
  head(20)
#>  [1] "KsjTmplt-C23.html"      "KsjTmplt-P23.html"      "KsjTmplt-W09-v2_2.html"
#>  [4] "KsjTmplt-W07.html"      "KsjTmplt-W01.html"      "KsjTmplt-W05.html"     
#>  [7] "KsjTmplt-G04-a.html"    "KsjTmplt-G04-c.html"    "KsjTmplt-G04-d.html"   
#> [10] "KsjTmplt-G08-v1_0.html" "KsjTmplt-L03-a.html"    "KsjTmplt-L03-b.html"   
#> [13] "KsjTmplt-L03-b-u.html"  "KsjTmplt-A13.html"      "KsjTmplt-A12.html"     
#> [16] "KsjTmplt-A09.html"      "KsjTmplt-A29.html"      "KsjTmplt-L01-v2_3.html"
#> [19] "KsjTmplt-L02-v2_3.html" "KsjTmplt-N03-v2_3.html"

とりあえずコードっぽい部分だけを抜き出しましょう。これにはlook aheads/behindsを使います(参考:正規表現の先読み・後読みを極める! - あらびき日記

str_extract(d$url, "(?<=KsjTmplt-).*(?=\\.html)") %>%
  purrr::discard(is.na) %>%
  head(20)
#>  [1] "C23"      "P23"      "W09-v2_2" "W07"      "W01"      "W05"     
#>  [7] "G04-a"    "G04-c"    "G04-d"    "G08-v1_0" "L03-a"    "L03-b"   
#> [13] "L03-b-u"  "A13"      "A12"      "A09"      "A29"      "L01-v2_3"
#> [19] "L02-v2_3" "N03-v2_3"

よさそうです。次に、-v2_3みたいな部分を取りましょう。これは後ろに(-v\\d_\\d+)?を入れるだけでOK、だと思ったんですが…

str_extract(d$url, "(?<=KsjTmplt-).*(?=(-v\\d_\\d+)?\\.html)") %>%
  purrr::discard(is.na) %>%
  head(20)
#>  [1] "C23"      "P23"      "W09-v2_2" "W07"      "W01"      "W05"     
#>  [7] "G04-a"    "G04-c"    "G04-d"    "G08-v1_0" "L03-a"    "L03-b"   
#> [13] "L03-b-u"  "A13"      "A12"      "A09"      "A29"      "L01-v2_3"
#> [19] "L02-v2_3" "N03-v2_3"

変わりません。これは、.*がgreedy matchなので-v2_3までマッチしてしまうからです。ということで正解は、.*?にすることです(そもそも.*じゃなくてもうちょっと絞り込んだ表現にするというのもあり)。

str_extract(d$url, "(?<=KsjTmplt-).*?(?=(-v\\d_\\d+)?\\.html)") %>%
  purrr::discard(is.na) %>%
  head(20)
#>  [1] "C23"     "P23"     "W09"     "W07"     "W01"     "W05"     "G04-a"  
#>  [8] "G04-c"   "G04-d"   "G08"     "L03-a"   "L03-b"   "L03-b-u" "A13"    
#> [15] "A12"     "A09"     "A29"     "L01"     "L02"     "N03"  

こんな感じ。

KSJCodeDescriptionURL <- d %>%
  mutate(code = str_extract(url, "(?<=KsjTmplt-).*?(?=(-v\\d+_\\d+)?\\.html)"),
         url  = glue::glue('http://nlftp.mlit.go.jp/ksj/{url}')) %>%
  filter(!is.na(code)) %>%
  arrange(code)

glimpse(KSJCodeDescriptionURL)
#> Observations: 105
#> Variables: 3
#> $ url  <S3: glue> "http://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-A03.ht...
#> $ name <chr> "三大都市圏計画区域", "都市地域", "自然公園地域", "自然保全地域", "農業地域", "森林地域", "鳥獣保護...
#> $ code <chr> "A03", "A09", "A10", "A11", "A12", "A13", "A15", "A16", "A17",...