具有多语言支持的Wikipedia信息框解析器

时间:2015-12-05 00:01:29

标签: python parsing wikipedia-api

我正在尝试用Python开发一个支持Wikipedia所有语言的Infobox解析器。解析器将获取信息框数据,并将以字典形式返回数据。

词典的键将是描述的属性(例如人口,城市名称等)

问题是维基百科的每种语言的页面内容略有不同。但最重要的是每种语言的API响应结构也可能不同。

例如,英语中'Paris'的API响应包含此信息框:

{{Infobox French commune |name = Paris |commune status = [[Communes of France|Commune]] and [[Departments of France|department]] |image = <imagemap> File:Paris montage.jpg|275px|alt=Paris montage

在希腊语中,'Παρίσι'的相应部分是:

[...] {{Πόλη (Γαλλία) | Πόλη = Παρίσι | Έμβλημα =Blason paris 75.svg | Σημαία =Mairie De Paris (SVG).svg | Πλάτος Σημαίας =120px | Εικόνα =Paris - Eiffelturm und Marsfeld2.jpg [...]

在第二个示例中, {{后面>没有任何'信息框'。此外,在API响应中,name = Paris Πόλη = Παρίσι的确切翻译。 (Πόλη表示城市,而不是名称)

由于响应之间存在这些差异,我的代码失败了。

以下是代码:

class WikipediaInfobox():
    # Class to get and parse the Wikipedia Infobox Data

    infoboxArrayUnprocessed = []    # Maintains the order which the data is displayed.
    infoboxDictUnprocessed = {}     # Still Contains Brackets and Wikitext coding. Will be processed more later...
    language="en"

    def getInfoboxDict(self, infoboxRaw): # Get the Infobox in Dict and Array form (Unprocessed)
        if infoboxRaw.strip() == "":
            return {}
        boxLines = [line.strip().replace("  "," ") for line in infoboxRaw.splitlines()]
        wikiObjectType = boxLines[0]
        infoboxData = [line[1:] for line in boxLines[1:]]
        toReturn = {"wiki_type":wikiObjectType}
        for i in infoboxData:
            key = i.split("=")[0].strip()
            value = ""
            if i.strip() != key + "=":
                value=i.split("=")[1].strip()
            self.infoboxArrayUnprocessed.append({key:value})
            toReturn[key]=value
        self.infoboxDictUnprocessed = toReturn
        return toReturn

    def getInfoboxRaw(self, pageTitle, followRedirect = False, resetOld=True): # Get Infobox in Raw Text
        if resetOld:
            infoboxDict = {}
            infoboxDictUnprocessed = {}
            infoboxArray = []
            infoboxArrayUnprocessed = []

        params = { "format":"xml", "action":"query", "prop":"revisions", "rvprop":"timestamp|user|comment|content" }
        params["titles"] = "%s" % urllib.quote(pageTitle.encode("utf8"))
        qs = "&".join("%s=%s" % (k, v)  for k, v in params.items())
        url = "http://" + self.language + ".wikipedia.org/w/api.php?%s" % qs
        tree = etree.parse(urllib.urlopen(url))
        revs = tree.xpath('//rev')
        if len(revs) == 0:
            return ""

        if "#REDIRECT" in revs[-1].text and followRedirect == True:
            redirectPage = revs[-1].text[revs[-1].text.find("[[")+2:revs[-1].text.find("]]")]
            return self.getInfoboxRaw(redirectPage,followRedirect,resetOld)
        elif "#REDIRECT" in revs[-1].text and followRedirect == False:
            return ""

        infoboxRaw = ""
        if "{{Infobox" in revs[-1].text:    # -> No Multi-language support:
            infoboxRaw = revs[-1].text.split("{{Infobox")[1].split("}}")[0]
        return infoboxRaw

    def __init__(self, pageTitle = "", followRedirect = False): # Constructor
        if pageTitle != "":
            self.language = guess_language.guessLanguage(pageTitle)
            if self.language == "UNKNOWN":
                self.language = "en"
            infoboxRaw = self.getInfoboxRaw(pageTitle, followRedirect)
            self.getInfoboxDict(infoboxRaw)  # Now the parsed data is in self.infoboxDictUnprocessed

此代码的某些部分位于this blog...

我不想重新发明轮子,所以也许有人有一个很好的解决方案来支持多语言和整洁解析维基百科的信息框部分。

我见过许多替代品,比如DBPedia或MediaWiki推荐的其他解析器,但我还没有找到任何适合我需要的解析器。我还想避免使用BeautifulSoup来抓取页面,因为在某些情况下它可能会失败,但如果有必要,它会这样做。

如果事情不够清楚,请询问。我想尽我所能帮助。

1 个答案:

答案 0 :(得分:0)

如果你想获得结构化数据,那么维基数据绝对是第一选择,无论如何,如果将来你需要解析维基百科文章中的数据,特别是当你使用Python时,我可以推荐mwparserfromhell这是一个旨在解析wikitext的python库,它有一个提取模板及其属性的选项。这不会直接解决您的问题,因为多种语言中的多个模板肯定会有所不同,但如果您继续尝试解析wikitext,这可能会很有用。