A toolkit for finding and retrieving geospatial data that survives only in WARP, the National Diet Library of Japan's web archive. It handles WARP's undocumented access path (collection-ID resolution, raw-byte retrieval, viewer-HTML detection) and records provenance for every file. Japanese docs below.
配布元のサイトが消え、Wayback Machine にも残っていない地理空間データが、 国立国会図書館の WARP(インターネット資料収集保存事業)にだけ現存していることがある。 それを見つけて、正しく取り出して、来歴を付けて保管するための道具。
汎用アーカイブクローラではない。 WARP に特化し、地理空間データを掘ることに特化している。
きっかけは mlit-groundwater-well-registry で、
国土交通省の地下水データベース2003年版(座標付きの深井戸 57,847点)を掘り出した作業だった。
配布元の tochi.mlit.go.jp は消滅し、Wayback にも地域別 zip は無く、
WARP が2009年に収集したものだけが現存していた。あの作業を汎用化したのがこれ。
WARP から生データを取るのは、URLに id_ を挟むだけでは済まない。
$ curl -o /dev/null -w '%{http_code}\n' \
'https://warp.ndl.go.jp/web/20090217012940id_/http://tochi.mlit.go.jp/.../kantou.zip'
500生データを返すのは /{コレクションID}/{ts}id_/{原URL} だけで、そのコレクションIDは
TimeMap にも API にも出てこない(閲覧用HTMLの iframe から抜くしかない)。
id_ を付け忘れると、zip を要求したのに閲覧用HTMLが 200 で返ってきて、
気づかず保存すると後段で原因不明の展開エラーになる。
こうした落とし穴を全部畳み込んであるのがこの道具。
仕様そのものは docs/warp-api-notes.md にまとめてあるので、
別の言語で実装したい人はそちらだけ読めばよい。
$ pip install git+https://github.com/shiwaku/ndl-warp-geospatial-data-fetcher.gitPython 3.11 以上。依存は httpx のみ。
発見・取得・素性判定に加え、GeoJSON への変換まで標準ライブラリだけで動く。
GDAL も geopandas も要らない。FlatGeobuf / GeoParquet と、
日本測地系からの実際の座標変換にだけ [convert] を足す。
$ pip install 'git+https://github.com/shiwaku/ndl-warp-geospatial-data-fetcher.git#egg=warpgeo[convert]'自分が探しているデータを掘りたい人は
docs/guide.mdを読んでください。 探す・収集回を選ぶ・絞る・素性を確かめる、の判断基準を段階ごとに書いた手順書です。 以下はコマンドの早見表です。
段階実行が基本。search と discover は候補を出すだけで取得はしない。
# 1. 配布ページを探す(全文検索)
$ warpgeo search "地下水 データベース ダウンロード" --limit 20
# 2. 収集日時を確認する
$ warpgeo timemap http://tochi.mlit.go.jp/tockok/tochimizu/F9/data/kantou.zip
収集回: 14
20041111072814 2004-11-11 07:28:14 UTC
20090217012940 2009-02-17 01:29:40 UTC
...
# 2b. どの収集回が充実しているかを、落とさずに測って比べる
$ warpgeo timemap http://tochi.mlit.go.jp/tockok/tochimizu/F9/data/kantou.zip --sizes
# 3. 配布ページを辿って候補を集める
$ warpgeo discover http://tochi.mlit.go.jp/tockok/tochimizu/F9/download.html \
--depth 0 -o work/manifest.jsonl
# 4. 欲しいものだけ、狙った収集回で取る(--dry-run で先に確認できる)
$ warpgeo fetch --manifest work/manifest.jsonl \
--exclude '[0-9]*' --at 20090217012940 --output out/
# 5. 中身を開いて素性を確かめる(WARP には繋がない)
$ warpgeo identify
# 6. 現代の形式に変換する
$ warpgeo convert --to geojson -o out/docs/recipes/ に置いてある手順をなぞると、先行事例と同じものが手に入る。
$ warpgeo discover http://tochi.mlit.go.jp/tockok/tochimizu/F9/download.html --depth 0
[1] zip http://tochi.mlit.go.jp/tockok/tochimizu/F9/data/kantou.zip
«関東»
...
巡回 1 ページ / 失敗 0 / 候補 55 件(収集日時 20041111072814)
$ warpgeo fetch --manifest work/manifest.jsonl --exclude '[0-9]*' --at 20090217012940
--include/--exclude で除外: 47 件
取得 kantou.zip 859,109 bytes [zip] @20090217012940
...
成功 8 / 失敗 0
コレクションID解決の節約: 7 リクエスト--exclude で都道府県別(01.zip〜47.zip)を落とし、--at で
一覧ページとは別の収集回を指定している。一覧ページを辿る収集回と、
実体を取る収集回は別に選ぶ必要があり、これがこの道具で一番の勘所。
8本を展開すると合計 57,847 点。先行事例の記載値と一致する。
取得したバイト列を開いて中身を確かめる。ここが単なるダウンローダとの差。
$ warpgeo identify
kantou.zip
関東 [Shapefile] Point 11,361 件 cp932
範囲 138.42186,33.10002 - 140.84361,37.10863
測地系 JGD2000(変換済みフラグ列)/ EPSG:4612 / 測地系変換 不要
⚠ S_TKY2JGD が示すとおり測地系変換は済んでいる。**二重変換の禁止** —
日本測地系とみなして再変換すると北483m・西334mずれる。
座標品質 一意 4,936 / 同一地点 1,189 / 代表点の疑い 5,236(46.1%)
注意 PH: 数値列の 77.2% が 0。空欄が 0 で埋められていれば真の 0 と区別できない
註 prj が無い(座標系の宣言が原本に無い)やっていること。
- 展開 — zip / lzh / gzip / tar / 自己解凍 exe を再帰的に開く。
zip 内のファイル名が cp932 のまま入っていれば復元する(
関東.shpが読めるようになる) - 形式判定 — 拡張子ではなく中身で決める。
.shpと.dbfと.shxは 1つのデータセットとしてまとめる - 文字コード判定 — cp932 / euc-jp / utf-8。
.cpgがあれば推定より宣言を優先する - 測地系判定 —
.prj、srsName、そして変換済みフラグ列(S_TKY2JGD等)を見る。 根拠が無ければ「不明」と記録し、変換を下流に禁じる - 座標品質 — 同一座標に別の地名が積まれている行を「代表点の疑い」として数える
- 列の欠陥 — 空欄が 0 で埋められた数値列、数値列への非数値の混入。 直さず、印を付けて残す
日本の経緯度データは、日本測地系(Tokyo)でも JGD2000 でも同じレンジに収まる。
座標値からは区別できない。 だから根拠が無ければ may_convert: false として、
下流が自動変換しないようにする。
先行事例では、変換済みのデータを未変換とみなして再変換した結果、 北483m・西334mの系統ズレが出た。判らないものを判ったことにしないのが、 この層で一番大事な仕事になっている。
判定結果は来歴付きで work/identify.jsonl に残る。
.lzh の展開だけは標準ライブラリでできないので、
pip install lhafile か lha/7z があれば使う(無ければ理由を添えて失敗として記録する)。
$ warpgeo convert --to geojson -o out/
kantou.zip
out/関東.geojson 11,361 地物 EPSG:4612 →(座標は変換なし) EPSG:4326
根拠 JGD2000(変換済みフラグ列)
註 S_TKY2JGD が示すとおり測地系変換は済んでいる。**二重変換の禁止** — …
註 補助列 _position_quality は本ツールの導出であり原本には無い(代表点の疑い 46.1%)
註 属性は原本のまま文字列で出している(数値化していない)判らないものは変換しない。
$ warpgeo convert wells.zip -o out/
断った wells: «wells» の測地系は「不明」。…
根拠があるなら --assume-crs EPSG:4301(日本測地系)のように明示すること
$ echo $?
1測地系変換をしてよいかは identify の判定が決め、変換層はそれを覆せません。
覆せるのは --assume-crs を明示したときだけで、そのときは
「利用者の指定による」と成果物に記録されます。
断ったデータセットは標準エラーに必ず出るので、
「出力に無い=元々無かった」と読み違えることがありません。
そのほかの約束。
- 原本の欠陥は直さない。 属性は dbf に入っていた文字列のまま出す。
0.00を数値の 0 に直すと、空欄由来の 0 と真の 0 が永久に区別できなくなる。 数値にしたい場合は--numericを明示して選ぶ - 来歴は成果物に埋め込む。 GeoJSON なら
warpgeoメンバとして本体に、 FlatGeobuf / GeoParquet なら併置する.provenance.jsonに - 導出した値には印を付ける。 座標の質は
_position_quality(unique/site/fallback)という補助列になる。原本の列とは接頭辞で区別できる
GeoJSON への変換は依存なしで動く。
FlatGeobuf・GeoParquet と、日本測地系からの実際の座標変換だけは
pip install 'warpgeo[convert]' が要る(無ければ理由を添えて断る)。
JGD2000 と WGS84 の差は実用上無視できるため、この間は座標を触らず宣言し直すだけにしてある。
同じURLでも収集回によって中身は違う。配布開始直後でまだ一部しか置かれていない回、 サイト閉鎖の直前でファイルが消えている回、実体が揃っている回が混ざる。 TimeMap は日時しか返さないので、日時からは判らない。
$ warpgeo timemap http://example.go.jp/data/kantou.zip --sizes
収集回: 14(うち 5 回を実測)
20041111072814 2004-11-11 12,043 bytes
最大の回の半分未満(中身が欠けている可能性)
20090217012940 2009-02-17 859,109 bytes ★ 推奨
...
20110302012512 2011-03-02 4,210 bytes
データではなくHTMLが返る(収集時点でファイルが無かった見込み)生データURLへの HEAD が Content-Length を返すので、本文を落とさずに比べられる
(docs/warp-api-notes.md §2.5)。
Content-Type が HTML なら、その回にはファイルが無かったと分かる。
自動選択はしない。 サイズは代用の指標にすぎず、中身が正しいかは identify でしか
判らない。道具は測って並べ、薦めるところまでにとどめる。
実測した回がすべて同じ大きさなら、そう言う(更新されていないファイルでは普通に起きる)。
1つの回を測るのに2リクエスト(閲覧用HTML + HEAD)かかる。既定は5回。
WARP には Wayback の CDX API に相当するものが無く、 「このディレクトリ配下のURL全部」は原理的に引けない。だから経路を使い分ける。
| 経路 | 使いどころ | 限界 |
|---|---|---|
timemap |
URLが分かっている | URLが分からないと使えない |
discover |
配布ページが分かっている | 起点が要る |
search |
何も分からない | 本文テキストしか索引されていない。zip や shp は出てこず、配布ページが出る |
search でデータファイルを直接探そうとしても出てこない。
配布ページを見つけて discover に渡す、というのが本筋。
取得物には必ず来歴が付く(work/index.jsonl)。
原URL・収集日時・コレクションIDの3点が揃っていれば、第三者が同じものを再取得できる。
{
"original_url": "http://tochi.mlit.go.jp/tockok/tochimizu/F9/data/kantou.zip",
"timestamp": "20090217012940",
"memento_datetime": "2009-02-17T01:29:40+00:00",
"warp_collection_id": "20090319",
"warp_raw_url": "https://warp.ndl.go.jp/20090319/20090217012940id_/http://...",
"sha256": "...", "size": 859109, "sniffed_format": "zip"
}warpgeo formats で一覧できる。2000年代前半の日本の官公庁サイトが相手なので、
現代のGIS形式だけでなく .lzh、自己解凍 .exe、.sima(SIMA)、.sfc(SXF)、
.dm(数値地図)、.mif(MapInfo)なども候補として拾う。
形式の知識は warpgeo/formats.py の1つの表に集約されている。
新しい形式への対応は、そこに1行足すだけで発見と素性判定の両方に効く。
この道具は WARP に負荷をかけないことを最優先に作られている。
- WARP は「大規模・継続的なリクエストはIPブロックの対象」と案内している。 継続的に利用する場合は WARP に事前に連絡すること。 → https://warp.ndl.go.jp/info/WARP_help.html
- 既定のアクセス間隔は 1リクエスト2秒・直列。並列取得はオプションとしても実装していない。
- User-Agent は既定でこのリポジトリのURLを名乗る。WARP 側から誰が叩いているか分かるようにするため。
- 取得済みのバイトは内容アドレスで保管し、再実行しても取り直さない。
- WARP の
robots.txtは一般のUAに対し/search/web//20/collections/を Disallow している。 本ツールは低レート・件数限定の調査利用を想定しており、網羅的なクロールに使うものではない。 この点を理解したうえで使うこと。
LICENSE の MIT ライセンスは本ソフトウェア(道具)にのみ適用される。
本ソフトウェアを用いて WARP から取得したコンテンツの著作権は、
元のコンテンツの権利者に帰属する。利用条件は取得物ごとに利用者が確認すること。
このリポジトリが含む WARP 由来のデータは、
tests/data/groundwater2003/ のテストデータだけ(4.6MB)。
国立国会図書館 WARP を通じて取得した国土交通省の資料であり、MIT ライセンスの対象外。
ネットワークに繋がずに実データで回帰テストを回すために置いている。
出典・収集日時・利用上の注意は
同ディレクトリの README に明記してある。
成果物としてデータを公開する場合は、 先行事例のように データ案件ごとに別リポジトリを立て、そこで権利関係と品質の但し書きを個別に書くことを勧める。 道具のリポジトリにデータを溜めるものではない。
| 文書 | 読むとき |
|---|---|
docs/guide.md |
自分が探しているデータを掘りたいとき(手順書) |
docs/recipes/ |
最後まで通した実例を見たいとき |
docs/warp-api-notes.md |
WARP の仕組みを知りたい・別の言語で実装したいとき |
DESIGN.md |
なぜこの設計なのか、未解決の課題は何か |
| 層 | 内容 | 状態 |
|---|---|---|
| Layer 1 | discover(TimeMap / クロール / 全文検索) | 実装済み |
| Layer 2 | fetch(コレクションID解決・生バイト取得・来歴) | 実装済み |
| Layer 3 | identify(展開・文字コード・CRS・座標品質) | 実装済み |
| Layer 4 | convert(GeoJSON / FlatGeobuf / GeoParquet) | 実装済み |
設計の全体像は DESIGN.md。
$ pip install -e '.[dev]'
$ pytest # オフラインテストのみ(WARP を叩かない)
$ pytest -m live # WARP への疎通確認。手動でだけ実行する
$ ruff check .CI は WARP にアクセスしない。記録済み応答(tests/fixtures/)と、
実際に取得したシェープファイル(tests/data/groundwater2003/)で回している。
テストデータを WARP から取り直したいときは:
$ python tests/data/groundwater2003/fetch.py --verify # 手元の sha256 を突合するだけ
$ python tests/data/groundwater2003/fetch.py # WARP から取り直す