🥲

古物商番号検索サイトを個人開発で作ろうとして妥協した何かができました

2024/04/27に公開

はじめに

以下が成果物です。

https://kobutsu.pages.dev/

画面

背景

ネットで古物営業法に規定される「古物」を売買または交換する個人・法人は基本12桁の古物商番号を取得し、掲載している場合があります。
ただし以下の問題点があると思います。

  1. 掲載されている古物商番号が正しいかは調べてみないとわからない
  2. 掲載場所は集約されておらず、各都道府県単位で掲載されている
  3. 掲載方法はPDFやHPで統一されていない
  4. DFやHPというフォーマットの特性上、プログラムでの取得が困難
  5. 番号で直接Google検索してインデックスに引っかかる場合もあるがない場合もあり

1~5の体験を少しでも改善したいと思い、簡単に作ってみました。

使い方

北海道公安委員会に掲載されている適当な番号を「101280000141」で検索してみます。

はい、3つ出てきました。

なぜなぜ

「おい、12桁で検索しているのに、北海道で特定できないのは何事だ💢」

と思われるかもしれません。結論をいうと頓挫しました。

開発当初は、すべての古物商番号をデータベースに格納して12桁で特定できるようにする最強サイトを作るwwwwwwwwwwwwと息巻いてました。
47パターンあるけど、RubyやPythonで何かしらのライブラリで解析すればまあ落とし込むのは簡単だ。。そんなふうに考えていた時期が俺にもありました

PDFをパースできるライブラリはあるのですが、以下の方が書いているように茨の道です。
https://qiita.com/mima_ita/items/d99afc28b6f51479f850

以下は東京都の掲載サイトですが、1行目のように1行でお行儀よく値が入っていると良いのですが、長いurlで改行されているパターンもあり、そこのキャッチをする必要があります。
https://www.kouaniinkai.metro.tokyo.jp/kobutsu/keisai.pdf

以下が東京パターンで、なんとかしようとしたRubyプログラムの残骸です。
前にかいたものなので正常に動くかわからないので辛い雰囲気だけ掴んでいただければと思います。

require 'pdf-reader'

pdf_path = 'tokyo.pdf'
reader = PDF::Reader.new(pdf_path)

def build_data(number, name, url)
    <<~TEMPLATE
        INSERT INTO antique_dealers (permission_number, publish_name, [url], prefecture, info_updated_on)
        VALUES (#{number}, '#{name.gsub(/\s/, '').gsub("'", "\\'")}', '#{url.gsub(/\s/, '')}', '東京都', '2024-01-10');
    TEMPLATE
end


result = ""
reader.pages.each do |page|
    split_text = page.text.split("\n")

    insert_permission_number = ""
    insert_name = ""
    insert_url = ""
    split_text.each_with_index do |line, i|
        next if line.empty?

        matched_permission_number = line.match(/3\d{11}/).to_s.to_i
        if matched_permission_number == 0
            if i == split_text.length - 1
                # 最終行にdateが含まれるのでそれよりも前の要素を追加して終了
                result << build_data(insert_permission_number, insert_name, insert_url)
                break
            end

            # マッチがなければ改行されたurlパターンであるので追加する
            insert_url << line
            next
        end

        if insert_permission_number != "" && insert_name != "" && insert_url != ""
            result << build_data(insert_permission_number, insert_name, insert_url)
        end

        insert_permission_number = matched_permission_number
        # 名前を抽出、名前を空白分割すると名前も分割されてしまうので不可
        insert_name = line.match(/(?<=\d{11}\s).+(?=\s)/).to_s

        # 残ったものがURL
        insert_url = line.gsub("#{insert_permission_number} #{insert_name} ", "")

        # 最後の行であればインサートを行う
        if i == split_text.length - 1
            result << build_data(insert_permission_number, insert_name, insert_url)
        end
    end
end

File.open("insert_queries.sql", "w") do |file|
    file.puts result
end

更に、上記3.でも書いたように、都道府県によってPDFやHP掲載があるので、47パターンのPDF解析やスクレイピングコードを書くことを考えると頓挫しました。
色々試みた結果は以下にも書いてます。
https://zenn.dev/shibata/articles/cec22020b12e48

これがcsvなら。。csvでなくとも統一の形式なら、、と思ってしまいます。
デジタル庁さんなんとかして。。

結論

都道府県によって、ある程度先頭番号に規則性があったので、目視で共通箇所を抜き出してテーブルに格納しました。
なので、「3010521xxxxx」と調べたときに、3010301のプレフィックスを持つ都道府県にヒットするようにしました。
これがフルで番号検索しているのに、数種類の都道府県が出る理由です。
あとは指定の都道府県のサイトを見に行って、サイト内検索でgrepしてください!

技術スタックを簡単に紹介すると、HonoとCloudFlare周りの技術スタックを使ってます。
個人開発では簡単に構築できるのでおすすめです。

もっといいやり方がぜひコメントで教えて下さい!読んでいただきありがとうございました。

Discussion