将所有维基百科解析为离线百科全书

2020-11-29 05:22:54

当我遇到\ u2013这样的转义unicode文字时,很快就变得棘手。他们无处不在。

因此,我又写了两个函数来尝试解决方括号中的内容。这些是链接,引用和图片之类的东西。由于我需要纯文本的Wikipedia,因此我真的只需要将其全部删除。

def remove_double_curly(text):而True:before = len(text)text = re。如果= =之后,则sub =(len,text)之后的sub(``,'',text)如果返回== after:返回文本def remove_double_brackets(文本):而True:before = len(文本)double_brackets = re。在double_brackets中查找db的findall('\ [\ [。*?\] \]',text):if'|'在db中:new = db。 split('|')[-1]。 strip(']')text = text。替换(db,new)else:new = db。跳闸 ( '[' )。 strip(']')text = text。如果= =之后,则在= len(文本)之后替换(db,new):返回文本

这些功能正常运行。您可能会注意到curl函数中的克拉^。这告诉它匹配另一个开口花括号之外的任何东西。这迫使它找到最内层的嵌套花括号。再次,这主要工作,但失败了几次,我放弃尝试找出原因。方括号略有不同,因为它们通常不嵌套,但是内部语法可能有几处不同。我选择了最简单的方法,即使如此,它也遗漏了一些东西。不知道为什么。

我想我应该倒带一些背景。维基百科的转储文件非常庞大。即使我的桌面上有32GB的RAM,我也一次只加载一个块就很快耗尽了内存。因此,这意味着我必须逐行读取每个文件。像这样:

打开(file,'r',encoding ='utf-8')作为infile:for infile中的行:line = literal_eval(f'“”“ {line}”“”))#这可以工作...有时如果第''行:#新文章文章=” elif''第行:#文章文章末尾+ =行

这对于一次只读取一个东西非常有用。 Wikipedia转储的一个一致性是每个页面分别以和开头和结尾,这是一个很好的界限。因此,我尝试使用ast.literal_eval处理Unicode文字。剧透:有效。一点点。此功能经常出于各种原因而被炸毁。

我最终放弃了手动解析WikiMedia Text的过程,发现了一些现存的解析器。首先是wikitextparser,在撰写本文时,它一直得到积极维护。其次是简单的html2text,它使一些东西首先遗漏了。这些预制的解析器非常棒,因为它们不需要我使用自己的任何脑力!但是,它们比我的正则表达式替换功能要慢得多。但是,这是无法避免的。

[{“ id”:“ 4413617”,“ text”:“ Samajtantrik Sramik阵线是孟加拉国的一个全国工会联合会。它隶属于世界工会联合会...”,“ title”:“ Samajtantrik Sramik Front“},{” id“:” 2618“,” text“:” Aeacus(;也拼写为Eacus;古希腊语:\ u 0391 \ u 1f30 \ u 03b1 \ u 03ba \ u 03cc \ u 03c2 Aiakos或Aiacos)是埃伊纳岛的神话般的国王...“,” title“:” Aeacus“},{” id“:” 3201“,” text“:” [[File:Global_Temperature_And_Forces.svg | thumb | upright = 1.35 |正确| NASA观测到的温度与IPCC用作工业化前基线的1850 \ u 20131900平均温度。工业时代导致全球温度升高的主要动力是人类活动,自然力增加了变化性图3.1面板2,图3.3面板5。]]]最近气候变化的归因是“,”标题“:”最近气候变化的归因“},]

它更清洁并且朝着正确的方向移动,但我仍然必须可靠地确定字面值,并且一些方括号也使它得以通过。这些预制的解析器要慢得多,但是清理Wikipedia文章的一个优点是,它们最终没有标记就小得多。如果您只想以纯文本格式存储所积累的知识,那么最终的结果只是它的一小部分。

我可以在这里和那里容忍一些畸变,但是我内心的完美主义者想做得更好。无论如何,这是我今天的脚本:

