用Python和R绘制维基百科哲学游戏图表

5 投票
2 回答
684 浏览
提问于 2025-04-17 05:51


我刚开始学习Python,为了提高自己,我写了一个程序,这个程序会去维基百科上随机找一篇文章,找到概述部分的第一个链接,然后跟着这个链接一直点下去,直到进入一个循环或者找到哲学页面(具体可以参考这里)。接着,我会对新的随机文章重复这个过程,指定次数。最后,我想把结果存储在某种有用的数据结构中,这样我就可以通过Rpy库把数据传给R,绘制一个网络图(R在绘制这类图方面很不错),图中的每个节点代表访问过的页面,箭头则表示从起始文章到哲学页面的路径。

我能顺利地用Python获取维基百科的结构化HTML,但有些问题我还没搞明白。到目前为止,我使用lxml库的css选择器来选择第一个链接。这个选择器是选取在p标签下的第一个a标签链接,而这个p标签又是class为“mw-content-ltr”的div标签的直接子标签,像这样:

    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标签里,我就会漏掉它。就像上面的维基文章,斜体字或括号里的链接不算在内,这意味着我不会得到斜体链接(这很好),但我经常会得到括号里的链接(这不好),有时还会漏掉像“椅子”文章中的第一个链接,那个链接是“凳子”,但它是加粗的,所以我就没抓到。我试过去掉直接子标签的限制,但这样我经常会得到在概述部分“上面”的链接,通常是在侧边框、p标签里、表格中,或者在同一个div里的概述部分。

所以我第一个问题是:

我该如何使用css选择器或其他函数或库,选择概述部分中不在括号里或不为斜体的第一个链接。我考虑过用正则表达式来查找原始HTML,但这似乎是个很笨重的解决方案,我觉得可能还有其他更好的方法我没想到。

目前我把结果存储在一个列表的列表中。我有一个叫“paths”的列表,里面有包含维基文章标题的字符串列表。

第二个问题是: 我该如何遍历这个列表的列表,以表示多个汇聚的路径?这样存储结果是否是个好主意?因为最终的图应该像个倒立的树,我考虑过做一个树的类,但这似乎是个很复杂的工作,而从概念上讲,这其实是相对简单的。

任何想法或建议都非常感谢。
谢谢,
Davy

2 个回答

1

首先,想用CSS选择器找到括号是不可能的,因为在HTML看来,括号只是普通的文本。

如果我是你,我会用选择器找到所有和游戏相关的段落元素。然后,我会查看这些段落里的文本,去掉那些不合法的内容,比如括号里的东西和斜体标签里的内容。接着,我会在处理过的文本中寻找我需要的链接元素。这样做比手动处理整个HTML文档要好一些。

至于你第二部分的做法,我不是很明白,但关于把搜索结果表示成树形结构,这个主意不好,因为你在寻找循环,而树形结构是不能表示循环的。

对于数据结构,我会有一个“节点”的列表,每个节点代表一个页面,包含一个网址和出现次数。然后我会用一种暴力算法来比较这些节点的列表——如果两个列表中有相同的节点,就可以合并它们,增加每个相同节点的“出现次数”。

我不会使用标准的Python“列表”,因为它不能自我循环。也许可以自己实现一个链表来存放这些节点。

4

我来回答第二个问题:

首先,你可以建立一个字典,把一个维基百科文章的标题映射到下一个文章的标题。这样做可以很方便、很快速地检查你是否已经访问过某篇文章。其实这就是在存储一个有向图的节点,用它们的来源来索引。

如果你发现用Python的字典效率不够高(因为当你有几百万个项目时,内存占用会变得很大),你可以寻找更高效的图数据结构来满足你的需求。

编辑

好吧,我也来回答第一个问题...

对于第一部分,我强烈建议使用MediaWiki API,而不是获取HTML版本然后解析它。这个API可以让你查询特定类型的链接,比如只查维基内部链接或者只查不同语言的链接。此外,还有Python客户端库可以使用这个API,这样在Python代码中使用就会很简单。

如果网站提供了全面且文档齐全的API,就不要去解析它的HTML了!

撰写回答