[PYTHON] Daten-Wrangling-PDF-Datei mit dem Status meiner Kartenausstellung

Referenz

Installation

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

Programm

BAD Open Data Memorial-Prozess

  1. Erstellen Sie eine CSV-Datei aus PDF
  2. Konvertieren Sie die Zeichenfolge in numerische Daten, indem Sie Kommas und% entfernen
tables = camelot.read_pdf(
    link, pages="all", split_text=True, strip_text="  ,%%\n", line_scale=40
)

Löschen Sie unnötige Zeichen mit "strip_text =", %% \ n "", wenn Sie eine Tabelle aus PDF extrahieren

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

#Konvertieren Sie vom japanischen zum westlichen Kalender

def wareki2date(s):

    m = re.search("(H|R|Heisei|Reiwa)([0-9 Yuan]{1,2})[.Jahr]([0-9]{1,2})[.Mond]([0-9]{1,2})Tag?",s)

    year, month, day = [1 if i == "Ehemalige" 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["Basisdatum der Bevölkerungsberechnung"] = population_date
    df["Basisdatum für die Berechnung der Anzahl der Lieferungen"] = delivery_date
    df.insert(0, "Basisdatum der Berechnung", 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("Lang schwarz 戶 lang schwarz lang", "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={"Gruppencode": int, "Name der Präfekturen": str, "Name des Landkreises": str, "Stadtname": str},
)

df_code["Stadtname"] = df_code["Name des Landkreises"].fillna("") + df_code["Stadtname"]
df_code.drop("Name des Landkreises", 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"))

    #Ordner erstellen
    path_dir = pathlib.Path(creation_date.strftime("%Y%m%d"))
    path_dir.mkdir(parents=True, exist_ok=True)

    #Tabelle aus PDF extrahieren
    tables = camelot.read_pdf(
        link, pages="all", split_text=True, strip_text="  ,%%\n", line_scale=40
    )

    #Nach Gruppenklassifikation

    df_tmp = tables[0].df

    df_tmp.iat[0, 1] = "Einstufung"
    df_tmp.iat[1, 1] = "Bundesweit"

    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),
        ["Einstufung", "Population", "Anzahl der Lieferungen", "Populationに対するAnzahl der Lieferungen率"],
        population_date,
        delivery_date,
        creation_date.strftime("%Y/%m/%d"),
    )

    df0 = df0.astype({"Population": int, "Anzahl der Lieferungen": int, "Populationに対するAnzahl der Lieferungen率": float})

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

    #Liste der Präfekturen

    dfs = []

    for table in tables[3:5]:

        df_tmp = table.df

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

        #Datumsanpassung meines Ausstellungsstatus für Nummernkarten (Stand: 1. April 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),
            ["Name der Präfekturen", "Gesamtzahl (Bevölkerung)", "Anzahl der Lieferungen", "人口に対するAnzahl der Lieferungen率"],
            population_date,
            delivery_date,
            creation_date.strftime("%Y/%m/%d"),
        )

        dfs.append(df)

    df3 = pd.concat(dfs)

    df3["Name der Präfekturen"] = df3["Name der Präfekturen"].str.normalize("NFKC")
    df3["Name der Präfekturen"] = df3["Name der Präfekturen"].apply(lambda s: s.translate(cjk))

    #Sortieren nach Präfekturnummer
    df3.index = df3["Name der Präfekturen"].apply(lambda s: pref_code(s))
    df3.sort_index(inplace=True)

    df3 = df3.astype({"Gesamtzahl (Bevölkerung)": int, "Anzahl der Lieferungen": int, "人口に対するAnzahl der Lieferungen率": float})

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

    df3

    #Nach Geschlecht und Alter

    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),
            [
                "Alter",
                "Population(Mann)",
                "Population(Frau)",
                "Population(Gesamt)",
                "Anzahl der Lieferungen(Mann)",
                "Anzahl der Lieferungen(Frau)",
                "Anzahl der Lieferungen(Gesamt)",
                "Zuschussrate(Mann)",
                "Zuschussrate(Frau)",
                "Zuschussrate(Gesamt)",
                "Verhältnis der Anzahl der Zuschüsse zum Ganzen(Mann)",
                "Verhältnis der Anzahl der Zuschüsse zum Ganzen(Frau)",
                "Verhältnis der Anzahl der Zuschüsse zum Ganzen(Gesamt)",
            ],
            population_date,
            delivery_date,
            creation_date.strftime("%Y/%m/%d"),
        )

        df5 = df5.astype(
            {
                "Population(Mann)": int,
                "Population(Frau)": int,
                "Population(Gesamt)": int,
                "Anzahl der Lieferungen(Mann)": int,
                "Anzahl der Lieferungen(Frau)": int,
                "Anzahl der Lieferungen(Gesamt)": int,
                "Zuschussrate(Mann)": float,
                "Zuschussrate(Frau)": float,
                "Zuschussrate(Gesamt)": float,
                "Verhältnis der Anzahl der Zuschüsse zum Ganzen(Mann)": float,
                "Verhältnis der Anzahl der Zuschüsse zum Ganzen(Frau)": float,
                "Verhältnis der Anzahl der Zuschüsse zum Ganzen(Gesamt)": float,
            }
        )

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

        df5

    #Liste nach Stadt

    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),
            ["Name der Präfekturen", "Stadtname", "Gesamtzahl (Bevölkerung)", "Anzahl der Lieferungen", "人口に対するAnzahl der Lieferungen率"],
            population_date,
            delivery_date,
            creation_date.strftime("%Y/%m/%d"),
        )

        dfs.append(df)

    df6 = pd.concat(dfs)

    df6["Name der Präfekturen"] = df6["Name der Präfekturen"].str.normalize("NFKC")
    df6["Name der Präfekturen"] = df6["Name der Präfekturen"].apply(lambda s: s.translate(cjk))

    #Bundesweit ausschließen
    df6 = df6[df6["Name der Präfekturen"] != "Bundesweit"].copy()

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

    df6["Stadtname"] = df6["Stadtname"].mask(df6["Name der Präfekturen"] + df6["Stadtname"] == "Shinoyama City, Präfektur Hyogo", "Tamba Shinoyama Stadt")
    df6["Stadtname"] = df6["Stadtname"].mask(
        df6["Name der Präfekturen"] + df6["Stadtname"] == "Stadt Kajiwara, Landkreis Takaoka, Präfektur Kochi", "Hibara-cho, Takaoka-gun"
    )
    df6["Stadtname"] = df6["Stadtname"].mask(
        df6["Name der Präfekturen"] + df6["Stadtname"] == "Sue Town, Kasuya County, Präfektur Fukuoka", "Sue-cho, Kasuya-gun"
    )

    if creation_date < datetime.date(2018, 10, 1):
        df6["Stadtname"] = df6["Stadtname"].mask(
            df6["Name der Präfekturen"] + df6["Stadtname"] == "Stadt Nakagawa, Präfektur Fukuoka", "Nakagawa-cho, Chikushi-Pistole"
        )
    else:
        df6["Stadtname"] = df6["Stadtname"].mask(
            df6["Name der Präfekturen"] + df6["Stadtname"] == "Stadt Nakagawa, Landkreis Chikushi, Präfektur Fukuoka", "Nakagawa City"
        )

    df6 = pd.merge(df6, df_code, on=["Name der Präfekturen", "Stadtname"], how="left")

    df6 = df6.astype(
        {"Gesamtzahl (Bevölkerung)": int, "Anzahl der Lieferungen": int, "人口に対するAnzahl der Lieferungen率": float, "Gruppencode": "Int64"}
    )

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

Recommended Posts

Daten-Wrangling-PDF-Datei mit dem Status meiner Kartenausstellung
Daten-Wrangling der Excel-Datei mit dem Status meiner Kartenausstellung (August)
Daten-Wrangling der Excel-Datei mit dem Status meiner Kartenausstellung (September)
Geschichte der Bildanalyse von PDF-Dateien und Datenextraktion