本記事の参考ぺージ
Wikipediaのダンプからページを取り出す #Python - Qiita
ダンプデータについて
Wikpediaのダンプ記事データにはindexとデータ本体の2種類がある。 indexを活用するとbz2ファイルを解凍せずに高速に記事にアクセスできる
- indexデータ: jawiki-20241001-pages-articles-multistream-index.txt.bz2
- 本体データ: jawiki-20241001-pages-articles-multistream.xml.bz2
indexデータの構成
indexデータは、以下のように構成される。一記事に1行1記事がある。
「index:page_id:記事名」という構成。
$ bzgrep "高城れに" "jawiki-20241001-pages-articles-mult istream-index.txt.bz2" 1972156087:1771835:高城れに 3217498582:3500139:高城れにの週末ももクロ☆パンチ!! 3217498582:3500156:高城れにの週末ももクロ☆パンチ
index検索もとに必要なデータ。
次のindexに代わるindexが必要。一つのindexに約100記事ぐらいづつ含まれてるそうです。 下の例だと1972322566になる。その番号でindexが切り替わってる。
bzgrep -A 60 "高城れに$" "jawiki-20241001-pages-artic les-multistream-index.txt.bz2" 1972156087:1771835:高城れに 1972156087:1771836:株式会社TSUTAYA 1972156087:1771838:マーベル・ゾンビーズシリーズ 1972156087:1771840:マーベル・ゾンビーズ 1972156087:1771841:教育映画 1972156087:1771844:熱闘シリーズ 1972156087:1771846:マハヴィーラ 1972156087:1771847:Wikipedia:削除依頼/完全メイド宣言 1972156087:1771848:クリムゾン・キモノ 1972156087:1771850:第6実験室 予告版 1972156087:1771851:Wikipedia:削除依頼/コスプレ系飲食店 1972156087:1771853:百田夏菜子 1972156087:1771854:Category:日本の公立短期大学 1972156087:1771855:神戸県 1972156087:1771856:2004年欧州議会議員選挙 (イギリス) 1972156087:1771858:カール・マリア・ヴィリグート 1972156087:1771859:高知親局送信所 1972156087:1771860:東北7県 1972156087:1771864:東北圏 1972156087:1771903:ルーシャス・シェパード 1972156087:1771904:フェルナンド・カセレス 1972156087:1771912:ファミマガディスク 1972156087:1771920:カルレス・ブスケツ 1972156087:1771937:ザ・ローリング・ストーンズ シャイン・ア・ライト 1972156087:1771953:海洋底 1972156087:1771958:ECC外語学院 1972156087:1771977:Wikipedia:削除依頼/ファイル:ライダーズ ラプソディZ2改.jpg 1972156087:1771978:トーザ外語学院 1972156087:1771979:NDソフトスタジアム山形 1972156087:1771980:ヒューマン外語学院 1972156087:1771981:ファミマガDisk 1972156087:1771982:声 あなたと読売テレビ 1972156087:1771984:ベアトリス・デ・カスティーリャ・イ・グスマン 1972156087:1771985:Category:ノルウェーのノルディック複合選手 1972156087:1771986:豆盧通 1972156087:1771988:グアダルーペ (ヌエボ・レオン州) 1972156087:1771989:立命館大学の人物一覧 1972156087:1771993:Category:ノルウェーのクロスカントリースキー選手 1972156087:1771994:ベアトリス・デ・カスティーリャ・イ・モリナ 1972156087:1771995:インクレディブル・ハルク 1972156087:1771997:テクタイト 1972156087:1771998:Wikipedia:投稿ブロック依頼/利用者:210.199.5.151 1972156087:1771999:ロック・ボトム 1972322566:1772000:古市 (広島市) 1972322566:1772001:大谷敬二郎
本体から取り出す。
Pythonを利用して記事本体からindex情報、id情報、次のindex情報を使って取り出す。
高城れにの場合の情報
- index: 1972156087
- id: 1771835
- 次のindex: 1972322566
コード
取り出した記事をtakagi.xlm にファイルとして保存する。out_file_nameで設定。
# ダンプファイルのパス dump_file = 'jawiki-20241001-pages-articles-multistream.xml.bz2' out_file_name="takagi" offset = 1972156087 # インデックスで得たオフセット値 id= 1771835 next_offset = 1972322566 # ダンプファイルをバイナリモードで開き、指定のオフセットから読み込む with open(dump_file, 'rb') as f: f.seek(offset) # オフセットに移動 block = f.read(next_offset-offset) #一ブロックの読み込み data=bz2.decompress(block) #ブロックを解答 xml = data.decode(encoding="utf-8") #ブロックを文字に #保存や出力など root = ET.fromstring("<root>" + xml + "</root>") page = root.find(f"page/[id='{id}']") tree = ET.ElementTree(page) print(ET.tostring(page,encoding='unicode')) tree.write(f"{out_file_name}.xml", encoding="utf-8")
ワードから記事取得まで行うコード
import bz2 import xml.etree.ElementTree as ET #index の検索 #search_term="高城れに" out_file_name="Doraemon" search_term="ドラえもん" index_file="jawiki-20241001-pages-articles-multistream-index.txt.bz2" indexs=[] next_indexs=[] count=0 old_tmp_offset="" with bz2.open(index_file, 'rt', encoding='utf-8') as f: for line in f: if search_term in line: indexs.append(line) count=count+1 tmp_offset=line.split(":")[0] if not (old_tmp_offset=="" or old_tmp_offset==tmp_offset): for no in range(count): next_indexs.append(tmp_offset) count=0 #break old_tmp_offset=tmp_offset print(next_indexs) #quit() #exit() names=[i.split(":")[2].strip() for i in indexs] offsets=[i.split(":")[0] for i in indexs] ids=[i.split(":")[1] for i in indexs] print(indexs) closest_index = min(range(len(names)), key=lambda i: abs(len(names[i]) - len(search_term))) word=(names[closest_index]) word_offset=(offsets[closest_index]) word_next_offset=(next_indexs[closest_index]) word_id=(ids[closest_index]) print(word) print(word_offset) print(word_next_offset) # ダンプファイルのパス dump_file = 'jawiki-20241001-pages-articles-multistream.xml.bz2' #offset = 1972156087 # インデックスで得たオフセット値 #id= 1771835 offset = int(word_offset) # インデックスで得たオフセット値 next_offset = int(word_next_offset) # インデックスで得たオフセット値 id= int(word_id) # ダンプファイルをバイナリモードで開き、指定のオフセットから読み込む with open(dump_file, 'rb') as f: print("seek0") f.seek(offset) # オフセットに移動 print("seek1") block = f.read(next_offset-offset) # 5000バイト分読み込む(必要に応じて調整) #block = f.read(1972322566-1972156087) # 5000バイト分読み込む(必要に応じて調整) data=bz2.decompress(block) xml = data.decode(encoding="utf-8") root = ET.fromstring("<root>" + xml + "</root>") page = root.find(f"page/[id='{id}']") # 読み込んだデータから記事を抽出 #start = data.find('<page>') #end = data.find('</page>') + len('</page>') #article = data[start:end] #print(article) #print(xml) tree = ET.ElementTree(page) print(ET.tostring(page,encoding='unicode')) tree.write(f"{out_file_name}.xml", encoding="utf-8")
まとめてワードリストを検索して早くする。
ワードリスト
ワードリストは「id ワード」の形式で用意する。 名前は、name_b_utf2.csv とした
$ head name_b_utf2.csv 1 スマホ 2 ハッシュタグ 3 Instagram 4 モデルプレス 5 ⭐ 6 インスタグラム 7 Xperia
作業フォルダの作成
wikiのフォルダを作っておく
mkdir wiki
ワードリストの単語のindexを検索
indexは、wiki/index_list0.csvに保存される。
import bz2 import xml.etree.ElementTree as ET import sys import copy import re args=sys.argv #index の検索 #出力ファイルノヘッダー #id_name="wiki/"+args[1] #search_term="高城れに" #search_term="ドラえもん" #search_term=args[2].strip().replace("\"","") id0s=[] search_terms=[] with open("name_b_utf2.csv") as fin: for line in fin.readlines(): line=line.strip().split(" ") id0s.append(line[0]) search_terms.append(line[1]) #word_file=.strip().replace("\"","") #index_file="jawiki-20241001-pages-articles-multistream-index.txt.bz2" index_file="jawiki-20241001-pages-articles-multistream-index.txt" indexs=[] next_indexs=[] file_id=[] count=0 old_tmp_offset="" #1print(id_name) print(search_terms) #quit() #exit() tmp_search_terms=copy.deepcopy(search_terms) #with open(index_file, 'rt', encoding='utf-8') as f: with bz2.open(index_file, 'rt', encoding='utf-8') as f: for line in f: #print(line) word0=re.sub(r'\(.*\)','',line.split(":")[2].strip()) #print(word0) if any([word == word0 for word in tmp_search_terms]): tmp_search_terms.remove(word0) print(line) indexs.append(line) #count=count+1 tmp_offset=line.split(":")[0] #if not (old_tmp_offset=="" or old_tmp_offset==tmp_offset): # for no in range(count): # next_indexs.append(tmp_offset) # count=0 #break #old_tmp_offset=tmp_offset print(next_indexs) names=[i.split(":")[2].strip() for i in indexs] offsets=[i.split(":")[0] for i in indexs] ids=[i.split(":")[1] for i in indexs] print(indexs) with open("wiki/index_list0.csv","w") as f_out: for name,offset,id in zip(names,offsets,ids): print((",").join([name,offset,id])) print((",").join([name,offset,id]),file=f_out) exit() quit()
保存フォーマットは、「単語,index,ID」。
$ head wiki/index_list0.csv つの丸,4827164,931 バンダイナムコエンターテインメント,7926411,1413 森高夕次,14088537,2290 UEFAヨーロッパリーグ,17410483,2757 東海林さだお,24147253,3987 1315年,34488021,5572 原子軌道,36621488,5957 311年,48348477,8347 銅酸化物,50256325,8644 ダービーステークス,52737293,9320
その単語のindexの次のindexのデータに追加
$ cat wiki/wiki3b.py import bz2 import xml.etree.ElementTree as ET import sys import copy import re args=sys.argv #index の検索 #出力ファイルノヘッダー #id_name="wiki/"+args[1] #search_term="高城れに" #search_term="ドラえもん" #search_term=args[2].strip().replace("\"","") #word_file=.strip().replace("\"","") #index_file="jawiki-20241001-pages-articles-multistream-index.txt.bz2" index_file="jawiki-20241001-pages-articles-multistream-index.txt" indexs=[] next_indexs=[] file_id=[] count=0 old_tmp_offset="" next_list={} with open(index_file, 'rt', encoding='utf-8') as f: #with bz2.open(index_file, 'rt', encoding='utf-8') as f: for line in f: #print(line) #print(word0) #count=count+1 tmp_offset=line.split(":")[0] if not (old_tmp_offset=="" or old_tmp_offset==tmp_offset): print(tmp_offset) next_list[old_tmp_offset]=tmp_offset old_tmp_offset=tmp_offset next_list[old_tmp_offset]=tmp_offset id_dic={} with open("name_b_utf2.csv") as fin: for line in fin.readlines(): line=line.strip().split(" ") id_dic[line[1]]=line[0] print(next_list) f_out=open("wiki/index_list1.csv","w") with open("wiki/index_list0.csv") as f_in: for i in f_in.readlines(): row=i.strip().split(",") #print(row) print(row[0]+","+row[1]+","+row[2]+","+next_list[row[1]]+","+id_dic[row[0]]) print(row[0]+","+row[1]+","+row[2]+","+next_list[row[1]]+","+id_dic[row[0]],file=f_out) f_out.close()
出力ファイル。
wiki/index_list1.csv。「単語,index,id,次のindex,ファイルについた単語の番号」
$ head wiki/index_list1.csv つの丸,4827164,931,5291755,13626 バンダイナムコエンターテインメント,7926411,1413,8773576,159 森高夕次,14088537,2290,15289179,11033 UEFAヨーロッパリーグ,17410483,2757,18218333,2362 東海林さだお,24147253,3987,25181487,15986 1315年,34488021,5572,35237307,6828 原子軌道,36621488,5957,37327331,16392 311年,48348477,8347,49019995,19384 銅酸化物,50256325,8644,50980445,18317 ダービーステークス,52737293,9320,53241655,14347
記事データを得る。
以下のスクリプトで記事データを得る。出力は,wiki/1.xml, wiki2.xmlなど。 単語ファイルにつけたidでつく。
import bz2 import xml.etree.ElementTree as ET import sys import copy import re args=sys.argv #index の検索 #出力ファイルノヘッダー #id_name="wiki/"+args[1] #search_term="高城れに" #search_term="ドラえもん" #search_term=args[2].strip().replace("\"","") #word_file=.strip().replace("\"","") #index_file="jawiki-20241001-pages-articles-multistream-index.txt.bz2" with open("wiki/index_list1.csv") as f_in: for i in f_in.readlines(): #exit() i=i.strip().split(",") # ダンプファイルのパス dump_file = 'jawiki-20241001-pages-articles-multistream.xml.bz2' #offset = 1972156087 # インデックスで得たオフセット値 #id= 1771835 offset = int(i[1]) # インデックスで得たオフセット値 id_name= int(i[4]) next_offset = int(i[3]) # インデックスで得たオフセット値 id= int(i[2]) # ダンプファイルをバイナリモードで開き、指定のオフセットから読み込む with open(dump_file, 'rb') as f: print("seek0") f.seek(offset) # オフセットに移動 print("seek1") block = f.read(next_offset-offset) # 5000バイト分読み込む(必要に応じて調整) #block = f.read(1972322566-1972156087) # 5000バイト分読み込む(必要に応じて調整) data=bz2.decompress(block) xml = data.decode(encoding="utf-8") root = ET.fromstring("<root>" + xml + "</root>") page = root.find(f"page/[id='{id}']") # 読み込んだデータから記事を抽出 #start = data.find('<page>') #end = data.find('</page>') + len('</page>') #article = data[start:end] #print(article) #print(xml) tree = ET.ElementTree(page) print(ET.tostring(page,encoding='unicode')) tree.write(f"{id_name}.xml", encoding="utf-8")