経緯
このようなTweetがTLに流れてきました。 元記事にも指摘があるとおり、PDFファイルが3000ページを超えていました。 さすがにユーザビリティに問題があると考えたのか、9月中に地図上に掲載予定とのことです。国のキャッシュレスポイント還元PRサイト、「使えるお店一覧」から18万店を網羅した3608ページのPDFに飛ばす #SmartNews https://t.co/2dkv221ddi
— ある2ー (@rdy3e24) September 2, 2019
ただ、PDFの状態にどうしても我慢できない人はおり、下記TweetのようにPythonスクリプトでテキストデータに加工した人もいました。
私も同じようにテキストデータに加工したいと考えた口です。 そこで、PDFからテキストデータをシェルスクリプトだけで抽出した手順を示します。なんかムラムラしてきたので、一次データをtsvにするコードを書いてみた
— しーちょー🚲 (@c_tyo) September 2, 2019
なぜかしらんが緯度経度付与して、空間検索インデックスにぶち込みたい(#^ω^)https://t.co/YI05uNX9lJ
- 検証環境 … Ubuntu 18.04 LTS
PDFファイルからテキストデータを抽出する
テキストデータの抽出自体はUnix系OSであれば下記CLIコマンドで実施可能です。
# infile.pdf … 加工対象のPDFファイル
# outfile.txt … 抽出したテキストデータの保存先
pdftotext -layout infile.pdf target.txt
読みやすく使いやすい形に加工する
抽出されたテキストデータを確認すると、以下のような形式です。
No. 都道府県 市区町村 事業所名(屋号) 業種 還元率
1 北海道 愛別町 セブン-イレブン愛別町店 小売業 食料品 2%
2 北海道 愛別町 伊藤新聞販売所 小売業 その他小売 5%
3 北海道 愛別町 三愛自動車工業株式会社 その他業種 ー 5%
4 北海道 赤平市 赤平 SS 小売業 ガソリンスタンド 2%
5 北海道 赤平市 赤平平岸SS 小売業 ガソリンスタンド 2%
6 北海道 赤平市 セブン-イレブン赤平文京町店 小売業 食料品 2%
7 北海道 赤平市 セブン-イレブン赤平茂尻店 小売業 食料品 2%
8 北海道 赤平市 出光茂尻SS 小売業 ガソリンスタンド 2%
9 北海道 赤平市 海鮮居食屋暖らん サービス 飲食業 5%
10 北海道 赤平市 株式会社菱友 赤平支店 小売業 その他小売 5%
11 北海道 赤平市 セルフ幌岡SS 小売業 ガソリンスタンド 2%
12 北海道 赤平市 デンキの桐原 小売業 電化製品 5%
これを以下のシェルスクリプト(totsv.sh)を作成してタブ区切りのデータに整形します。
#!/bin/sh
cat "$1" |
awk 'BEGIN{ # 必要な範囲のテキストデータのみを取得
target = 0 # 出力フラグ
}
{
if($0 ~ /固定店舗(EC・通信販売を除く).*令和元年8月21日 現在/){ # 固定店舗を対象とするため、フラグを有効化
target = 1
}
if($0 ~ /EC・通信販売(楽天市場)/){# 通販のリストは除外するため、フラグを無効化
target = 0
}
if(target == 1){ # 有効な区間の文字列を出力
print $0
}
}' > tmp_result
cat tmp_result |
sed 's/.*キャッシュレス・消費者還元事業.*事務局審査を通過した加盟店一覧.*//' | # 不要な文字列を削除
sed 's/.*固定店舗(EC・通信販売を除く).*//' | # 不要な文字列を削除
sed 's/^ *[0-9]* *$//' | # ページ番号を削除
sed 's/.*※9月中に地図上に掲載予定.*//' | # 不要な文字列を削除
sed 's/.*都道府県.*//' | # 不要な文字列を削除
grep -v '^ *$' | # 不要な空行を削除
awk 'BEGIN{ # 項目ごとに整形
OFS="\t"
}
{
industry1 = $(NF - 2) # 業種1列目
industry2 = $(NF - 1) # 業種2列目
rate = $NF # 還元率
name = "" # 店舗名
for(i = 4; i <= NF - 3; i++){ # 店舗名を半角スペースで結合
if(i == 4){name = $i; continue}
name = name " " $i
}
print $1, $2, $3, name, industry1, industry2, rate # タブ区切りで出力
}'
シェルスクリプトの実行
以下のコマンドでresult.tsv
というファイルに出力されます。
# target.txtを引数としてシェルスクリプトを実行し、`result.tsv`として保存
$ totsv.sh target.txt > result.tsv
シェルスクリプトの解説
シェルスクリプトは大きく2つのブロックに分かれます。
1つはテキストデータから必要なデータの範囲のみ抽出する上半分のブロックと、抽出したデータを整形する下半分のブロックです。
必要なデータの抽出
まず必要なデータ範囲ですが、今回は固定店舗のみを対象とします。
元のPDFファイルを見ると表のあるページ先頭には必ず見出しがあります。
この見出しをキーとしてそのページが必要かどうかを判定します。
この判定はawk
コマンドのみで実施しました。
出力結果は確認のためにあえてtmp_result
ファイルに出力しています。
整形処理前半:不要な文字列の削除
tmp_result
ファイルを見て確認した状態をもとに整形処理を作成しました。
整形処理の前半ではsed
とgrep
コマンドで不要な文字列を一掃します。
整形処理後半:タブ区切りに整える
Excel等の表計算ソフトや文字列処理でも扱いやすいことから、タブ区切りに整形しました。
これはawk
コマンドのみで済ませました。
処理した結果
result.tsv
ファイルの中身はそのままスプレッドシートやExcelにコピー&ペーストやインポートが可能な形式になっています。
grepコマンドなどで住所を指定して検索すれば、特定の住所の事業者一覧を作ることができますし、これを元データとしてWeb APIや検索サービスとして提供することも難しくないでしょう。
# 検索の例
$ grep "東京都\s*目黒区" result.tsv
ちなみに上記検索条件では687件表示されました。
このPDFの住所は市区町村までしか記載がないため、これ以上詳しい住所では検索できず、地図へのプロットも大雑把すぎるため断念しました。
先ほど記したように公式では9月中に地図上に掲載予定とのことですが、今回私が作成したものより使いやすいとうれしいですね。