Cloudflare から「月間 10,000 PV を突破しました」というメールが届きました。国別の内訳は米国 8,594 に対して日本 142。1 つの IP が全体の 58% を占めていて、その数がサイトの収録校数とほぼ一致していました。bot を除いた実訪問者は 24 時間で 12 人です。スクレイプは止められないので、開き直って公式にデータセットと名乗ることにしました。そこで「公開する 1 件ごとに出典 URL を必ず添える」というルールを 1 本入れたら、データの充足率が 67% しかないことが分かった、という話です。
記事全体の要約です。左が 24 時間のアクセスの正体、右が「公式に配る」と決めてから見つかったデータ品質の穴です。
自分で作っている高校選びのサービス manabi-map の話です。アクセスの正体を割るときに User-Agent は見ていません。偽装が 1 行で済むものは判定材料にならないからです。代わりに使ったのは、割り当て(RDAP)と逆引き(PTR)という、詐称にコストがかかる 2 つでした。大手クローラーは逆引きの名前を正引きし直して元の IP に戻るかで検証できるようになっているので、裏返すと PTR を持たない IP はどの大手クローラーでもないと言い切れます。
止められないと分かってからの判断が本題です。データは CC BY-SA 4.0 なので、公式に配布物として宣言すれば再利用する側に帰属表示の義務が発生します。黙って抜かれ続けるより、出典付きで引用される方がいい。そう決めて「公開する各レコードは出典元の URL を必ず同梱する」という条件を置いたところ、出典が確認できない学校が 3 分の 1 あると判明しました。原因は 3 週間前の自分で、データ投入をブロックごとに手書きしていたせいで、後半のブロックほど項目が静かに落ちていました。
24 時間ぶんのリクエストを分解したものです。9.23k のうち、実際の人に紐づくのは 200 前後でした。
ブロックが進むほど項目が脱落していきます。しかも項目ごとに崩れ始める時期が違い、列リストが手書きだったことを裏づけていました。
取りこぼしの正体は地理ではなく所管でした。県立高校しか載っていないカタログを何回舐めても、市立高校は 1 校も増えません。
生成側は「載せてよいものだけ載せる」、検証側は「載ってはいけないものが載っていたら落とす」で向きが逆です。片方だけだと、実装を書き換えたときに静かに緩みます。
充足率は 67% から 99.8% まで戻り、公開 API は本番で動いています。全都道府県が /api/v1/schools.json、県別が /api/v1/schools/{prefecture}.json で、説明ページは manabi-map.app/data/ です。1 レコードごとに出典 URL が同梱されているので、受け取った側がその 1 件だけを見て元の資料まで辿れます。CC BY-SA 4.0 なので、帰属表示さえしてもらえれば自由に使えます。
一番刺さったのは「文章で書いた防御は守られない」でした。手順書には「公立と私立の両方を押さえる」と書いてあり、設計メモには「1 県でも全欠落したら停止する」と書いてありました。どちらも守られていませんでした。読む人が読む前提で書かれた防御は、実行時に飛ばされます。機械で落ちる形にして初めて防御になります。