[PYTHON] Fichier PDF de gestion des données de l'état d'émission de ma carte numérique

référence

Installation

apt install ghostscript
pip install camelot-py[cv]
pip install pandas
pip install requests
pip install beautifulsoup4
pip install japanmap
pip install tqdm

programme

BAD Open Data Memorial Process

  1. Créez un fichier CSV à partir d'un PDF
  2. Convertissez la chaîne de caractères en données numériques en supprimant les virgules et%
tables = camelot.read_pdf(
    link, pages="all", split_text=True, strip_text="  ,%%\n", line_scale=40
)

Supprimez les caractères inutiles avec "strip_text =", %% \ n "" lors de l'extraction d'un tableau à partir d'un PDF

import csv
import datetime
import pathlib
import re
from urllib.parse import urljoin

import camelot
import pandas as pd
import requests
from bs4 import BeautifulSoup
from japanmap import pref_code
from tqdm.notebook import tqdm

#Passer du calendrier japonais au calendrier occidental

def wareki2date(s):

    m = re.search("(H|R|Heisei|Reiwa)([0-9 yuans]{1,2})[.Année]([0-9]{1,2})[.Mois]([0-9]{1,2})journée?",s)

    year, month, day = [1 if i == "Ancien" else int(i) for i in m.group(2, 3, 4)]

    if m.group(1) in ["Heisei", "H"]:
        year += 1988
    elif m.group(1) in ["Reiwa", "R"]:
        year += 2018

    return datetime.date(year, month, day)

def df_conv(df, col_name, population_date, delivery_date, criteria_date):

    df.set_axis(col_name, axis=1, inplace=True)

    df["Date de base du calcul de la population"] = population_date
    df["Date de base pour le calcul du nombre de livraisons"] = delivery_date
    df.insert(0, "Date de base du calcul", criteria_date)

    return df

url = "https://www.soumu.go.jp/kojinbango_card/"

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

cjk = str.maketrans("Long noir 戶 long noir long", "Kamecho Kuroto Ryu Nishi Aoki")

df_code = pd.read_csv(
    "https://docs.google.com/spreadsheets/d/e/2PACX-1vSseDxB5f3nS-YQ1NOkuFKZ7rTNfPLHqTKaSag-qaK25EWLcSL0klbFBZm1b6JDKGtHTk6iMUxsXpxt/pub?gid=0&single=true&output=csv",
    dtype={"Code de groupe": int, "Nom des préfectures": str, "Nom du comté": str, "Nom de Ville": str},
)

df_code["Nom de Ville"] = df_code["Nom du comté"].fillna("") + df_code["Nom de Ville"]
df_code.drop("Nom du comté", axis=1, inplace=True)

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

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

links = soup.select("ul.normal > li a[href$=pdf]")

