やったこと
MotoHub という中古バイクの検索サイトを個人で作っている。その中に「二輪免許が取れる指定自動車教習所」の一覧ページがあり、都道府県ごとに教習所を並べて、普通自動二輪と大型自動二輪の教習をやっているかを○×で出している。
23県ぶんは公開済みだった。残りの24県、489校を今回そろえた。
調査には Claude(Cowork)を使った。県ごとにサブエージェントを立てて、公式サイト・県警の名簿・県の指定自動車教習所協会の一覧などを読ませ、校名・所在地・公式URL・二輪の可否をCSVに落とす。作業としては速い。24県ぶんの一次データは1日で揃った。
問題はそのあとだった。
最後まで判定が固まらなかった13校を、自分でブラウザを開いて公式サイトを見たら、4校で結論がひっくり返った。
3割である。
この記事は「AIは使えない」という話ではない。集めるのは速くなったが、検証は1ミリも速くならなかったという話で、その検証で何につまずいたかを書く。
なお、公開情報を読んで人間が判断しているだけで、スクレイピングはしていない。
失敗1:○×表を種別ごとに読んではいけない
最初に踏んだのがこれだった。
教習所の情報は「○×のマトリクス」で提供されていることが多い。行が学校名、列が免許の種類、交点に○か×か空欄。人間が目で見るぶんには読める。
ある県の協会サイトのHTMLを読ませたら、大型自動二輪が○なのに普通自動二輪が×という行が出てきた。これは制度上ありえない。大型二輪を教習できる設備と指導員がいて普通二輪をやらない、という教習所は存在しない。
同じページをもう一度読ませたら、違う結果が返ってきた。列がずれていたのである。
その後、同じ症状を各所で確認した。
- 県警がPDFで出している名簿(3県で発生)
- 県協会のHTML表
- 県協会がアイコン画像で○×を表しているページ
- バイク店が出している提携教習所の一覧
いずれも、セルの結合や空セルの扱いで列がずれる。しかもずれ方が毎回同じとは限らないので、突き合わせて検出することもできない。
対策として決めたのはこうだった。
○×マトリクスは母数(その県に指定教習所が何校あるか)を確定するためだけに使う。可否は校ごとに公式サイトで取り直す。
ただし○×表がまったく無駄かというとそうでもなく、「○の個数」だけは復元できることが多かった。ある県では、県警のPDFから「この学校は11種目のうち7つに○がついている」ということだけを取り出し、別サイトが列挙している免許の種類が7つとぴったり一致することを確認して、間接的に確定させた。列の位置は信用できないが、個数は信用できる。
失敗2:テキスト形式でも壊れる
「表がダメならテキストの名簿なら安全か」というと、そうでもなかった。
ある県の協会サイトは、校名・住所・電話番号を素のテキストで並べていた。読ませてCSVにしたところ、35件中8件以上で、住所が隣の学校のものとすり替わっていた。
原因はページ側のマークアップにあった。行の区切りが視覚的にしか表現されておらず、機械的に読むと境界を取り違える。「キドロ豊栄自動車学校」という、実在しない校名が出てきたのが発覚のきっかけだった。地名と校名がつながっていた。
以降、校名・住所・電話のどれか1つでも見慣れない形をしていたら、その名簿全体を疑うようにした。
失敗3:第三者サイトの結論はきれいに割れる
教習所をまとめている第三者サイトはいくつかある。全国規模のものが2つあって、これを突き合わせれば精度が上がるだろうと考えた。
実際には、両方に載っている学校でも大型二輪の有無が食い違うケースが一定数出た。
最後まで残った校のうち、この2サイトが真っ向から割れていたものが4校あった。決着させるために公式サイトを1つずつ開いたところ——正解は両方にばらけた。
サイトAが正しかった校もあれば、サイトBが正しかった校もあり、両方とも間違っていた校もあった。「Aのほうが信頼できる」という結論にはならなかった。
もうひとつ分かったのは、同じサイトでも県によって網羅性がまったく違うことだった。ある県では県内の教習所をほぼ網羅していたのに、隣の県では大型二輪を扱う学校が1件しか登録されていない。使い物にならない。さらに、指定教習所ではない届出教習所が混ざっている県もあった(ある県では、その県の公安委員会が公表している指定校リストに載っていない学校が2件混ざっていた)。
結論として、こういう運用ルールにした。
第三者サイトへの「掲載」は肯定の材料になる。「不掲載」は否定の根拠にならない。
失敗4:「無い」の証明がいちばんあぶない —— 自分のミス
これは私自身がやらかした話である。
宮城県のある教習所について、公式サイトが車種ごとに個別ページを持っているのに大型二輪のページだけ存在しない、という理由で「大型二輪なし」と判定した。他の車種は ordinary-car、large-vehicles、two-wheeled-vehicle といったURLでページがある。大型二輪だけ無い。だから扱っていない、と。
間違いだった。
あとで見つかった。large_size_bike である。他の車種はハイフン区切りなのに、大型二輪だけアンダースコアだった。しかも topics-heavy という大型二輪専用のお知らせページまであった。
「特定のパターンで探して見つからなかった」ことを「存在しない」と読んではいけない、という当たり前の話なのだが、他の車種で規則性が見えていたぶん、疑わなかった。
以降、「個別ページの欠落」を否定の根拠にするときは、命名規則が車種ごとに揺れていないかを必ず確認することにした。ハイフン/アンダースコア/ローマ字/英語の混在を疑う。
失敗5:出典に日付が書いてある
鹿児島県の教習所を数えていたとき、母数を31校と置いていた。根拠にしたのは、進学情報サイトが出している指定校の一覧だった。別の公的なポータルの検索結果とも件数が一致したので、それで確定させた。
あとから、そのページの隅に小さくこう書いてあるのに気づいた。
※2017年2月現在の情報です
2020年末に閉校して別の教習所に統合された学校が、そのまま残っていた。**しかも私のCSVには、閉校した旧校と統合先の新校が両方入っていた。**同じ教習所を2回数えていたことになる。
一覧サイトの「現在」がいつなのかは、たいてい目立たないところに書いてある。母数の根拠に使うなら、そこを見る。
結局どうしたか
判定ルールを1枚に決めて、それに合わないものは公開しないことにした。
DBの verified_at カラムが NULL の行は、絶対に画面に出さない。取り込みはできるが、人間が確認するまで非公開のままになる。これが最後の砦になった。
verified_at を入れてよい条件は次のどれか。
- 公式サイトの本文・ページタイトル・PDFで確認できた
- 公的機関(県警・公安委員会・自治体)の資料で確認できた
- 県協会の車種入り名簿(テキスト形式で車種が明記されているもの)で確認できた
- 独立した第三者2件以上が、住所または電話番号の一致で同一校と確認でき、かつ車種の記載も一致した
第三者1件だけ、あるいは出典が割れている場合は空欄のまま。「たぶんこうだろう」を入れる余地をなくすのが目的だった。
取り込み自体も、(都道府県, 校名) をキーにした upsert にして、全削除→再投入は禁止にした。CSVを1本流すたびに全消しされる設計だと、途中で壊れたCSVを流し込んだときに気づけない。
数字
最終的にこう動いた。
| 時点 | 総数 | 非公開 |
|---|---|---|
| 一次データができた直後 | 488 | 86 |
| 出典を追加で当たった後 | 490 | 25 |
| 閉校の重複を除去 | 489 | 13 |
| 公式サイトで最終確認 | 489 | 0 |
86校からスタートして、公開できる状態まで持っていくのに、それなりの日数がかかった。AIが1日で集めたデータを、人間が検証するのに数日かかった。
そして最後の13校を確認する段階でも、4校で判定がひっくり返っている。
まとめ
作業を通して残った実感は3つ。
AIは調査を速くするが、検証は速くしない。 むしろ、集まる量が増えるぶん検証の総量は増える。速くなったぶんを検証に回す前提で計画したほうがいい。
「無い」の判定がいちばん危ない。 「あった」は1つ証拠を見つければ終わるが、「なかった」は探し方が正しかったことまで証明しないといけない。私が唯一やらかしたのもここだった。
未確認のまま出さない仕組みが要る。 判断を保留したデータが、いつのまにか確定データとして画面に出ていくのがいちばん怖い。verified_at が NULL なら出さない、という1行のルールがあるだけで、ずいぶん気が楽になった。
47都道府県、1058校ぶんのデータは MotoHub の教習所一覧で公開している。もし間違いを見つけたら教えてください。たぶん、まだある。