维基百科哲学游戏图在python和R

时间:2011-11-08 12:07:48

标签: python parsing wikipedia


所以我对python来说比较新,为了学习,我已经开始编写一个上传到维基百科的程序,在随机文章的概述部分找到第一个链接,跟随该链接并继续前进,直到它进入一个循环或查找哲学页面(详细为here),然后为新的随机文章重复此过程指定的次数。然后我想以某种形式的有用数据结构收集结果,这样我就可以使用Rpy library将数据传递给R,这样我就可以绘制某种网络图(R很擅长绘制类似的东西表示所访问页面的每个节点,以及从起始文章到哲学页面的路径箭头。

所以我没有问题让python从wiki返回结构合理的html但是有一些我无法弄清楚的问题。到目前为止,我已经使用lxml库中的cssselector选择了第一个链接。它选择第一个链接(在一个标记中)作为p标记的直接后代,它是div标记的直接后代,其类似于“mw-content-ltr”:

    user_agent = 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT)'
    values = {'name' : 'David Kavanagh',
      'location' : 'Belfast',
      'language' : 'Python' }
    headers = { 'User-Agent' : user_agent }
    encodes = urllib.urlencode(values)
    req = urllib2.Request(url, encodes, headers)
    page = urllib2.urlopen(req)
    root = parse(page).getroot()
    return root.cssselect("div.mw-content-ltr>p>a")[0].get('href')

此代码驻留在我用于查找页面中第一个链接的函数中。它大部分都有效,但问题是如果第一个链接在某个其他标记内,而不是像p标记的直接后代,比如说b标记或其他东西,那么我会想念它。正如你从上面的wiki文章中看到的那样,斜体或括号内的链接不符合游戏的条件,这意味着我从来没有得到斜体链接(好)但经常得到括号内的链接(坏)和有时会错过一个页面上的第一个链接,比如椅子上的第一个链接,即凳子,但它是粗体,所以我不明白。我已经尝试删除直接后代规定,但后来我经常得到概述部分“上方”的链接,这些链接通常位于侧边框,ap标记,表格中,与概览部分相同的div中。

所以问题的第一部分是:

如何使用cssselectors或其他函数或库来选择概述部分中不在括号内或斜体中的第一个链接。我想过使用正则表达式查看原始html,但这似乎是一个非常笨重的解决方案,我认为可能有一些更好的东西,我没有想到。

所以目前我将结果存储在列表列表中。所以我有一个名为paths的列表,其中有一些列表包含包含wiki文章标题的字符串。

问题的第二部分是: 如何遍历此列表列表以表示多个收敛路径?存储这样的结果是个好主意吗?由于结束图应该看起来像一个颠倒的树,我想要制作某种树类,但这对于概念上相当简单的事情来说似乎很多工作。

非常感谢任何想法或建议 干杯,
戴维

2 个答案:

答案 0 :(得分:4)

我只想回答第二个问题:

首先,保持一个dict将一个维基百科文章标题映射到下一个。这样可以轻松快速地检查我是否已经找到了您之前找到过的文章。基本上这只是存储有向图的顶点,由它们的起源索引。

如果你达到Python dict效率不高的程度(它确实有很大的内存开销,一旦你有数百万项内存可能是一个问题),你可以找到一个更有效的图形数据结构,以适应你的需要。

修改

好的,我也会回答第一个问题......

对于第一部分,我强烈建议使用MediaWiki API而不是获取HTML版本并解析它。 API允许查询某些类型的链接,例如仅仅是维基链接或仅仅是语言间链接。此外,此API有Python client libraries,应该可以简单地使用Python代码。

如果网站的HTML提供了全面且记录良好的API,请不要对其进行解析!

答案 1 :(得分:1)

对于第一部分,不可能找到带有css选择器的括号,因为就html而言,括号只是文本。

如果我是你,我会使用选择器来查找对游戏有效的所有相关段落元素。然后,我将查看段落元素的文本,并删除任何无效的文本 - 例如,括号之间的任何内容,以及斜体标记之间的任何内容。然后,我会在此处理过的文本中搜索我需要的链接元素。这比手动处理整个html文档稍微好一些。

我不确定我是否完全遵循你在第二部分所做的事情,但至于将这个搜索的结果表示为树:这是一个坏主意,因为你正在寻找周期,树木不能代表。

对于数据结构,我会有“节点”列表,其中一个节点代表一个页面,并且有一个URL和一个出现次数。然后,我使用强力算法来比较节点列表 - 如果两个列表的节点相同,则可以合并它们,从而增加每个镜像节点的“出现次数”。

我不会使用标准的python'list',因为它无法循环回来。也许创建自己的链表实现来包含节点。