[Python] Récupérez le texte de la loi à partir de l'API e-GOV law

Nous avons résumé comment obtenir et formater les données de droit japonais à partir de e-Gov Law API. Je me réfère à l'article Qiita suivant.

Chaque code de cet article, y compris les classes mentionnées dans le "Résumé" final, peut être téléchargé à partir du référentiel GitHub.

1. Déclencheur

Je voulais utiliser l'ordonnance ministérielle (J-GCP, ordonnance ministérielle sur les normes de conduite des essais cliniques de produits pharmaceutiques) que je confirme souvent au travail comme sujet d'étude du traitement du langage naturel. Je crains que le montant soit faible par rapport au texte publié sur Twitter, mais j'ai pensé que ce serait utile comme sujet pour le traitement du langage naturel car il y a peu de fluctuations de notation.

2. Environnement

Utilisez requests (nécessite l'installation de pip) pour accéder à l'API et au package xml (bibliothèque standard) pour analyser les données XML. functools.lru_cache réduit le nombre d'accès à l'API (cache de sortie des fonctions), pprint affiche les dictionnaires et les listes proprement, et re supprime les chaînes inutiles (par expression régulière). Utilisé pour (supprimer la chaîne de caractères).

#Bibliothèque standard
from functools import lru_cache
from pprint import pprint
import re
from xml.etree import ElementTree
# pip install requests
import requests
Environnement d'exécution
OS Windows Subsystem for Linux / Ubuntu
Gestion des paquets pipenv
Language Python 3.8.5
requests 2.24.0

3. Acquisition du numéro de loi

Outre le nom de la loi, il semble qu'un identifiant unique appelé «numéro de loi» soit défini. Le numéro n'est pas un simple numéro de série, mais une chaîne de caractères japonais ...

Le numéro de loi (Horeibangou) est un numéro attribué individuellement pour l'identification aux différentes lois et réglementations promulguées par les gouvernements nationaux et locaux. Les numéros sont initialisés (à partir du n ° 1) à intervalles réguliers (année civile, etc.), les numéros de série à partir d'une date précise (anniversaire d'indépendance, etc.), etc. Les méthodes de gestion et d'exploitation sont différentes. "Numéro de loi" Source: Encyclopédie gratuite "Wikipedia"

Vérifiez comment rechercher le numéro de loi par nom, car il est spécifié à l'aide du numéro de loi lors de l'acquisition du texte de loi.

Dictionnaire des numéros de loi

Tout d'abord, créez une fonction pour obtenir la relation entre le nom de la loi et le numéro de la loi sous forme de dictionnaire.

law_number.py


@lru_cache
def get_law_dict(category=1):
    #Obtenez une liste des lois et réglementations incluses dans chaque type de loi à partir de l'API
    url = f"https://elaws.e-gov.go.jp/api/1/lawlists/{category}"
    r = requests.get(url)
    #Analyse des données XML
    root = ElementTree.fromstring(r.content.decode(encoding="utf-8"))
    #dictionnaire{Nom:Numéro de loi}Création
    names = [e.text for e in root.iter() if e.tag == "LawName"]
    numbers = [e.text for e in root.iter() if e.tag == "LawNo"]
    return {name: num for (name, num) in zip(names, numbers)}

Il existe quatre types de lois (arguments «catégorie»).

―― 1: Toutes les lois et réglementations ―― 2: Constitution, loi ―― 3: Ordonnance du gouvernement, décret ―― 4: Ordonnance ministérielle

Exemple de sortie:

pprint(get_law_dict(category=2), compact=True)
# ->
{
    "Meiji 22 Loi n ° 34 (Lutte contre le crime Affaire Niseki Suru)": "Loi Meiji 22 n ° 34",
    "Règles de dépôt": "Loi Meiji 23 n ° 1",
    "Loi sur le contrôle de l'imitation des devises et des valeurs mobilières": "Loi Meiji 28 n ° 28",
    "Méthode de rejet des achats de titres d'obligations d'État": "Loi Meiji 29 n ° 5",
    "Droit civil": "Meiji 29 Loi n ° 89",
...
    "Agir sur les exceptions extraordinaires des lois fiscales nationales pour faire face aux effets des nouvelles infections à coronavirus, etc.": "Loi n ° 25 de la 2e année Reiwa",
    "Loi relative à l'interdiction de la saisie des prestations spéciales à montant fixe, etc.": "Loi n ° 27 de la 2e année Reiwa",
    "Loi sur les mesures spéciales concernant la promotion des travaux de prévention des catastrophes, etc.": "Loi n ° 56 de 2e année Reiwa"
}

Root.iter () de "Créer un dictionnaire {nom: numéro de loi}" divise les données XML en unités d'élément et les renvoie sous forme d'itération. Il peut être exécuté en le remplaçant par root.getiterator (), mais il semble que DeprecationWarning se produise comme suit.

DeprecationWarning: This method will be removed in future versions.
Use 'tree.iter()' or 'list(tree.iter())' instead.

De plus, les balises «.text» et «.tag» sont définies pour chaque élément.

--Lorsque .tag ==" LawName ": .text indique le nom de la loi --Lorsque .tag ==" LawNo ": .text indique le numéro de loi

Image de l'élément


elements = [
    f"{e.tag=}, {e.text=}" for e in root.iter()
    if e.tag in set(["LawName", "LawNo"])
]
pprint(elements[:4], compact=False)
# ->
["e.tag='LawName', e.text='Ordre approximatif du budget des recettes et dépenses'",
 "e.tag='LawNo', e.text='Ordonnance n ° 12 du Cabinet Meiji 22'",
 "e.tag='LawName', e.text='Règles de calcul des dépenses planifiées'",
 "e.tag='LawNo', e.text='Ordonnance n ° 19 du Cabinet Meiji 22'"]

En utilisant cela, j'ai créé un dictionnaire de noms et de numéros de loi dans la partie suivante.

get_law_dict()


names = [e.text for e in root.iter() if e.tag == "LawName"]
numbers = [e.text for e in root.iter() if e.tag == "LawNo"]
return {name: num for (name, num) in zip(names, numbers)}

Recherche par mot-clé pour les noms

Je pense qu'il est rare de se souvenir du nom officiel de la loi, je vais donc permettre une recherche par mot-clé.

law_number.py


def get_law_number(keyword, category=1):
    """
    Return the law number.
    This will be retrieved from e-Gov (https://www.e-gov.go.jp/)

    Args:
        keyword (str): keyword of the law name
        category (int): category number, like 1 (all), 2 (Loi), 3 (Ordonnance), 4 (Ordonnance ministérielle)

    Returns:
        dict(str, str): dictionary of law name (key) and law number (value)
    """
    law_dict = get_law_dict(category=category)
    return {k: v for (k, v) in law_dict.items() if keyword in k}

Exemple de sortie:

Acquisition du numéro de loi


print(get_law_number("Essais cliniques de produits pharmaceutiques", category=4))
# ->
{
    'Ordonnance ministérielle sur les normes relatives à la conduite des essais cliniques de médicaments': 'Ordonnance n ° 28 du Ministère de la santé et du bien-être de 1997',
    'Ordonnance ministérielle sur les normes relatives à la conduite d'essais cliniques de médicaments vétérinaires': '1997 Ordonnance n ° 75 du Ministère de l'agriculture, des forêts et des pêches'
}

Le numéro de loi de la cible J-GCP (Ordonnance du Ministère sur les Normes pour la Conduite des Essais Cliniques de Produits Pharmaceutiques) s'est avéré être "Ordonnance n ° 28 du Ministère de la Santé et du Bien-être de 1997".

4. Acquisition du texte juridique

Envoyez le numéro de loi à l'API et récupérez le texte. Analysez le XML pour obtenir le corps et supprimez les espaces et les lignes vides supplémentaires.

law_contents.py


@lru_cache
def get_raw(number):
    """
    Retrieve contents of the law specified with law number from e-Gov API.

    Args:
        number (str): Number of the law, like 'Ordonnance n ° 28 du Ministère de la santé et du bien-être de 1997'

    Returns:
        raw (list[str]): raw contents of J-GCP
    """
    url = f"https://elaws.e-gov.go.jp/api/1/lawdata/{number}"
    r = requests.get(url)
    root = ElementTree.fromstring(r.content.decode(encoding="utf-8"))
    contents = [e.text.strip() for e in root.iter() if e.text]
    return [t for t in contents if t]

Exemple de sortie:

gcp_raw = get_raw("Ordonnance n ° 28 du Ministère de la santé et du bien-être de 1997")
pprint(gcp_raw, compact=False)
# ->
[
    "0",
    "Ordonnance n ° 28 du Ministère de la santé et du bien-être de 1997",
...
    "table des matières",
...
    "Chapitre 1 Règles générales",
    "(Effet)",
    "Premier article",
    "Cette ordonnance ministérielle vise à protéger les droits de l'homme des sujets, à maintenir leur sécurité et à améliorer leur bien-être, ainsi que la qualité scientifique des essais cliniques et
Loi relative à la garantie de la qualité, de l'efficacité et de la sécurité des produits pharmaceutiques, des dispositifs médicaux, etc. afin de garantir la fiabilité des résultats
(Ci-après dénommée la "loi") Article 14, paragraphe 3 (applicable mutatis mutandis à l'article 14, paragraphe 9 et à l'article 19-2, paragraphe 5 de la loi)
Y compris l'étui. même que ci-dessous. ) Et l'article 14-4, paragraphe 4 et l'article 14-6, paragraphe 4 de la loi (ces dispositions
Y compris les cas où il est appliqué mutatis mutandis conformément à l'article 19-4 de la loi. même que ci-dessous. ) Des normes spécifiées par l'Ordonnance du Ministère de la Santé, du Travail et du Bien-être
Prescrit à l'article 80-2, paragraphes 1, 4 et 5 de la loi ainsi que ceux relatifs à la mise en œuvre d'essais cliniques de produits pharmaceutiques.
Les normes spécifiées par l'ordonnance du ministère de la Santé, du Travail et du Bien-être seront établies.",
    "(Définition)",
    "Article 2",
...
    "Dispositions complémentaires",
    "(Date effective)",
    "Premier article",
    "Cette ordonnance ministérielle entrera en vigueur le 1er avril 1991."
]

5. Formatage du texte

Extrait et joint uniquement les lignes qui se terminent par un signe de ponctuation. En outre, supprimez les chaînes de caractères entre parenthèses (exemple: "Loi sur les affaires pharmaceutiques ** (loi n ° 145 de 1955) **") et "". En outre, dans le cas de J-GCP, l'article 56 est supprimé car il concerne principalement le remplacement de mots et je ne souhaite pas l'utiliser pour l'analyse.

law_contents.py


def preprocess_gcp(raw):
    """
    Perform pre-processing on raw contents of J-GCP.

    Args:
        raw (list[str]): raw contents of J-GCP

    Returns:
        str: pre-processed string of J-GCP

    Notes:
        - Article 56 will be removed.
        - Strings enclosed with ( and ) will be removed.
        - 「 and 」 will be removed.
    """
    # contents = raw[:]
    # Remove article 56
    contents = raw[: raw.index("Article 56")]
    # Select sentenses
    contents = [s for s in contents if s.endswith("。")]
    # Join the sentenses
    gcp = "".join(contents)
    # 「 and 」 will be removed
    gcp = gcp.translate(str.maketrans({"「": "", "」": ""}))
    # Strings enclosed with ( and ) will be removed
    return re.sub("([^(|^)]*)", "", gcp)

Exemple de sortie:

J-Mise en forme GCP


gcp = preprocess_gcp(gcp_raw)
# ->
"L'article 14, paragraphe 3, l'article 14-4, paragraphe 4, et l'article 14-5, paragraphe 4, de la loi sur les affaires pharmaceutiques,
Sur la base des dispositions de l'article 80-2, paragraphes 1, 4 et 5, et de l'article 82
L'ordonnance ministérielle sur les critères de conduite des essais cliniques de médicaments est établie comme suit.
Cette ordonnance ministérielle vise à protéger les droits de l'homme des sujets, à maintenir leur sécurité et à améliorer leur bien-être.
Assurer la qualité scientifique des essais cliniques et la fiabilité des résultats, la qualité des produits pharmaceutiques, des dispositifs médicaux, etc.
Loi garantissant l'efficacité et la sécurité, etc....(Omis)
Un consentement écrit doit être obtenu pour participer à l'étude."

Pour la partie à supprimer à l'article 56, remplacez-la par contents = raw [:] etc. dans le cas d'autres lois et règlements.

6. Résumé

Je l'ai mis ensemble dans une classe.

law_all.py


class LawLoader(object):
    """
    Prepare law data with e-Gov (https://www.e-gov.go.jp/) site.

    Args:
        category (int): category number, like 1 (all), 2 (Loi), 3 (Ordonnance), 4 (Ordonnance ministérielle)
    """

    def __init__(self, category=1):
        self.law_dict = self._get_law_dict(category=category)
        self.content_dict = {}

    @staticmethod
    def _get_xml(url):
        """
        Get XML data from e-Gov API.

        Args:
            url (str): key of the API

        Returns:
            xml.ElementTree: element tree of the XML data
        """
        r = requests.get(url)
        return ElementTree.fromstring(r.content.decode(encoding="utf-8"))

    def _get_law_dict(self, category):
        """
        Return dictionary of law names and numbers.

        Args:
            category (int): category number, like 1 (all), 2 (Loi), 3 (Ordonnance), 4 (Ordonnance ministérielle)

        Returns:
            dict(str, str): dictionary of law names (keys) and numbers (values)
        """
        url = f"https://elaws.e-gov.go.jp/api/1/lawlists/{category}"
        root = self._get_xml(url)
        names = [e.text for e in root.iter() if e.tag == "LawName"]
        numbers = [e.text for e in root.iter() if e.tag == "LawNo"]
        return {name: num for (name, num) in zip(names, numbers)}

    def get_law_number(self, keyword, category=1):
        """
        Return the law number.
        This will be retrieved from e-Gov (https://www.e-gov.go.jp/)

        Args:
            keyword (str): keyword of the law name
            category (int): category number, like 1 (all), 2 (Loi), 3 (Ordonnance), 4 (Ordonnance ministérielle)

        Returns:
            dict(str, str): dictionary of law name (key) and law number (value)
        """
        return {k: v for (k, v) in self.law_dict.items() if keyword in k}

    def get_raw(self, number):
        """
        Args:
            number (str): Number of the law, like 'Ordonnance n ° 28 du Ministère de la santé et du bien-être de 1997'

        Returns:
            raw (list[str]): raw contents of J-GCP
        """
        if number in self.content_dict:
            return self.content_dict[number]
        url = f"https://elaws.e-gov.go.jp/api/1/lawdata/{number}"
        root = self._get_xml(url)
        contents = [e.text.strip() for e in root.iter() if e.text]
        raw = [t for t in contents if t]
        self.content_dict = {number: raw}
        return raw

    @staticmethod
    def pre_process(raw):
        """
        Perform pre-processing on raw contents.

        Args:
            raw (list[str]): raw contents

        Returns:
            str: pre-processed string

        Notes:
            - Strings enclosed with ( and ) will be removed.
            - 「 and 」 will be removed.
        """
        contents = [s for s in raw if s.endswith("。")]
        string = "".join(contents)
        string = string.translate(str.maketrans({"「": "", "」": ""}))
        return re.sub("([^(|^)]*)", "", string)

    def gcp(self):
        """
        Perform pre-processing on raw contents of J-GCP.

        Args:
            raw (list[str]): raw contents of J-GCP

        Returns:
            str: pre-processed string of J-GCP

        Notes:
            - Article 56 will be removed.
            - Strings enclosed with ( and ) will be removed.
            - 「 and 」 will be removed.
        """
        number_dict = self.get_law_number("Essais cliniques de produits pharmaceutiques")
        number = number_dict["Ordonnance ministérielle sur les normes relatives à la conduite des essais cliniques de médicaments"]
        raw = self.get_raw(number)
        raw_without56 = raw[: raw.index("Article 56")]
        return self.pre_process(raw_without56)

Comment utiliser:

Comment utiliser LawLoader


# The Constitution of Japan
loader2 = LawLoader(category=2)
consti_number = loader2.get_law_number("La Constitution du Japon")
print(consti_number) # -> 'Constitution de Showa 21'
consti_raw = loader2.get_raw("Constitution de Showa 21")
consti = loader2.pre_process(consti_raw)
# J-GCP: enregistré en tant que méthode incluant le formatage des données
loader4 = LawLoader(category=4)
gcp = loader4.gcp()

7. Post-scriptum

En tant que sujet de traitement du langage naturel, j'ai téléchargé et façonné les lois et réglementations japonaises.

Je vous remercie pour votre travail acharné!

Recommended Posts

[Python] Récupérez le texte de la loi à partir de l'API e-GOV law
Récupérer le contenu de git diff depuis python
Récupérer le code retour d'un script Python depuis bat
Existence du point de vue de Python
Utilisez l'API Flickr de Python
python Obtenez la météo à venir de l'API météo
Obtenez votre fréquence cardiaque à partir de l'API fitbit en Python!
Notes d'apprentissage depuis le début de Python 1
Comment obtenir des abonnés et des abonnés de Python à l'aide de l'API Mastodon
Obtenez les débats parlementaires via l'API
[Python] Obtenir la date de mise à jour d'un article d'actualité à partir de HTML
[Python] Récupère le code de caractère du fichier
Notes d'apprentissage depuis le début de Python 2
[Python] Obtenez la couleur principale de la capture d'écran
Récupérez uniquement le texte du formulaire Django.
J'ai essayé d'obtenir le code d'authentification de l'API Qiita avec Python.
Obtenez des visites d'articles et des likes avec l'API Qiita + Python
J'ai essayé d'obtenir les informations sur le film de l'API TMDb avec Python
[Python] Obtenir / modifier l'étiquette d'échelle de la figure
[Python] Obtenez les principaux sujets de Yahoo News
Récupérer l'appelant d'une fonction en Python
[Python] Obtenez la dernière date de mise à jour du site Web
[Python] Get the day (anglais et japonais)
Essayez d'accéder à l'API YQL directement depuis Python 3
Obtenez la date de mise à jour du fichier de mémorandum Python.
le zen de Python
Le mur lors du passage du service Django de Python 2.7 à la série Python 3
Python: texte japonais: caractéristique du discours à partir de la similitude des mots
Traduire de Visual Studio 2017 vers Python (API Microsoft Translator Text)
Comment obtenir le nombre de chiffres en Python
Apprenez Nim avec Python (dès le début de l'année).
[Python] Obtenez le chemin d'accès officiel du fichier de raccourci (.lnk)
[python] Récupère la liste des classes définies dans le module
Étude depuis le début de Python Hour1: Hello World
Obtenir le calendrier de l'API Garoon SOAP avec Python + Zeep
Points Python du point de vue d'un programmeur en langage C
Obtenir la taille (nombre d'éléments) de Union Find en Python
Utilisons la version Python du module API Confluence.
[Python] Obtenir la liste des noms ExifTags de la bibliothèque Pillow
Python: texte japonais: caractéristique de la parole à partir de la continuité des mots
Étude de Python Hour8: Utilisation de packages
Obtenez l'état de fonctionnement de JR West avec Python
[Python] Obtenez le nombre de vues de tous les articles publiés
Obtenez l'URL de la destination de la redirection HTTP en Python
[Python] Utilisez l'API Face de Microsoft Cognitive Services
Vers la retraite de Python2
Obtenez le nombre de chiffres
[Python] Récupérez le mois précédent
Appelez l'API avec python3.
À propos des fonctionnalités de Python
Utilisez l'API e-Stat de Python
Le pouvoir des pandas: Python
Essayez d'obtenir la liste des fonctions du paquet Python> os
Différent du type d'importation de python. Signification de depuis A import B
Obtenez le nombre d'éléments spécifiques dans la liste python
Touchons l'API de Netatmo Weather Station avec Python. #Python #Netatmo
Obtenez la valeur tout en spécifiant la valeur par défaut de dict en Python
[Python] Extrayez des données texte à partir de données XML de 10 Go ou plus.