You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取维基百科分类的父分类?含API与Dump解析场景

解决方案:获取维基百科分类的父分类

我来帮你搞定维基百科分类父分类提取的问题,针对你提到的两个业务场景,分别给出实用的解决方案,同时优化你用wptools的代码,解决父分类提取的难点:

场景1:通过维基百科API根据文章ID提取父分类ID

这个场景可以分两步走:先通过文章ID拿到所属的所有分类,再逐个查询每个分类的父分类。这里用requests直接调用维基百科API,比wptools更灵活可控:

import requests
import time

def get_page_categories(page_id):
    """根据文章ID获取该文章的所有分类(不含前缀)"""
    api_url = "https://en.wikipedia.org/w/api.php"
    params = {
        "action": "query",
        "pageids": page_id,
        "prop": "categories",
        "format": "json",
        "cllimit": "max"  # 一次性获取所有分类
    }
    response = requests.get(api_url, params=params)
    data = response.json()
    categories = []
    for page_data in data["query"]["pages"].values():
        if "categories" in page_data:
            # 去掉"Category:"前缀,同时过滤隐藏分类(可选)
            categories = [
                cat["title"].replace("Category:", "") 
                for cat in page_data["categories"] 
                if not cat.get("hidden")
            ]
    return categories

def get_category_parent_ids(category_name):
    """获取单个分类的父分类ID(以及父分类名称)"""
    api_url = "https://en.wikipedia.org/w/api.php"
    params = {
        "action": "query",
        "titles": f"Category:{category_name}",
        "prop": "categories",
        "format": "json",
        "cllimit": "max",
        "clshow": "!hidden"  # 排除隐藏分类
    }
    response = requests.get(api_url, params=params)
    data = response.json()
    parent_info = []
    for page_data in data["query"]["pages"].values():
        if "categories" in page_data:
            for cat in page_data["categories"]:
                parent_name = cat["title"].replace("Category:", "")
                parent_info.append({
                    "parent_id": cat["pageid"],
                    "parent_name": parent_name
                })
    # 去重
    return list({item['parent_id']: item for item in parent_info}.values())

# 组合使用:根据文章ID获取所有分类的父分类ID
def get_page_category_parents(page_id):
    categories = get_page_categories(page_id)
    all_parent_ids = {}
    for cat in categories:
        all_parent_ids[cat] = get_category_parent_ids(cat)
        time.sleep(1)  # 避免触发API频率限制
    return all_parent_ids

场景2:解析维基百科Dump后获取细分类的父分类

如果你已经解析了Dump拿到文章对象(比如{'Title':'The Dark Knight (film)', 'id':4276475, 'Categories':['2008 films','English-language films','2000s action thriller films',...]}),核心需求是给这些细分类找父分类,比如从"2000s action thriller films"得到"action thriller films"。

方案1:API批量查询

可以直接复用场景1中的get_category_parent_ids函数,遍历文章的分类列表即可。但如果处理大量文章,频繁调用API会受限,建议:

  • 批量收集所有需要查询的分类,去重后再批量请求(维基百科API支持多标题查询,用titles=Category:A|Category:B的格式)
  • 添加请求间隔,避免被封IP

方案2:本地数据库查询(高效大规模处理)

如果数据量很大,推荐使用维基百科的分类链接Dump文件(比如categorylinks.sql.gz),导入本地MySQL/PostgreSQL数据库后直接查询,效率提升N倍:

  1. 下载对应版本的categorylinks.sql.gz和page.sql.gz(前者存分类关联,后者存页面ID和标题映射)
  2. 导入数据库后,用SQL查询直接父分类:
-- 先获取细分类的页面ID
SELECT page_id FROM page 
WHERE page_title = '2000s_action_thriller_films' 
AND page_namespace = 14; -- 14是分类的命名空间

-- 再根据页面ID查父分类
SELECT cl_to, (SELECT page_id FROM page WHERE page_title = cl_to AND page_namespace =14) as parent_id
FROM categorylinks 
WHERE cl_from = [上面拿到的页面ID]
AND cl_type = 'subcat'; -- 只取子分类关联,排除页面关联

优化wptools的使用,解决父分类提取难点

你之前的wptools代码只获取了分类页面,但没提取父分类。这里优化一下,直接从分类页面的返回数据中提取父分类,还支持递归获取所有上层父分类:

import wptools
import time

def get_direct_parent_categories(category_name, skip_hidden=True):
    """用wptools获取分类的直接父分类"""
    # 初始化分类页面,silent=True关闭日志输出
    cat_page = wptools.page(f"Category:{category_name}", silent=True)
    cat_page.get_more()
    parent_cats = []
    for cat in cat_page.data.get('categories', []):
        # 处理隐藏分类的标记
        if "(hidden)" in cat and skip_hidden:
            continue
        clean_name = cat.replace("Category:", "").replace(" (hidden)", "")
        parent_cats.append(clean_name)
    return list(set(parent_cats))

def get_all_parent_categories(category_name, skip_hidden=True, visited=None):
    """递归获取分类的所有上层父分类(直到顶级分类)"""
    if visited is None:
        visited = set()
    # 避免循环引用(比如某些分类互相引用)
    if category_name in visited:
        return []
    visited.add(category_name)
    direct_parents = get_direct_parent_categories(category_name, skip_hidden)
    all_parents = direct_parents.copy()
    # 递归获取每个父分类的上层分类
    for parent in direct_parents:
        all_parents.extend(get_all_parent_categories(parent, skip_hidden, visited))
        time.sleep(0.5)  # 控制请求频率
    return list(set(all_parents))

# 示例:获取"2000s action thriller films"的所有父分类
all_parents = get_all_parent_categories("2000s action thriller films")
print(all_parents)
# 输出会包含"action thriller films"、"2000s thriller films"等上层分类

关键注意事项

  • API频率限制:维基百科API对非认证用户有请求频率限制,建议添加time.sleep(),或者注册账号使用OAuth认证提升限额
  • 隐藏分类过滤:大部分业务场景不需要隐藏分类(比如维护类、删除类分类),记得过滤
  • 循环引用处理:少数分类可能存在循环引用,递归时一定要加visited集合避免无限递归

内容的提问来源于stack exchange,提问作者DsCpp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 11:32:30