for i in tqdm(links):

    creation_date = wareki2date(i.find_parent("li").get_text(strip=True))
    link = urljoin(url, i.get("href"))

    #Créer le dossier
    path_dir = pathlib.Path(creation_date.strftime("%Y%m%d"))
    path_dir.mkdir(parents=True, exist_ok=True)

    #Extraire le tableau du PDF
    tables = camelot.read_pdf(
        link, pages="all", split_text=True, strip_text="  ,%%\n", line_scale=40
    )

    #Par classification de groupe

    df_tmp = tables[0].df

    df_tmp.iat[0, 1] = "Classification"
    df_tmp.iat[1, 1] = "À l'échelle nationale"

    population_date = wareki2date(df_tmp.iat[0, 2]).strftime("%Y/%m/%d")
    delivery_date = wareki2date(df_tmp.iat[0, 3]).strftime("%Y/%m/%d")

    df0 = df_conv(
        df_tmp.iloc[1:, 1:].reset_index(drop=True),
        ["Classification", "population", "Nombre de livraisons", "populationに対するNombre de livraisons率"],
        population_date,
        delivery_date,
        creation_date.strftime("%Y/%m/%d"),
    )

    df0 = df0.astype({"population": int, "Nombre de livraisons": int, "populationに対するNombre de livraisons率": float})

    df0.to_csv(
        pathlib.Path(path_dir, "summary_by_types.csv"),
        index=False,
        quoting=csv.QUOTE_NONNUMERIC,
        encoding="utf_8_sig",
    )

    #Liste des préfectures

    dfs = []

    for table in tables[3:5]:

        df_tmp = table.df

        population_date = wareki2date(df_tmp.iat[0, 1]).strftime("%Y/%m/%d")

        #Ajustement de la date du statut d'émission de ma carte numérique (au 1er avril 2019)
        if creation_date == datetime.date(2019, 4, 1):
            delivery_date = wareki2date(
                df_tmp.iat[0, 2].replace("H31.41", "H31.4.1")
            ).strftime("%Y/%m/%d")
        else:
            delivery_date = wareki2date(df_tmp.iat[0, 2]).strftime("%Y/%m/%d")

        df = df_conv(
            df_tmp.iloc[1:].reset_index(drop=True),
            ["Nom des préfectures", "Nombre total (population)", "Nombre de livraisons", "人口に対するNombre de livraisons率"],
            population_date,
            delivery_date,
            creation_date.strftime("%Y/%m/%d"),
        )

        dfs.append(df)

    df3 = pd.concat(dfs)

    df3["Nom des préfectures"] = df3["Nom des préfectures"].str.normalize("NFKC")
    df3["Nom des préfectures"] = df3["Nom des préfectures"].apply(lambda s: s.translate(cjk))

    #Trier par numéro de préfecture
    df3.index = df3["Nom des préfectures"].apply(lambda s: pref_code(s))
    df3.sort_index(inplace=True)

    df3 = df3.astype({"Nombre total (population)": int, "Nombre de livraisons": int, "人口に対するNombre de livraisons率": float})

    df3.to_csv(
        pathlib.Path(path_dir, "all_prefectures.csv"),
        index=False,
        quoting=csv.QUOTE_NONNUMERIC,
        encoding="utf_8_sig",
    )

    df3

    #Par sexe et âge

    n = 5

    if creation_date > datetime.date(2017, 3, 8):

        n = 6

        df_tmp = tables[5].df

        population_date = wareki2date(df_tmp.iat[0, 1]).strftime("%Y/%m/%d")
        delivery_date = wareki2date(df_tmp.iat[0, 4]).strftime("%Y/%m/%d")

        df5 = df_conv(
            df_tmp.iloc[2:].reset_index(drop=True),
            [
                "âge",
                "population(Homme)",
                "population(femme)",
                "population(Total)",
                "Nombre de livraisons(Homme)",
                "Nombre de livraisons(femme)",
                "Nombre de livraisons(Total)",
                "Taux de subvention(Homme)",
                "Taux de subvention(femme)",
                "Taux de subvention(Total)",
                "Ratio du nombre de subventions à l'ensemble(Homme)",
                "Ratio du nombre de subventions à l'ensemble(femme)",
                "Ratio du nombre de subventions à l'ensemble(Total)",
            ],
            population_date,
            delivery_date,
            creation_date.strftime("%Y/%m/%d"),
        )

        df5 = df5.astype(
            {
                "population(Homme)": int,
                "population(femme)": int,
                "population(Total)": int,
                "Nombre de livraisons(Homme)": int,
                "Nombre de livraisons(femme)": int,
                "Nombre de livraisons(Total)": int,
                "Taux de subvention(Homme)": float,
                "Taux de subvention(femme)": float,
                "Taux de subvention(Total)": float,
                "Ratio du nombre de subventions à l'ensemble(Homme)": float,
                "Ratio du nombre de subventions à l'ensemble(femme)": float,
                "Ratio du nombre de subventions à l'ensemble(Total)": float,
            }
        )

        df5.to_csv(
            pathlib.Path(path_dir, "demographics.csv"),
            index=False,
            quoting=csv.QUOTE_NONNUMERIC,
            encoding="utf_8_sig",
        )

        df5

    #Liste par ville

    dfs = []

    for table in tables[n:]:

        df_tmp = table.df

        population_date = wareki2date(df_tmp.iat[0, 2]).strftime("%Y/%m/%d")
        delivery_date = wareki2date(df_tmp.iat[0, 3]).strftime("%Y/%m/%d")

        df = df_conv(
            df_tmp.iloc[1:].reset_index(drop=True),
            ["Nom des préfectures", "Nom de Ville", "Nombre total (population)", "Nombre de livraisons", "人口に対するNombre de livraisons率"],
            population_date,
            delivery_date,
            creation_date.strftime("%Y/%m/%d"),
        )

        dfs.append(df)

    df6 = pd.concat(dfs)

    df6["Nom des préfectures"] = df6["Nom des préfectures"].str.normalize("NFKC")
    df6["Nom des préfectures"] = df6["Nom des préfectures"].apply(lambda s: s.translate(cjk))

    #Exclure à l'échelle nationale
    df6 = df6[df6["Nom des préfectures"] != "À l'échelle nationale"].copy()

    df6["Nom de Ville"] = df6["Nom de Ville"].str.normalize("NFKC")
    df6["Nom de Ville"] = df6["Nom de Ville"].apply(lambda s: s.translate(cjk))

    df6["Nom de Ville"] = df6["Nom de Ville"].mask(df6["Nom des préfectures"] + df6["Nom de Ville"] == "Ville de Shinoyama, préfecture de Hyogo", "Ville de Tamba Shinoyama")
    df6["Nom de Ville"] = df6["Nom de Ville"].mask(
        df6["Nom des préfectures"] + df6["Nom de Ville"] == "Ville de Kajiwara, comté de Takaoka, préfecture de Kochi", "Hibara-cho, Takaoka-gun"
    )
    df6["Nom de Ville"] = df6["Nom de Ville"].mask(
        df6["Nom des préfectures"] + df6["Nom de Ville"] == "Ville de Sue, comté de Kasuya, préfecture de Fukuoka", "Sue-cho, Kasuya-gun"
    )

    if creation_date < datetime.date(2018, 10, 1):
        df6["Nom de Ville"] = df6["Nom de Ville"].mask(
            df6["Nom des préfectures"] + df6["Nom de Ville"] == "Ville de Nakagawa, préfecture de Fukuoka", "Nakagawa-cho, Chikushi-gun"
        )
    else:
        df6["Nom de Ville"] = df6["Nom de Ville"].mask(
            df6["Nom des préfectures"] + df6["Nom de Ville"] == "Ville de Nakagawa, comté de Chikushi, préfecture de Fukuoka", "Ville de Nakagawa"
        )

    df6 = pd.merge(df6, df_code, on=["Nom des préfectures", "Nom de Ville"], how="left")

    df6 = df6.astype(
        {"Nombre total (population)": int, "Nombre de livraisons": int, "人口に対するNombre de livraisons率": float, "Code de groupe": "Int64"}
    )

    df6.to_csv(
        pathlib.Path(path_dir, "all_localgovs.csv"),
        index=False,
        quoting=csv.QUOTE_NONNUMERIC,
        encoding="utf_8_sig",
    )

Recommended Posts

Fichier PDF de gestion des données de l'état d'émission de ma carte numérique
Traitement des données du fichier Excel de l'état de l'émission de ma carte numérique (août)
Data wrangling of Excel file of my number card issue status (septembre)
Histoire de l'analyse d'image du fichier PDF et de l'extraction de données