列出一个类别和子类别中的所有维基百科文章

时间:2014-02-01 11:13:50

标签: php wikipedia mediawiki-api

有没有办法在一个类别中获取所有维基百科文章的列表,包括所有子类别?

我尝试使用PHP脚本从类别页面中提取链接,但似乎没有可能获得包括子类别在内的所有文章。

2 个答案:

答案 0 :(得分:4)

您可以使用MediaWiki API执行此操作,特别是list=categorymembers

这是一个随机的例子:

上面的链接将以XML格式为您提供Category:Defunct airports in Prince Edward Island中所有页面的列表(默认情况下打印得非常方便)。您可以通过在网址上附加适当的参数(例如format=xmlformat=json),从各种机器可读的output formats中进行选择。

请注意,通常,上面显示的查询将包含该类别中的所有页面,包括文章和子类别。您只能通过包含参数cmnamespace=0将其限制为文章,但之后您将错过任何子类别。 (不过,您可以随时使用cmnamespace=14单独获取这些内容。)

您可能需要该信息的原因是list=categorymembers查询本身将递归到子类别中,因此如果您需要,则必须自己执行此操作。但是,如果你这样做,请注意不要陷入任何类别循环,并确保对结果进行健全性检查 - 很容易得到方式比你预期更多的页面完整的子类别遍历。

此外,默认情况下,单个categorymembers查询最多可获得10个结果。您可以通过在查询中包含参数cmlimit=max将该限制增加到500(或5000,如果您碰巧有权访问维基百科上的bot-flagged account,但即使这样,也可能会削减非常大的类别关闭。如果发生这种情况,查询结果将包含query continuation部分,该部分将告诉您(或您的MW API client library)如何使用其他查询获取其余页面。


编辑:我有点想念你特别询问在子类别中获取文章的事实。这里有一些基本的(未经测试的)示例代码,说明如何使用Apibot 0.40桥接接口(我只是随机选择),因为它看起来像一个不错的PHP MW API客户端库,所以我不需要担心查询延续等细节:

function pages_under_category ( $category ) {
    global $bridge;  // I'll assume you've set this up in advance

    $queue = array( $category );  // categories to fetch
    $seen  = array( $category );  // categories already seen
    $pages = array();  // result pages (format: $title => array( $cat, ... ))

    while ( !empty( $queue ) ) {
        $cat = array_shift( $queue );

        $query = $bridge->query_list_categorymembers();
        $query->title = $cat;  // assume "Category:" prefix is included

        // fetch the contents of the category
        $query_result = $query->xfer();
        while ( $query_result ) {
            foreach ( $query->data as $page_data ) {

                $title = $page_data['title'];
                $namespace = $page_data['ns'];

                if ( $namespace == 0 ) {      // it's an article!
                    if ( !isset( $pages[$title] ) ) {
                        $pages[$title] = array();
                    }
                    $pages[$title][] = $cat;  // record where we found it
                }
                else if ( $namespace == 14 ) {  // it's a subcategory
                    if ( !in_array( $title, $seen ) ) {
                        $seen[] = $title;  // avoid loops!
                        $queue[] = $title;
                    }
                }
            }
            $query_result = $query->next();
        }
    }
    return $pages;
}

您可能想要添加到上面代码中的一个功能是对结果大小/迭代次数的某种限制,因此即使递归检索以某种方式找到它的路径,比如Category:Contents,它也是如此将在某个时候停止尝试列出维基百科上的每一页。

答案 1 :(得分:0)

这可以通过PetScan完成,例如,在示例https://petscan.wmflabs.org/?psid=19820

您可以选择进入子类别的深度,添加esarch术语和/或排除属于指定其他类别的页面。