导入重新导入os从uuid导入json从uuid导入uuid4从html2text导入gc导入html2text作为htt导入wikitextparser as wtp archive_dir ='d:/ WikipediaArchive /'dest_dir ='D:/ enw​​iki20201020 /'chars_per_file = 40 * 1000 * 1000#创建一个大小一致的块(每个块约40MB)def dewiki(文本):text = wtp。解析(文本)。 plain_text()文本= htt(文本)文本=文本。 replace('\\ n','')text = re。 sub('\ s +','',text)返回文本def analytics_chunk(text):try:如果text中的'')[1]。split('')[0]如果标题中的':':#这是一个演讲,类别或其他(不是真实的文章),返回无序列号=文本。split('')[1]。split('')[0] content =文本。split('',maxsplit = 1)[1] content = dewiki(con​​tent)return {'title':title,'text':content,'id':serial}除了:返回None def save_data(data) :如果len(data)== 0:返回文件名= dest_dir + str(uuid4())+'.json'print('Saving:\ t',filename)打开(filename,'w',encoding ='utf -8')作为outfile:json。dump(data,outfile,sort_keys = True,indent = 1)def main(file):print(file)outdata = list()article =''total_le n = 0并以infile格式打开(archive_dir + file,'r',encoding ='utf-8'):for infile中的行:如果行中的'':#新文章以article =''elif''行中:#文章结尾doc = analytics_chunk(文章),如果doc:outdata。 append(doc)total_len + = len(doc ['text'])如果total_len> = chars_per_file:save_data(outdata)outdata = list()total_len = 0否则:如果+ __name__ =='__main__ ':用于os中的文件。 listdir(archive_dir):如果file中的'bz2':继续main(file)gc。搜集 ()

这不是最优雅的解决方案,但仅需100多行代码,它将解析几乎所有Wikipedia并将其保存为40MB的JSON块。运行此脚本如下所示:

(基本)C:\ OfflineWikipedia> python jsonify_wikipedia.pyenwiki-20201020-pages-meta-current1.xml-p1p41242保存:D:/enwiki20201020/95952e69-ed97-4807-bd47-f7019242a5dd.json保存:D:/ enw​​iki20201073 / 7fbc8 -4e92-9fe6-24be8076d71e.json保存:D:/enwiki20201020/df3de04a-b088-4daa-94e5-6368d9c631a9.json保存:D:/ enw​​iki20201020 / dc8360a0-4d0f-45cd-93c9-4530cf5a8265 / json420102020:20 52ae-41f7-a5d5-2b2f1509b663.json保存:D:/enwiki20201020/6eb66a52-3b49-47bb-a74f-c4b9e6f4578f.json保存:D:/ enw​​iki20201020 / 356f8242-fc36-4517-be32-7dd9e7af620 / wiki:feb20307 / -223f-4a8b-a940-551cbc3cd21a.json保存:D:/enwiki20201020/d8546da5-762c-48af-bba1-c8dacf92d257.json保存:D:/ enw​​iki20201020 / 4d25c46b-0d1d-4031-94f6-071c39fa91a5 / json保存20:D 511f5c91-6347-449d-a1a3-ce384988d497.json保存:D:/enwiki20201020/cad2328c-dcaf-4e8e-bc6b-c68016e32ebc.jsonenwiki-20201020-pages-meta-current10.xml-p4045403p5399366保存:D:/ enw​​ikib20d 4548-44e8-b7be-e3fe813272f2.json保存:D:/enwiki20201020/baca8df6-8a6b-4c57-a3de-cce4cacceac0.json保存:D:/ enw​​iki20201020 / 919c6b37-b18f-46e5-917b-6e38553e7c26。

每个文章都可以由UUID引用以获取文件名和整数ID号。这意味着所有Wikipedia都可以轻松索引并且易于阅读。当然,由于删除上下文信息(例如链接和图片)会造成一些损失。但是无所谓。您仍然可以获得> 95%的信息。

我是个白痴。但是,不用说。只是问我以前的任何一个浪漫伴侣。

无论如何,unicode文字不是来自读取方,而是来自json.dump。所以解决方案很简单:

那解决了我的大多数问题。我认为调整了操作顺序,并将一些功能重新添加到我的dewiki功能中。

def dewiki(文本):text = remove_double_curly(文本)#删除大多数文本= remove_double_brackets(文本)#删除大多数[[]] text = wtp。解析(文本)。 plain_text()#解析出MediaWiki text = htt(text)#解析出任何剩余的HTML text = text。 replace('\\ n','')#用单个空格text = re替换任何换行符。 sub('\ [\ [','',text)#删除所有残余[[text = re。 sub('\] \]','',text)#删除所有剩余的]] text = re。 sub('\ s +','',text)#将多余的空格压缩为一个空格,返回文本

最后一招-头衔。我还没有在那里进行任何清理。原来那里有一些HTML,因此我在标题解析部分添加了以下内容:

现在,我的离线Wikipedia很好而且干净,我可以继续进行下一个实验-索引,搜索和平方。