ベルマーク教育助成財団の週別ベルマーク受付状況のPDFから都道府県別・市区町村別に集計する

# はじめに

[ベルマーク教育助成財団](https://www.bellmark.or.jp/)の[週別ベルマーク受付状況](https://www.bellmark.or.jp/collect/accept.htm)のPDFから都道府県別・市区町村別に集計しました

現在は[ウェブベルマーク](https://www.webbellmark.jp/)というのも始まっていてウェブベルマークサイトからお好きなショップにアクセスお買い物に応じてベルマークポイントがたまります

[利用可能ショップ](https://www.webbellmark.jp/#kyosan-company)

![ウェブベルマーク.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36151/c08266f2-420c-3e6c-b012-79bb96757d51.png)

じゃらんや楽天トラベルなども利用可能なのでGo To トラベルを申し込む前にご利用するだけで、自己負担なく支援できます。

※要事前登録

# 説明

こちらの処理はX座標、Y座標のlimitの範囲にあるのもを多い座標の位置に集約しています
文字数が多く2段になっているものや、多少ずれているところを調整しています

```python
def snap_adjustment(s, limit=5):

    count = s.value_counts().sort_index()

    index = 0
    value = 0

    for i, v in count.items():

        if (i - index) < limit:

            if v > value:
                s = s.replace(index, i)
                index = i
                value = v

            else:
                s = s.replace(i, index)

        else:
            index = i
            value = v

    return s
```

# プログラム

```python
import pathlib
import time

import pandas as pd
import pdfplumber
import requests
from bs4 import BeautifulSoup


def fetch_file(url, dir="."):

    r = requests.get(url)
    r.raise_for_status()

    p = pathlib.Path(dir, pathlib.PurePath(url).name)
    p.parent.mkdir(parents=True, exist_ok=True)

    with p.open(mode="wb") as fw:
        fw.write(r.content)
    return p


def snap_adjustment(s, limit=5):

    count = s.value_counts().sort_index()

    index = 0
    value = 0

    for i, v in count.items():

        if (i - index) < limit:

            if v > value:
                s = s.replace(index, i)
                index = i
                value = v

            else:
                s = s.replace(i, index)

        else:
            index = i
            value = v

    return s


url = "https://www.bellmark.or.jp/collect/accept.htm"

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"
}

r = requests.get(url, headers=headers)
r.raise_for_status()

soup = BeautifulSoup(r.content, "html.parser")

links = {
    href.get("href")
    for href in soup.select("div.cal-process > div.cal-row-date > div > a")
}

dfs = []

for link in links:

    p = fetch_file(link)

    with pdfplumber.open(p) as pdf:

        for page in pdf.pages:

            crop = page.within_bbox((0, 65, page.width, page.height - 40))

            df_tmp = (
                pd.DataFrame(crop.extract_words(keep_blank_chars=True))
                .astype({"x0": float, "x1": float, "top": float, "bottom": float})
                .sort_values(["top", "x0"])
            )

            df_tmp["top"] = snap_adjustment(df_tmp["top"], 6)
            df_tmp["x0"] = snap_adjustment(df_tmp["x0"])

            table = (
                df_tmp.pivot_table(
                    index=["top"],
                    columns="x0",
                    values="text",
                    aggfunc=lambda x: "".join(str(v) for v in x),
                )
            ).values

            df = pd.DataFrame(table, columns=["都道府県", "市", "区町村", "参加団体", "受付日"])
            dfs.append(df)

            time.sleep(3)

df = pd.concat(dfs)

df

df["市区町村"] = df["市"].fillna("") + df["区町村"].fillna("")

df1 = df.reindex(columns=["都道府県", "市区町村", "参加団体", "受付日"])

df1.to_csv("data.csv")

df1
```

# 都道府県別

```python
import japanize_matplotlib
import matplotlib as mpl
import matplotlib.pyplot as plt

mpl.rcParams["figure.dpi"] = 200

df1["都道府県"].value_counts(ascending=True).plot.barh(figsize=(5, 10))
# グラフを保存
plt.savefig("01.png", dpi=200, bbox_inches="tight")
plt.show()
```
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36151/846b3eca-b435-9e5e-a1da-c505bc56658b.png)

# 市区町村別

```python
s = df1.groupby(["都道府県", "市区町村"])["市区町村"].count().sort_values(ascending=True)

s.tail(50).plot.barh(figsize=(5, 10))

# グラフを保存
plt.savefig("02.png", dpi=200, bbox_inches="tight")
plt.show()
```

![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/36151/d89a09c8-ca0e-3392-684b-9dc14e4a78c5.png)