Knock 100 language processing publié sur la page Web du laboratoire Inui-Okazaki de l'Université de Tohoku pour la formation au traitement du langage naturel et Python. Je vais contester nlp100 /). Je prévois de prendre note du code implémenté et des techniques à supprimer. Le code sera également publié sur GitHub.
Grâce à sauter pendant un moment, j'ai fini par écrire un article en lisant le code que j'avais écrit auparavant. Un style de «je suis une autre personne il y a trois jours» sur le terrain. Pendant ce temps, mon niveau de compétence a considérablement changé et je regardais mon code tout en me parlant. Il y a un écart entre les mises à jour, mais j'espère que vous pourrez l'utiliser comme une pierre d'une autre montagne.
Il existe un fichier jawiki-country.json.gz qui exporte les articles Wikipedia dans le format suivant.
Une information d'article par ligne est stockée au format JSON Dans chaque ligne, le nom de l'article est stocké dans la clé "title" et le corps de l'article est stocké dans l'objet dictionnaire avec la clé "text", et cet objet est écrit au format JSON. Le fichier entier est gzippé Créez un programme qui effectue le traitement suivant.
Lisez le fichier JSON de l'article Wikipedia et affichez le texte de l'article sur "UK". Dans les problèmes 21-29, exécutez sur le texte de l'article extrait ici.
20.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 20.py
import json
with open("jawiki-country.json") as f:
article_json = f.readline()
while article_json:
article_dict = json.loads(article_json)
if article_dict["title"] == u"Angleterre":
print(article_dict["text"])
article_json = f.readline()
Le jawiki-country.json.gz utilisé cette fois est de 9,9 Mo, ce qui est assez lourd, donc j'ai lu ligne par ligne avec readline ()
et seul l'article "UK" est print
(les autres articles sont terminés).
Je sens que l'opération s'arrêtera pendant un certain temps si je fais readlines ()
, et s'il y a un plus large éventail d'utilisations, je n'opérerai que pour les articles en "UK", donc je l'ai implémenté comme ça.
Dans ces données texte, chaque ligne du fichier est décrite au format JSON. Cependant, la simple lecture de (json.load ()
) ne fonctionne pas bien et l'avantage de JSON ne peut pas être utilisé, j'ai donc utilisé json.loads ()
pour le convertir au format JSON (cette fois, c'est un vrai dictionnaire). Je vais.
À partir de là, le travail d'extraction des seuls articles de "UK" se poursuivra pendant un certain temps, je l'ai donc modulaire comme suit.
extract_from_json.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# extract_from_json.py
import json
def extract_from_json(title):
with open("jawiki-country.json") as f:
json_data = f.readline()
while json_data:
article_dict = json.loads(json_data)
if article_dict["title"] == title:
return article_dict["text"]
else:
json_data = f.readline()
return ""
Contrairement à «20.py», cette fonction renvoie la chaîne de caractères de l'article lorsque le titre est passé en argument (chaîne de caractères vide si elle n'existe pas).
Extrayez la ligne qui déclare le nom de la catégorie dans l'article.
21.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 21.py
from mymodule import extract_from_json
lines = extract_from_json(u"Angleterre").split("\n")
for line in lines:
if "Category" in line:
print(line)
#Avec python3, cela peut toujours être affiché (bien que ce soit une liste)
# print([line for line in lines if "Category" in line])
Bien qu'il s'agisse d'un chapitre sur les expressions régulières, il n'utilise pas d'expressions régulières. Eh bien, celui-ci est plus facile à comprendre ... Par conséquent, seule la ligne contenant la chaîne de caractères «Category» est «print».
Si vous l'écrivez dans la notation d'inclusion, elle s'adaptera parfaitement, mais en Python2, si vous «imprimez» simplement une liste contenant des chaînes de caractères Unicode, elle sera échappée. Par conséquent, il n'est pas affiché sous une forme qui peut être lue en japonais. Ce code peut être exécuté en Python3, donc si vous l'exécutez en Python3, il sera bien traité.
Extraire les noms des catégories d'articles (par nom, pas ligne par ligne).
22.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 22.py
import re
from mymodule import extract_from_json
lines = extract_from_json(u"Angleterre").split("\n")
for line in lines:
category_line = re.search("^\[\[Category:(.*?)(|\|.*)\]\]$", line)
if category_line is not None:
print(category_line.group(1))
Tout d'abord, extrayez la ligne de catégorie de la même manière qu'en 21., et extrayez-en uniquement le nom en utilisant re.search ()
.
re.search ()
retourne une instanceMatchObject
s'il y a une partie de la chaîne de caractères spécifiée par le deuxième argument qui correspond au modèle d'expression régulière du premier argument.
En plus de ce à quoi ressemble MatchObject
, vous pouvez utiliser .group ()
pour obtenir la chaîne correspondante.
Dans ce cas, dans category_line.group (0)
, toute la chaîne de caractères correspondante (par exemple " [[Category: United Kingdom | *]] "
), mais dans category_line.group (1)
, la première partie correspondante Vous obtiendrez une chaîne (par exemple ʻUK`).
Et bien que ce soit une expression régulière essentielle, les détails sont jetés dans le Document officiel, et des exemples d'adaptation spécifiques sont suivis sur cette page. J'aimerai essayer. Cliquez ici pour la ligne de catégorie à traiter cette fois (résultat d'exécution de 21.py)
22.Résultat d'exécution de py
$ python 22.py
[[Category:Angleterre|*]]
[[Category:Royaume du Royaume-Uni|*]]
[[Category:Pays membres du G8]]
[[Category:Pays membres de l'Union européenne]]
[[Category:Nation marine]]
[[Category:Pays souverain]]
[[Category:Pays insulaire|Kureito Furiten]]
[[Category:État / région créé en 1801]]
En gros, c'est [[Category: nom de la catégorie]]
, mais il y en a qui spécifient la lecture en séparant par |
. Donc, en tant que politique,
[[Category:
|
vient
--Enfin, fermez avec ]]
Ce sera sous la forme de.
Exprimer cela dans une expression régulière (je ne suis pas sûr que ce soit optimal) est " ^ \ [\ [Category: (. *?) (\ |. *) * \] \] $ "
.
Intention | Expression régulière réelle | Commentaire |
---|---|---|
Premier[[Category: Commence par |
^\[\[Category: |
^Spécifiez le début avec |
Une sorte de chaîne de caractères (nom de catégorie) vient | (.*?) |
Correspondance la plus courte avec n'importe quelle chaîne |
Dans certains cas| Le pseudonyme de lecture séparé par |
(\|.*)* |
(\|.*)*? Peut être plus approprié |
finalement]] Serrez avec |
\]\]$ |
Indique la fin$ Peut ne pas être nécessaire |
Affichez les noms de sections et leurs niveaux contenus dans l'article (par exemple, 1 si "== nom de section ==").
23.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 23.py
import re
from mymodule import extract_from_json
lines = extract_from_json(u"Angleterre").split("\n")
for line in lines:
section_line = re.search("^(=+)\s*(.*?)\s*(=+)$", line)
if section_line is not None:
print(section_line.group(2), len(section_line.group(1)) - 1)
La structure de base est la même que 22., mais cette fois, le nom de la section (par exemple == section ==) est la cible, nous allons donc la récupérer.
Puisqu'il y avait une légère fluctuation dans la notation (== section ==, == section ==), un caractère d'espacement \ s
est inséré entre eux afin qu'il puisse être absorbé.
Puisque le niveau de section correspond à la longueur de ==
(== 1 ==, === 2 ===, ...), il est calculé en acquérant la longueur et -1. Il est.
Extrayez tous les fichiers multimédias référencés dans l'article.
24.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 24.py
import re
from mymodule import extract_from_json
lines = extract_from_json(u"Angleterre").split("\n")
for line in lines:
file_line = re.search(u"(File|Fichier):(.*?)\|", line)
if file_line is not None:
print(file_line.group(2))
Au départ, seuls ceux commençant par File:
étaient extraits ... stupide.
C'est ʻUnicodeparce que le japonais est inclus dans le modèle d'expression régulière, mais il semble que cela soit autorisé dans le modèle d'expression régulière Python. Je vois souvent des exemples de chaînes brutes comme
r" hogehoge ", mais au moins cela ne me semble pas indispensable, car cela empêche le processus d'échappement de se dupliquer et de devenir difficile à lire? De plus, si vous voulez réutiliser le modèle d'expression régulière à plusieurs reprises, il semble plus efficace de compiler en utilisant
re.compile ()`. Cependant, le dernier modèle d'expression régulière utilisé est mis en cache, vous n'avez donc pas à vous en préoccuper cette fois.
Extraire les noms de champs et les valeurs du modèle "informations de base" inclus dans l'article et les stocker sous forme d'objet dictionnaire.
25.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 25.py
import re
from mymodule import extract_from_json
temp_dict = {}
lines = re.split(r"\n[\|}]", extract_from_json(u"Angleterre"))
for line in lines:
temp_line = re.search("^(.*?)\s=\s(.*)", line, re.S)
if temp_line is not None:
temp_dict[temp_line.group(1)] = temp_line.group(2)
for k, v in sorted(temp_dict.items(), key=lambda x: x[1]):
print(k, v)
Le modèle ~~ est inclus sous la forme «| nom du modèle = contenu du modèle», c'est donc une expression régulière qui lui correspond.
Comme mentionné ci-dessus, si vous écrivez ^ \ | (. *?) \ S = \ s (. *)
, La première parenthèse est le nom du modèle et la deuxième parenthèse est le contenu du modèle, alors mettez-le dans le dictionnaire. Il est stocké. ~~
Fondamentalement, le modèle est stocké ** dans chaque ligne ** sous la forme de «| nom du modèle = contenu du modèle», mais le nom officiel du pays était un peu gênant.
Nom officiel du pays
|Nom officiel du pays= {{lang|en|United Kingdom of Great Britain and Northern Ireland}}<ref>Nom officiel du pays autre que l'anglais:<br/>
*{{lang|gd|An Rìoghachd Aonaichte na Breatainn Mhòr agus Eirinn mu Thuath}}([[Gaélique écossais]])<br/>
*{{lang|cy|Teyrnas Gyfunol Prydain Fawr a Gogledd Iwerddon}}([[Pays de Galles]])<br/>
*{{lang|ga|Ríocht Aontaithe na Breataine Móire agus Tuaisceart na hÉireann}}([[irlandais]])<br/>
*{{lang|kw|An Rywvaneth Unys a Vreten Veur hag Iwerdhon Glédh}}([[Cornouailles]])<br/>
*{{lang|sco|Unitit Kinrick o Great Breetain an Northren Ireland}}([[Écossais]])<br/>
**{{lang|sco|Claught Kängrick o Docht Brätain an Norlin Airlann}}、{{lang|sco|Unitet Kängdom o Great Brittain an Norlin Airlann}}(Ulster écossais)</ref>
Comme mentionné ci-dessus, il s'étend sur plusieurs lignes, y compris les sauts de ligne (caractère = \ n
), il est donc nécessaire de bien gérer cette zone.
Après tout
split ()
, utilisez \ n |
ou \ n}
au lieu de \ n
(re.split ()
)split ()
}
Est impliqué car |
n'apparaît pas à la toute fin.re.S
à faire re.search () ʻincluant
\ n`search ()
car |
est époustouflé par split ()
Il a été fait par divers essais et erreurs.
J'ai utilisé for loop
to print
pour vérifier le contenu, mais Python3 est également recommandé. Python3 est utile pour une raison quelconque ...
Au moment du traitement> 25, supprimez le balisage d'accentuation MediaWiki (tout accent faible, accentuation et accentuation forte) de la valeur du modèle et convertissez-le en texte (Référence: [Markup Quick Reference](https: // ja. wikipedia.org/wiki/Help: tableau de référence rapide)).
26.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 26.py
import re
from mymodule import extract_from_json
temp_dict = {}
lines = re.split(r"\n[\|}]", extract_from_json(u"Angleterre"))
for line in lines:
temp_line = re.search("^(.*?)\s=\s(.*)", line, re.S)
if temp_line is not None:
temp_dict[temp_line.group(1)] = re.sub(r"'{2,5}", r"", temp_line.group(2))
# 25.Voir Python3 ainsi que py
for k, v in sorted(temp_dict.items(), key=lambda x: x[1]):
print(k, v)
re.sub
est une fonction qui remplace la partie qui correspond à l'expression régulière.
Cette fois, j'écris pour effacer 2 ou plus et 5 ou moins s. Si vous écrivez `{n, m}`, vous pouvez exprimer le caractère précédent comme n ou plus et m ou moins dans une expression régulière. ~~ Eh bien, j'ai l'impression que j'aurais dû supprimer tout
purement cette fois ... ~~
En plus du traitement 26, supprimez le balisage de lien interne de MediaWiki de la valeur du modèle et convertissez-le en texte (Référence: [Markup Quick Reference](https://ja.wikipedia.org/wiki/Help :) Graphique simplifié)).
27.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 27.py
import re
from mymodule import extract_from_json
def remove_markup(str):
str = re.sub(r"'{2,5}", r"", str)
str = re.sub(r"\[{2}([^|\]]+?\|)*(.+?)\]{2}", r"\2", str)
return str
temp_dict = {}
lines = extract_from_json(u"Angleterre").split("\n")
for line in lines:
category_line = re.search("^\|(.*?)\s=\s(.*)", line)
if category_line is not None:
temp_dict[category_line.group(1)] = remove_markup(category_line.group(2))
for k, v in sorted(temp_dict.items(), key=lambda x: x[0]):
print(k, v)
J'ai créé une fonction remove_markup ()
qui supprime les balises.
numéro de ligne | Cible à supprimer |
---|---|
La première ligne | Emphasis (similaire à 26) |
2e ligne | Lien interne |
Comment écrire des liens internes
Il existe trois types, mais tous sont conformes à la règle selon laquelle "le nom de l'article commence par [[
et se termine par un symbole (]]
, |
, #
) ". J'ai écrit une expression régulière.
En plus du traitement de> 27, supprimez autant que possible le balisage MediaWiki de la valeur du modèle et formatez les informations de base du pays.
28.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 28.py
import re
from mymodule import extract_from_json
def remove_markup(str):
str = re.sub(r"'{2,5}", r"", str)
str = re.sub(r"\[{2}([^|\]]+?\|)*(.+?)\]{2}", r"\2", str)
str = re.sub(r"\{{2}.+?\|.+?\|(.+?)\}{2}", r"\1 ", str)
str = re.sub(r"<.*?>", r"", str)
str = re.sub(r"\[.*?\]", r"", str)
return str
temp_dict = {}
lines = extract_from_json(u"Angleterre").split("\n")
for line in lines:
temp_line = re.search("^\|(.*?)\s=\s(.*)", line)
if temp_line is not None:
temp_dict[temp_line.group(1)] = remove_markup(temp_line.group(2))
for k, v in sorted(temp_dict.items(), key=lambda x: x[0]):
print(k, v)
En plus de 27
numéro de ligne | Cible à supprimer |
---|---|
La première ligne | Emphasis (similaire à 26) |
2e ligne | Lien interne (identique à 27) |
3e ligne | Notation avec la langue spécifiée (mais pas dans le tableau de balisage) |
4ème ligne | commentaire |
5ème ligne | Lien externe |
Réécriture de remove_markup ()
pour supprimer.
Utilisez le contenu du modèle pour obtenir l'URL de l'image du drapeau. (Astuce: appelez imageinfo dans l'API MediaWiki pour convertir les références de fichiers en URL)
29.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 29.py
import re
import requests
from mymodule import extract_from_json
def json_search(json_data):
ret_dict = {}
for k, v in json_data.items():
if isinstance(v, list):
for e in v:
ret_dict.update(json_search(e))
elif isinstance(v, dict):
ret_dict.update(json_search(v))
else:
ret_dict[k] = v
return ret_dict
def remove_markup(str):
str = re.sub(r"'{2,5}", r"", str)
str = re.sub(r"\[{2}([^|\]]+?\|)*(.+?)\]{2}", r"\2", str)
str = re.sub(r"\{{2}.+?\|.+?\|(.+?)\}{2}", r"\1 ", str)
str = re.sub(r"<.*?>", r"", str)
str = re.sub(r"\[.*?\]", r"", str)
return str
temp_dict = {}
lines = extract_from_json(u"Angleterre").split("\n")
for line in lines:
temp_line = re.search("^\|(.*?)\s=\s(.*)", line)
if temp_line is not None:
temp_dict[temp_line.group(1)] = remove_markup(temp_line.group(2))
url = "https://en.wikipedia.org/w/api.php"
payload = {"action": "query",
"titles": "File:{}".format(temp_dict[u"Image du drapeau"]),
"prop": "imageinfo",
"format": "json",
"iiprop": "url"}
json_data = requests.get(url, params=payload).json()
print(json_search(json_data)["url"])
Comment puis-je accéder à l'API en Python? Quand je l'ai recherché, c'était assez compliqué ...
requests
a été développé car il est difficile à utiliserrequests
se trouve ʻurllib3`... Eh bien, d'après la conclusion, il semble que les «requêtes» soient recommandées. Documentation officielle pour Python 3
Pour une interface client HTTP de niveau supérieur, le package Requests est recommandé.
Ou, Documents officiels pour les demandes
Requêtes: HTTP pour les humains (Omis) Le module urllib2 standard de Python a la plupart des fonctionnalités HTTP requises, mais l'API ne fonctionne pas correctement.
«Requests» est recommandé pour le texte fort.
Pour plus de détails sur son utilisation, reportez-vous au document officiel, mais cette fois, j'ai reçu le résultat de la frappe de l'API en JSON et je l'ai traité. La structure du JSON renvoyé était compliquée, j'ai donc cherché partout et vérifié la partie où l'URL était écrite.
Passez au chapitre 4.
Recommended Posts