Port 53

明日のための技術メモ

言語処理100本ノック 2020 第3章 後半

nlp100.github.io

第3章 正規表現の後半(25-29まで)解説書きます。
一気に難易度上がった。正規表現一覧表と格闘してる。
第3章 前半はこちら

目次

この章で使うファイル

Wikipediaの記事をJSONにしてgzで固めたもの。
途中、抽出してほしい箇所を指定されるが、WikipediaのHelp:早見表を見て確認のこと。

                   title                                               text
0                   エジプト  {{otheruses|主に現代のエジプト・アラブ共和国|古代|古代エジプト}}\n{{基礎...
1                 オーストリア  {{基礎情報 国\n|略名 = オーストリア\n|日本語国名 = オーストリア共和国\n|公...
2                 インドネシア  {{基礎情報 国\n| 略名 =インドネシア\n| 日本語国名 =インドネシア共和国\n| ...
3                    イラク  {{複数の問題\n| 参照方法 = 2011年8月\n| 独自研究 = 2012年10月\n...
4                    イラン  {{半保護}}\n{{未検証|date=2010年3月}}\n{{基礎情報 国\n | 略名...
..                   ...                                                ...
243  スヴァールバル諸島およびヤンマイエン島  '''スヴァールバル諸島およびヤンマイエン島''' (Svalbard and Jan Ma...
244               シンガポール  {{参照方法|date=2012年2月}}\n{{基礎情報 国\n|略名 = シンガポール\...
245                マレーシア  {{基礎情報 国\n|略名 =マレーシア\n|日本語国名 =マレーシア\n|公式国名 ={{...
246                BES諸島                     #転送 [[ボネール、シント・ユースタティウスおよびサバ]]
247               キュラソー島                             #転送 [[キュラソー (オランダ王国)]]

25-28. テンプレートの抽出~MediaWikiマークアップの除去

f:id:saturn-glave:20200509213116p:plain f:id:saturn-glave:20200509213349p:plain f:id:saturn-glave:20200509213429p:plain f:id:saturn-glave:20200509213528p:plain

ja.wikipedia.org

Wikipediaの国の基本情報を見ながら何が書いてあるか把握しておく。

正規表現と文字列置換を使い倒してゴリ押ししてしまった。(コードは汚いけど...)
後の問題見たら、多分タプルに国のテンプレートを格納したやつを辞書化するまでで良かったらしい。

ポイント

  • re.subで( )で囲った置換元のパターンを置換先で使いたい時、r'\参照したいパターンがある番号'で参照できる
s = '[[ファイル:アルパカ|alpaca.png]]'
tmp = re.sub(r'\[\[(?:ファイル|File):(.+?)\|(.+?)\]\]', r'\1', tmp)
print(tmp)

# アルパカ
# alpaca.pngを表示させたければ、r'\2'を指定する

解答

# coding:utf-8
import pandas as pd
import re


def uk_load():
    path = './jawiki-country.json.gz'
    wiki = pd.read_json(path, compression='infer', orient='records', lines=True)
    uk = wiki[wiki['title'] == 'イギリス']['text'].values[0]
    return(uk)


def main():
    uk_txt = uk_load()
    uk_basic = re.findall(r'\|(.+?) \= (.+)', uk_txt)
    ans = {}

    '''
    for item in uk_basic:
        print(item)
    print('')
    '''

    for item in uk_basic:
        tmp = re.sub(r'\{\{(.+)\|\[\[ファイル:(.+)\]\]\}\}', r'\2', item[1])
        tmp = re.sub(r'\[\[(?:ファイル|File):(.+?)\|(.+?)\]\]', r'\1', tmp)
        tmp = re.sub(r'\{\{lang\|(?:en|fr)\|(.+)\}\}', r'\1', tmp)
        tmp = re.sub(r'\{\{仮リンク\|(.+)\|(.+)\|(.+)\}\}', r'\1 \3', tmp)
        tmp = tmp.replace('{{en icon}}', '').replace('{{center|[[ファイル:', '')
        tmp = tmp.replace('[[', '').replace(']]', '').replace('{{', '').replace('}}', '')
        tmp = re.sub(r'\|', ' ', tmp)
        tmp = re.sub(r'<(.+?)>$', '', tmp)
        tmp = re.sub(r'<br \/>', ' ', tmp)
        tmp = tmp.replace('\'\'\'', '').replace('\'\'', '').replace(':en:', '')
        ans[item[0]] = tmp

    print(ans)


if __name__ == "__main__":
    main()

出力は以下の通り

{'日本語国名': 'グレートブリテン及び北アイルランド連合王国', '公式国名': 'United Kingdom of Great Britain and Northern Ireland', '国旗画像': 'Flag of the United Kingdom.svg', '国章画像': 'Royal Coat of Arms of the United Kingdom.svg', '標語': 'Dieu et mon droit (フランス語:Dieu et mon droit 神と我が権利)', '国歌': '女王陛下万歳 United States Navy Band - God Save the Queen.ogg', '地図画像': 'Europe-UK.svg', '位置画像': 'United Kingdom (+overseas territories) in the World (+Antarctica claims).svg', '公用語': '英語', '首都': 'ロンドン(事実上)', '最大都市': 'ロンドン', '元首等肩書': 'イギリスの君主 女王', '元首等氏名': 'エリザベス2世', '首相等肩書': 'イギリスの首相 首相', '首相等氏名': 'ボリス・ジョンソン', '他元首等肩書1': '貴族院 (イギリス) 貴族院議長', '他元首等氏名1': 'Norman Fowler, Baron Fowler ノーマン・ファウラー', '他元首等肩書2': '庶民院 (イギリス) 庶民院議長', '他元首等氏名2': 'リンゼイ・ホイル Lindsay Hoyle', '他元首等肩書3': '連合王国最高裁判所 最高裁判所長官', '他元首等氏名3': 'Brenda Hale, Baroness Hale of Richmond ブレンダ・ヘイル', '面積順位': '76', '面積大きさ': '1 E11', '面積値': '244,820', '水面積率': '1.3%', '人口統計年': '2018', '人口順位': '22', '人口大きさ': '1 E7', '人口値': '6643万5600', '人口密度値': '271', 'GDP統計年元': '2012', 'GDP値元': '1兆5478億', 'GDP統計年MER': '2012', 'GDP順位MER': '6', 'GDP値MER': '2兆4337億', 'GDP統計年': '2012', 'GDP順位': '6', 'GDP値': '2兆3162億', 'GDP/人': '36,727', '建国形態': '建国', '確立形態1': 'イングランド王国/スコットランド王国 (両国とも合同法 (1707年) 1707年合同法まで)', '確立年月日1': '927年/843年', '確立形態2': 'グレートブリテン王国成立 (1707年合同法)', '確立年月日2': '1707年05月01日', '確立形態3': 'グレートブリテン及びアイルランド連合王国成立 (合同法 (1800年) 1800年合同法)', '確立年月日3': '1801年01月01日', '確立形態4': '現在の国号「グレートブリテン及び北アイルランド連合王国」に変更', '確立年月日4': '1927年04月12日', '通貨': 'スターリング・ポンド UKポンド (£)', '通貨コード': 'GBP', '時間帯': '±0', '夏時間': '+1', 'ISO 3166-1': 'GB / GBR', 'ccTLD': '.uk / .gb', '国際電話番号': '44', '注記': ''}

参考記事

www.kt.rim.or.jp

note.nkmk.me

29. 国旗画像のURLを取得する

f:id:saturn-glave:20200509213614p:plain

WikipediaMediaWiki APIから、imageinfoを使ってURLを取ってくる。
JSONで取っておいて、それをまたDataFrame化して必要なところを抜いた。
URLを引っ張ってくるには、パラメータiipropにてurlと指定してあげることが必要。

www.mediawiki.org

www.mediawiki.org

http://wiki.step.im/api.php?action=help&recursivesubmodules=1

ポイント

  • 入れ子になったJSONをDataFrameにする時、r'pandas.json_normalize(JSON)'で参照できる
    • pandas.io.json.json_normalizeは非推奨になった。

解答スクリプト

# coding:utf-8
import pandas as pd
import re
import requests


def uk_load():
    path = './jawiki-country.json.gz'
    wiki = pd.read_json(path, compression='infer', orient='records', lines=True)
    uk = wiki[wiki['title'] == 'イギリス']['text'].values[0]
    return(uk)


def main():
    uk_txt = uk_load()
    uk_basic = re.findall(r'\|(.+?) \= (.+)', uk_txt)
    uk_dict = {}

    for item in uk_basic:
        tmp = re.sub(r'\{\{(.+)\|\[\[ファイル:(.+)\]\]\}\}', r'\2', item[1])
        tmp = re.sub(r'\[\[(?:ファイル|File):(.+?)\|(.+?)\]\]', r'\1', tmp)
        tmp = re.sub(r'\{\{lang\|(?:en|fr)\|(.+)\}\}', r'\1', tmp)
        tmp = re.sub(r'\{\{仮リンク\|(.+)\|(.+)\|(.+)\}\}', r'\1 \3', tmp)
        tmp = tmp.replace('{{en icon}}', '').replace('{{center|[[ファイル:', '')
        tmp = tmp.replace('[[', '').replace(']]', '').replace('{{', '').replace('}}', '')
        tmp = re.sub(r'\|', ' ', tmp)
        tmp = re.sub(r'<(.+?)>$', '', tmp)
        tmp = re.sub(r'<br \/>', ' ', tmp)
        tmp = tmp.replace('\'\'\'', '').replace('\'\'', '').replace(':en:', '')
        uk_dict[item[0]] = tmp

    # print(uk_dict)
    # print(uk_dict['国旗画像'])

    url = 'https://www.mediawiki.org/w/api.php'
    params = {
        "action": "query",
        "format": "json",
        "prop": "imageinfo",
        "titles": 'File:' + uk_dict['国旗画像'],
        "iiprop": "url"
    }

    r = requests.get(url, params=params)
    result = r.json()
    # print(result)

    df = pd.json_normalize(result)
    url = df['query.pages.-1.imageinfo'].values[0]
    # print(url)
    print(url[0]['url'])


if __name__ == "__main__":
    main()

出力は以下の通り。

# APIでデータを抜いた結果
{'continue': {'iistart': '2019-09-10T16:52:58Z', 'continue': '||'}, 'query': {'pages': {'-1': {'ns': 6, 'title': 'File:Flag of the United Kingdom.svg', 'missing': '', 'known': '', 'imagerepository': 'shared', 'imageinfo': [{'url': 'https://upload.wikimedia.org/wikipedia/commons/a/ae/Flag_of_the_United_Kingdom.svg', 'descriptionurl': 'https://commons.wikimedia.org/wiki/File:Flag_of_the_United_Kingdom.svg', 'descriptionshorturl': 'https://commons.wikimedia.org/w/index.php?curid=347935'}]}}}}

# DataFrame化した後
       continue.iistart  ...                           query.pages.-1.imageinfo
0  2019-09-10T16:52:58Z  ...  [{'url': 'https://upload.wikimedia.org/wikiped...


# 最終結果
$ python CH3-29.py
https://upload.wikimedia.org/wikipedia/commons/a/ae/Flag_of_the_United_Kingdom.svg

参考記事

note.nkmk.me

note.nkmk.me