20
import gzip import json country_dict_list = [] with gzip.open('jawiki-country.json.gz', 'rt') as r: data = r.readlines() for line in data: country_dict_list.append(json.loads(line)) for line_dict in country_dict_list: if line_dict['title'] == 'イギリス': england_data = line_dict['text'] print(england_data)
出力は
dict_values(['イギリス', '{{redirect|UK}}
で始まり
[[Category:1801年に成立した国家・領域]]'])
で終わる。
jsonは
{"title": "エジプト", "text": "長い文章"}
{"title": "長い文章...
となっており、辞書としてjline['title']とjline['text']でそれぞれの内容を取り出せるようにcountry_dict_listに追加していく。
openのオプションがrtであり、rと比べるとテキストとしてprintでき便利。
titleがイギリスである要素は1個であると仮定し、「england_data = line_dict['text']」の直後でbreakをしてもよい。
21
import gzip import json country_dict_list = [] with gzip.open('jawiki-country.json.gz', 'rt') as r: data = r.readlines() for line in data: country_dict_list.append(json.loads(line)) for line_dict in country_dict_list: if line_dict['title'] == 'イギリス': england_data = line_dict['text'] ##### attr_split = england_data.splitlines() for line in attr_split: if line[:11] == '[[Category:' or line[:7] == '[[カテゴリ:': print(line)
出力は
[[Category:イギリス|*]]
[[Category:イギリス連邦加盟国]]
[[Category:英連邦王国|*]]
[[Category:G8加盟国]]
[[Category:欧州連合加盟国|元]]
[[Category:海洋国家]]
[[Category:現存する君主国]]
[[Category:島国]]
[[Category:1801年に成立した国家・領域]]
である。
#####より上は問題20のコードの表示以外と同じである。以降本記事内では同様。
カテゴリ名の宣言には、「[[Category:」以外にも「[[カテゴリ:」で始まるが、イギリスの記事には存在しなかった。
22
import gzip import json import re country_dict_list = [] with gzip.open('jawiki-country.json.gz', 'rt') as r: data = r.readlines() for line in data: country_dict_list.append(json.loads(line)) for line_dict in country_dict_list: if line_dict['title'] == 'イギリス': england_data = line_dict['text'] ##### attr_split = england_data.splitlines() for line in attr_split: if re.fullmatch(r'^\[\[Category:.*$|^\[\[カテゴリ:.*\]\]$', line): line = re.sub(r'^\[\[Category:', '', line) line = re.sub(r'^\[\[カテゴリ:', '', line) line = re.sub(r'\|[^|]+\]\]$', '', line) line = re.sub(r'\]\]$', '', line) print(line)
出力は
イギリス
イギリス連邦加盟国
英連邦王国
G8加盟国
欧州連合加盟国
海洋国家
現存する君主国
島国
1801年に成立した国家・領域
正規表現を用いた。
それぞれの行に対して、[[Category:で始まって]]で終わるか、[[カテゴリ:で始まって]]で終わるかをre.fullmatch()で判定し、
先頭と末尾から余分なものを順に削除。
if文のように|でつなげば一行で4処理を同時に書けるが、可読性に難あり。
23
import gzip import json import re country_dict_list = [] with gzip.open('jawiki-country.json.gz', 'rt') as r: data = r.readlines() for line in data: country_dict_list.append(json.loads(line)) for line_dict in country_dict_list: if line_dict['title'] == 'イギリス': england_data = line_dict['text'] ##### attr_split = england_data.splitlines() for line in attr_split: if re.fullmatch(r'^==.*',line): print(re.sub(r'^==+ ?| ?=+$', '', line), len(re.match(r'^==+', line).group())-1)
出力は
国名 1
歴史 1
地理 1
主要都市 2
気候 2
政治 1
元首 2
法 2
内政 2
地方行政区分 2
外交・軍事 2
経済 1
鉱業 2
農業 2
貿易 2
不動産 2
エネルギー政策 2
通貨 2
企業 2
通信 3
交通 1
道路 2
鉄道 2
海運 2
航空 2
科学技術 1
国民 1
言語 2
宗教 2
婚姻 2
移住 2
教育 2
医療 2
文化 1
食文化 2
文学 2
哲学 2
音楽 2
ポピュラー音楽 3
映画 2
コメディ 2
国花 2
世界遺産 2
祝祭日 2
スポーツ 2
サッカー 3
クリケット 3
競馬 3
モータースポーツ 3
野球 3
カーリング 3
自転車競技 3
脚注 1
関連項目 1
外部リンク 1
==で始まる行をfullmatch()で見つけ、
前後の=と半角スペースを除去し、==で始まる=の数-1で階層を計算。
24
import gzip import json import re country_dict_list = [] with gzip.open('jawiki-country.json.gz', 'rt') as r: data = r.readlines() for line in data: country_dict_list.append(json.loads(line)) for line_dict in country_dict_list: if line_dict['title'] == 'イギリス': england_data = line_dict['text'] ##### attr_split = england_data.splitlines() pattern = re.compile(r"^\[\[ファイル:.*") for line in attr_split: if re.fullmatch(r'^\[\[ファイル:.*', line): print(line.split('|')[0].replace('[[ファイル:',''))
出力は
Descriptio Prime Tabulae Europae.jpg
Lenepveu, Jeanne d'Arc au siège d'Orléans.jpg
London.bankofengland.arp.jpg
Battle of Waterloo 1815.PNG
Uk topo en.jpg
BenNevis2005.jpg
Population density UK 2011 census.png
2019 Greenwich Peninsula & Canary Wharf.jpg
Leeds CBD at night.jpg
Palace of Westminster, London - Feb 2007.jpg
Scotland Parliament Holyrood.jpg
Donald Trump and Theresa May (33998675310) (cropped).jpg
Soldiers Trooping the Colour, 16th June 2007.jpg
City of London skyline from London City Hall - Oct 2008.jpg
Oil platform in the North SeaPros.jpg
Eurostar at St Pancras Jan 2008.jpg
Heathrow Terminal 5C Iwelumo-1.jpg
UKpop.svg
Anglospeak.svg
Royal Aberdeen Children's Hospital.jpg
CHANDOS3.jpg
The Fabs.JPG
Wembley Stadium, illuminated.jpg
「[[ファイル:」で始まる行を取り出し、最初の|の直前までを表示。
25
不真面目に解きます。
正式には、{{と}}でパースする方法だと思いつつ、正規表現の処理ではないと思ったため、行ごとに処理。
例えば、正式国名は「'{{lang|en|United Kingdom of Great Britain and Northern Ireland}}英語以外での正式国名:
',」などになる。
import gzip import json import re country_dict_list = [] with gzip.open('jawiki-country.json.gz', 'rt') as r: data = r.readlines() for line in data: country_dict_list.append(json.loads(line)) for line_dict in country_dict_list: if line_dict['title'] == 'イギリス': england_data = line_dict['text'] ##### attr_split = england_data.splitlines() template_dict = dict() mode = 0 # if in 基礎情報 mode=1, else mode=0 for line in attr_split: if re.search(r'^\{\{基礎情報', line): mode = 1 if mode == 1: if line == '}}': break; m = re.findall(r'[^=]+=.*', line) for item in m: mm = re.findall(r'[^=]+', item) template_dict[mm[0].lstrip('|').rstrip()] = ''.join(mm[1:]).lstrip()
出力は
{'GDP/人': '36,727',
'GDP値': '2兆3162億',
'GDP値MER': '2兆4337億',
で始まり
'首相等氏名': '[[ボリス・ジョンソン]]',
'首相等肩書': '[[イギリスの首相|首相]]',
'首都': '[[ロンドン]](事実上)'}
で終わる。
基礎情報である間は1、それ以外で0となる、modeを使った。
文に「{{基礎情報」があればmode=1、文全体が「}}」ならばmode=0とした。
=でつながれた行において、
左辺から先頭の「|」と末尾の空白を除いたものをキー、右辺の末尾の空白を除いたものを値として辞書にした。
wikipediaの記法について詳しければ更に正しくパースできると思う。
問題26では{{と}}の数を数えたものも実装したが、結局行ごとの処理である。
26
import gzip import json import re country_dict_list = [] with gzip.open('jawiki-country.json.gz', 'rt') as r: data = r.readlines() for line in data: country_dict_list.append(json.loads(line)) for line_dict in country_dict_list: if line_dict['title'] == 'イギリス': england_data = line_dict['text'] ##### attr_split = england_data.splitlines() template_dict = dict() mode = 0 # if in 基礎情報 mode=1, else mode=0 depth = 0 for line in attr_split: if re.search(r'^\{\{基礎情報',line): mode = 1 if mode == 1: if re.findall(r'\{\{', line): #{{でdepthを{{の個数だけ増やす depth += len(re.findall(r'\{\{', line)) if 0 < depth: #もし{{の内部なら m = re.findall(r'[^=]+=.*', line) for item in m: # hoge = fuga があれば mm = re.findall(r'[^=]+', item) # 「=」を含まない場所を配列で取得 if re.findall(r'\}\}', line) and (depth == len(re.findall(r'\}\}', line))): #この行で終わる場合}}を除く template_dict[mm[0].lstrip('|').rstrip()] = ''.join(mm[1:]).lstrip()[:-2] else: template_dict[mm[0].lstrip('|').rstrip()] = ''.join(mm[1:]).lstrip() if re.findall(r'\}\}', line): depth -= len(re.findall(r'\}\}',line)) if depth <= 0: mode = 0 for key, value in template_dict.items(): value = value.replace('\'\'\'','').replace('\'\'','') #「強調」の削除。 print(key, value)
出力は
略名 イギリス
日本語国名 グレートブリテン及び北アイルランド連合王国
公式国名 {{lang|en|United Kingdom of Great Britain and Northern Ireland}}英語以外での正式国名:
で始まり
ccTLD [[.uk]] / [[.gb]]使用は.ukに比べ圧倒的少数。
国際電話番号 44
注記
で終わる。
modeに関しては問題25と同じ。
depthによって{{が何個あったか?を意味し、対応する個数}}を受け取ったら基礎情報の終わりとした。
強調マークアップはアポストロフィ3個で囲んだものと2個で囲んだものがある。
先に2個で囲んだものを置換(=replace)すると、3個で囲んだものが1個で囲んだものになってしまうため、先に3個で囲んだものを置換している。(正確には、囲んでいるか?は気にしていない)
27
下から3行以外は問題26と同様。
import gzip import json import re country_dict_list = [] with gzip.open('jawiki-country.json.gz', 'rt') as r: data = r.readlines() for line in data: country_dict_list.append(json.loads(line)) for line_dict in country_dict_list: if line_dict['title'] == 'イギリス': england_data = line_dict['text'] attr_split = england_data.splitlines() template_dict = dict() mode = 0 # if in 基礎情報 mode=1, else mode=0 depth = 0 for line in attr_split: if re.search(r'^\{\{基礎情報',line): mode = 1 if mode == 1: if re.findall(r'\{\{', line): #{{でdepthを{{の個数だけ増やす depth += len(re.findall(r'\{\{', line)) if 0 < depth: #もし{{の内部なら m = re.findall(r'[^=]+=.*', line) for item in m: # hoge = fuga があれば mm = re.findall(r'[^=]+', item) # 「=」を含まない場所を配列で取得 if re.findall(r'\}\}', line) and (depth == len(re.findall(r'\}\}', line))): #この行で終わる場合、}}を除くため別処理 template_dict[mm[0].lstrip('|').rstrip()] = ''.join(mm[1:]).lstrip()[:-2] else: template_dict[mm[0].lstrip('|').rstrip()] = ''.join(mm[1:]).lstrip() if re.findall(r'\}\}', line): depth -= len(re.findall(r'\}\}',line)) if depth <= 0: mode = 0 for key, value in template_dict.items(): value = value.replace('\'\'\'','').replace('\'\'','') # マークアップ「強調」の削除。 value = re.sub(r'\[\[([^\[]*?)\|([^\]]*)\]\]',r'\2', value) #リンク記法削除1 [[hoge|fuga]]->fuga value = value.replace('[[','').replace(']]','') #リンク記法削除2 [[hoge]]->hoge print(key, value)
出力は
略名 イギリス
日本語国名 グレートブリテン及び北アイルランド連合王国
公式国名 {{lang|en|United Kingdom of Great Britain and Northern Ireland}}英語以外での正式国名:
で始まり
ccTLD .uk / .gb使用は.ukに比べ圧倒的少数。
国際電話番号 44
注記
で終わる。
リンク記法を削除した。
#リンク記法削除1 の
\[\[([^\[]*?)\|([^\]]*)\]\]
は、[[リンク先|表示名]]なので表示名だけを残す。
\2で2個目の丸括弧内を取得し、sub()の第2引数(置換後の文字列)とした。
その後、単なるリンク[[リンク先]](表示名も同じ)のリンク記法を[[と]]の削除によって削除。
正確な処理では、「|」を含むリンクやそのエスケープ手法があるかもしれないが、妥協。
28
下から8行以外は問題26と同様。
import gzip import json import re country_dict_list = [] with gzip.open('jawiki-country.json.gz', 'rt') as r: data = r.readlines() for line in data: country_dict_list.append(json.loads(line)) for line_dict in country_dict_list: if line_dict['title'] == 'イギリス': england_data = line_dict['text'] ##### attr_split = england_data.splitlines() template_dict = dict() mode = 0 # if in 基礎情報 mode=1, else mode=0 depth = 0 for line in attr_split: if re.search(r'^\{\{基礎情報',line): mode = 1 if mode == 1: if re.findall(r'\{\{', line): #{{でdepthを{{の個数だけ増やす depth += len(re.findall(r'\{\{', line)) if 0 < depth: #もし{{の内部なら m = re.findall(r'[^=]+=.*', line) for item in m: # hoge = fuga があれば mm = re.findall(r'[^=]+', item) # 「=」を含まない場所を配列で取得 if re.findall(r'\}\}', line) and (depth == len(re.findall(r'\}\}', line))): #この行で終わる場合、}}を除くため別処理 template_dict[mm[0].lstrip('|').rstrip()] = ''.join(mm[1:]).lstrip()[:-2] else: template_dict[mm[0].lstrip('|').rstrip()] = ''.join(mm[1:]).lstrip() if re.findall(r'\}\}', line): depth -= len(re.findall(r'\}\}',line)) if depth <= 0: mode = 0 for key, value in template_dict.items(): value = value.replace('\'\'\'','').replace('\'\'','') # マークアップ「強調」の削除。 value = re.sub(r'\[\[([^\[]*?)\|([^\]]*)\]\]',r'\2', value) #リンク記法削除1 [[hoge|fuga]]->fuga value = value.replace('[[','').replace(']]','') #リンク記法削除2 [[hoge]]->hoge value = value.replace('{{en icon}}', '') # {{en icon}}削除 value = re.sub(r'\d+px\|', '', value) # 画像サイズを表す 「85px|」 を削除(汎用的に 「[数字]px|」を削除 value = value.replace('{{0}}',' ') # {{0}}は文字「0」と同じ幅の空白なので{{}}の削除のみではないとした value = re.sub(r'\{\{.*?([^\|\}]*?)\}\}',r'\1', value) # {{}}の削除(最後の要素のみ残す value = re.sub(r'<ref>.*?(</ref>|$)', '', value) #<ref>~</ref> と <ref>~で終わるものを削除。 value = re.sub(r'<ref name".*?(" />|</ref>)', '', value) value = value.replace('<br />',' ') #改行コードの削除 print(key, value)
出力は
略名 イギリス
日本語国名 グレートブリテン及び北アイルランド連合王国
公式国名 United Kingdom of Great Britain and Northern Ireland
で始まり
ccTLD .uk / .gb
国際電話番号 44
注記
で終わる。
コメントに書いたとおり、それぞれのMediaWikiマークアップなどを削除した。
公式国名の抽出が不適格なため、が閉じないまま行末に至るものも削除している。
29
#######までは問題28と同様。
import gzip import json import re country_dict_list = [] with gzip.open('jawiki-country.json.gz', 'rt') as r: data = r.readlines() for line in data: country_dict_list.append(json.loads(line)) for line_dict in country_dict_list: if line_dict['title'] == 'イギリス': england_data = line_dict['text'] attr_split = england_data.splitlines() template_dict = dict() mode = 0 # if in 基礎情報 mode=1, else mode=0 depth = 0 for line in attr_split: if re.search(r'^\{\{基礎情報',line): mode = 1 if mode == 1: if re.findall(r'\{\{', line): #{{でdepthを{{の個数だけ増やす depth += len(re.findall(r'\{\{', line)) if 0 < depth: #もし{{の内部なら m = re.findall(r'[^=]+=.*', line) for item in m: # hoge = fuga があれば mm = re.findall(r'[^=]+', item) # 「=」を含まない場所を配列で取得 if re.findall(r'\}\}', line) and (depth == len(re.findall(r'\}\}', line))): #この行で終わる場合、}}を除くため別処理 template_dict[mm[0].lstrip('|').rstrip()] = ''.join(mm[1:]).lstrip()[:-2] else: template_dict[mm[0].lstrip('|').rstrip()] = ''.join(mm[1:]).lstrip() if re.findall(r'\}\}', line): depth -= len(re.findall(r'\}\}',line)) if depth <= 0: mode = 0 ####### import requests S = requests.Session() URL = "https://en.wikipedia.org/w/api.php" PARAMS = { "action": "query", "format": "json", "prop": "imageinfo", "titles": 'File:'+template_dict['国旗画像'], 'iiprop': 'url' } R = S.get(url=URL, params=PARAMS) DATA = R.json() PAGES = DATA["query"]["pages"] for k, v in PAGES.items(): print(v['imageinfo'][0]['url'])
参考:API:Imageinfo - MediaWiki
ほぼ参考リンクのまま書くだけである。
呼び出し方は「v["imageinfo"][0]["user"]」の例のuserをurlに変更した。
「Gives URL to the file and the description page. If the file has been revision deleted, a filehidden property will be returned.」と書かれているため、このurlという要素を呼び出すとそのままurlである。