Open-Assistant 知乎 KOL 问答数据集构建指南:爬取、清洗、转换与上传全流程
2026/9/19 7:57:24 网站建设 项目流程

Open-Assistant 知乎 KOL 问答数据集构建指南:爬取、清洗、转换与上传全流程

【免费下载链接】Open-AssistantOpenAssistant is a chat-based assistant that understands tasks, can interact with third-party systems, and retrieve information dynamically to do so.项目地址: https://gitcode.com/gh_mirrors/op/Open-Assistant

导读

本文围绕 Open-Assistant 项目中的中文高质量问答数据源 Zhihu KOL 数据集卡片 展开,完整讲解如何从知乎抓取 KOL(关键意见领袖)的问答内容,将其转换为 Open-Assistant 训练管线可直接消费的 Instruction 格式,并以 Parquet 形式发布到 Hugging Face Hub。读完本文,你将掌握单用户 url_token 爬取、圆桌话题批量爬取、数据格式转换、质量过滤与上传发布的全套实战方案,并能将这套流程复用到其他中文问答站点或社区数据的采集任务中。

数据集概览:为什么需要知乎 KOL 问答数据

背景与定位

Open-Assistant 旨在训练一个能够理解任务、与第三方系统交互并动态检索信息的对话式助手。高质量、多样化的训练数据是其核心燃料,仓库根目录的 data/datasets/README.md 明确指出:该仓库致力于提供可用于训练 OpenAssistant 模型的多样化、易获取的数据集集合,覆盖广泛的主题、语言与任务。

知乎(Zhihu)是中国最流行的问答社区,天然包含海量的「问题—回答」二元组,这与 Instruction 数据集的形态高度契合。本数据集当前阶段聚焦 KOL(Key Opinion Leader,意见领袖)的回答,原因在于:

  • KOL 回答通常更长、更结构化、信息密度更高,更适合作为监督微调的目标输出;
  • KOL 内容的点赞数等互动指标可以反哺元数据(如回答质量筛选);
  • 项目计划后续逐步扩展到更广泛的话题和普通用户内容,当前版本只收录 KOL 数据作为起步。

从仓库注册表 data/datasets/init.py 可以看到,zhihu-kol已被注册到INSTRUCTION_DATASETS字典中,对应 Hugging Face 仓库wangrui6/zhihu-kol,即该数据集已经进入 Open-Assistant 的正式指令数据集清单。

数据形态示例

数据集的「问题—回答」对直接以中文呈现,例如 README 中给出的两个典型样本:

Q: ChatGPT 这个项目会开源吗? A: 别开源了,开源就有中国名字了: HarmonyGPT.2014年6月21日,特斯拉公司在全球范围内公开了271项专利... Q: TensorFlow 真的要被 PyTorch 比下去了吗? A: 当我找到一个tf的代码,我的第一反应就是这货大概率跑不起来.

这类样本真实反映了社区用户的提问风格和 KOL 的个性化回答风格,是训练中文指令跟随能力(尤其是互联网技术话题)的天然语料。

环境准备:依赖安装与 Playwright 浏览器

开始抓取前需要准备两件事:Python 依赖和 Playwright 无头浏览器。

安装 Python 依赖

项目提供了完整的依赖清单 data/datasets/zhihu-kol/requirements.txt,直接安装即可:

pip install -r requirements.txt

其中与抓取链路直接相关的核心依赖包括:

依赖版本用途
playwright1.31.0无头浏览器驱动,用于圆桌话题页面渲染与链接采集
requests2.28.2知乎 API 与页面请求
beautifulsoup44.11.2HTML 解析,提取回答正文
pandas1.5.3数据表处理与 CSV 输出
pyarrow11.0.0Parquet 格式转换
datasets2.10.0Hugging Face 数据集加载与上传
huggingface-hub0.12.1HF Hub 推送底层支持
multitasking0.0.11多任务并发抓取回答内容
retry0.9.2网络请求自动重试
tqdm4.64.1抓取进度可视化
loguru0.6.0圆桌抓取日志记录

注意requirements.txt中还捆绑了大量 Jupyter/科学计算依赖(如jupytermatplotlibtensorboard等),实际生产抓取时可按需裁剪。

安装 Playwright 浏览器及系统库

playwright install

若系统缺少浏览器运行所需的基础库,需要补充安装(以 Ubuntu/Debian 为例):

sudo apt-get install libatk1.0-0 libatk-bridge2.0-0 libcups2 libatspi2.0-0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 libgbm1 libxkbcommon0 libpango-1.0-0 libcairo2 libasound2

这些库为 Chromium 在无头(headless)模式下渲染页面所必需;缺少时 Playwright 会因启动浏览器失败而报错。注意,在scrape_by_topic.py中浏览器以headless=False(有头模式)启动,这是因为知乎页面需要真实浏览器环境来通过部分反爬校验。

单用户抓取:基于 url_token 的 KOL 回答采集

url_token 与 uid 的获取

知乎用户的个人主页 URL 形如https://www.zhihu.com/people/la-ge-lang-ri-96-69,其中最后一段la-ge-lang-ri-96-69即为该用户的url_token。抓取的第一步是将其转换为 API 所需的数字uid

main.py 中的get_uid_by_url_token函数实现这一转换:它构造一组模拟浏览器请求的 headers(包含user-agentx-requested-with: fetchoriginreferer等字段),请求https://api.zhihu.com/people/{url_token},并从响应的 JSON 中提取id字段:

url = "https://api.zhihu.com/people/" + url_token response = requests.get(url, headers=headers) uid = response.json()["id"]

由于知乎对无登录 API 请求存在限流,该函数未做重试保护;若调用失败,get_user_answers外层会捕获异常并返回空 DataFrame,脚本随后打印「url_token 可能有误!」并退出。

拉取用户回答元数据列表

get_user_answers(url_token, max_count=100000)是单用户抓取的核心。它使用 iOS 端请求头模拟知乎 App 客户端,调用分页接口:

url = f"https://api.zhihu.com/members/{uid}/answers" params = (("limit", "20"), ("offset", str(offset)))

关键行为包括:

  • 分页逻辑:每页limit=20条,通过offset递增翻页,直到offset >= total或超过max_count(默认 100000,即几乎不设上限)时停止;
  • 自动重试:函数上装饰了@retry(tries=3),网络异常时最多重试 3 次;
  • 字段提取:通过operations映射表,从原始 JSON 中抽取 9 个字段(含嵌套字段),列名全部使用中文:
输出列名来源字段说明
作者名称author.nameKOL 显示名
作者IDauthor.idKOL 数字 uid
作者tokenauthor.url_tokenKOL url_token
回答点赞数voteup_count可用于回答质量评估
回答时间created_time创建时间戳
更新时间updated_time最后更新时间戳
回答IDurl末段回答唯一 ID(aid)
问题IDquestion.id问题唯一 ID(qid)
问题内容question.title问题标题文本

其中「回答ID」通过x["url"].split("/")[-1]从回答链接中截取;「问题内容」直接取自问题的 title。该函数返回一个列名均为中文的 pandas DataFrame,为后续正文抓取提供索引。

抓取回答正文

拿到「问题ID + 回答ID」后,get_answer_content(qid, aid)通过移动端页面请求https://www.zhihu.com/question/{qid}/answer/{aid},再用 BeautifulSoup 解析 HTML:

soup = BeautifulSoup(response.text, "html.parser") content = " ".join([p.text.strip() for p in soup.find_all("p")])

即将页面内所有<p>段落文本拼接成一段连续文本。需要注意:这种粗暴拼接会丢失段落结构与列表、代码块等富文本信息;同时 README 示例中可看到回答内容会保留原始换行与排版,实际以页面解析结果为准。

并发落盘与格式转换

save_answers_to_csv将上述两步串联成一个端到端流程:

  1. 调用get_user_answers获取元数据 DataFrame,为空则报错返回;
  2. 对每一行「问题ID + 回答ID」组合,使用multitasking.task装饰的start(qid, aid)并发抓取正文,每个任务带@retry(tries=3)重试;
  3. 通过tqdm显示进度,multitasking.wait_for_tasks()等待全部并发任务结束;
  4. 问题ID回填回答内容(源码注释特别强调使用 qid 作为 key,确保并发下 qid 与 aid 一一对应);
  5. 调用reformat_csv_to_openassistant转换为 Open-Assistant 标准格式:
    • INSTRUCTION← 问题内容
    • RESPONSE← 回答内容
    • SOURCE← 固定为"Zhihu"
    • METADATA← JSON 字符串,包含「回答点赞数」和「回答时间」两项
  6. encoding="utf-8-sig"编码写入 CSV(带 BOM,便于 Excel 等工具直接打开中文内容)。

脚本主入口默认抓取 url_token 为nicole-97-93的 KOL 并保存为nicole-97-93.csv,实际使用时可修改main.py底部的url_token变量:

# 知乎用户的 url_token # 例如主页为 : https://www.zhihu.com/people/la-ge-lang-ri-96-69 的用户 # 其 url_token 为 la-ge-lang-ri-96-69 # url_token = 'la-ge-lang-ri-96-69' url_token = "nicole-97-93" # 回答数据保存路径 csv_path = url_token + ".csv" # 调用函数获取数据 save_answers_to_csv(url_token, csv_path)

运行命令(对应 README 的「Download data based on single KOL url token」):

python main.py

圆桌话题批量抓取:Playwright 端到端自动化

单用户模式需要逐个提供 url_token,扩展性有限。为此 scrape_by_topic.py 提供了基于知乎「圆桌」(roundtable)话题的批量抓取方案,README 对应命令为:

python scrape_by_topic.py

抓取思路

圆桌是知乎围绕某一主题聚合问答的专题页面(如科技、职场等),页面中包含大量与主题相关的问题和回答链接。脚本借助 Playwright 的真实浏览器能力实现端到端自动化,核心流程如下:

  1. 进入圆桌列表页page.goto("https://zhihu.com/roundtable"),通过roundtable_topic_scrolldown = 20End键滚动加载更多圆桌主题(每次滚动后wait_for_timeout(1000));
  2. 提取主题链接get_all_href(page)使用page.evaluate执行页面内 JS,收集全部href,过滤出包含https://www.zhihu.com/roundtable/的链接,并np.random.shuffle随机打乱顺序;
  3. 跳过早期主题starting_offset = 4,跳过列表前 4 个主题——源码注释说明早期圆桌话题可能尚未正式开始,偏移量是任意设定的;
  4. 逐主题进入:对每个主题页收集所有href,从中过滤出含/people/的用户主页链接(scrape_people_roundtable函数会将其累计写入people.csv,用于反推 KOL 名单);
  5. 逐问题抓取回答end_to_end_auto_scrape函数进一步遍历主题页上的问题链接(过滤掉含waiting的未开始问题),进入每个问题页:
    • .QuestionHeader-title选择器读取问题标题;
    • .QuestionAnswers-answers容器内收集所有href,用正则r"/question/\d+/answer/\d+"匹配出「问题ID/回答ID」对;
    • 对每个回答调用get_answer_content(qId, aId, question_title)抓取正文,任务间time.sleep(1)限速以降低封禁风险;
  6. 增量落盘:每处理完一个主题,就把累积的 payload 用pd.json_normalize展平并写入zhihu.csv,做到边抓边存、断点可续。

富化的回答数据结构

圆桌流程使用的get_answer_content返回的是Content_Data数据类,字段比单用户版本更丰富:

@dataclass class Content_Data: question_id: int answer_id: int author_id: str question_title: str content: str upvotes: str answer_creation_time: str

其中额外字段的提取方式体现了对页面元数据的挖掘:

  • 回答创建时间:从<meta itemprop="dateCreated">标签中读取(源码注释说明经在线页面人工核对,该 meta 内容即回答创建时间);
  • 点赞数:查找class="Button VoteButton VoteButton--up"按钮文本,并清理零宽字符\u200b
  • 作者 ID:遍历<meta itemprop="url">标签,筛出 content 中含/people/的那一个。

这些字段在后续 Parquet 转换时会被写入 METADATA,为数据筛选(例如按点赞数过滤低质量回答)提供依据。

有头模式的取舍

脚本中headless = False,即 Playwright 以有头模式运行。虽然无头模式更省资源,但知乎对纯无头浏览器的反爬识别更严格;有头模式配合真实 UA 能显著提高抓取成功率。代价是需要图形环境(桌面或带显示的容器),在纯服务器上运行可能需要配合xvfb之类的虚拟显示方案,这一点在 README 中并未展开,属于从代码推断的部署注意事项。

数据标准化:转换为 Open-Assistant Parquet 格式

抓取产物是 CSV(zhihu.csv{url_token}.csv),而训练管线需要标准化的 Parquet 文件。convert_parquet.py 完成这一转换,对应 README 命令:

python convert_parquet.py

Instruction 格式规范

根据 data/datasets/README.md 的统一定义,Instruction 数据集必须包含以下列:

  1. INSTRUCTION(字符串):指令文本(此处即知乎问题标题);
  2. RESPONSE(字符串):期望的回复(此处即 KOL 回答正文);
  3. SOURCE(字符串):原始数据源简称,此处固定为"Zhihu"
  4. METADATA(JSON 字符串,可选):其他有用信息,如 NSFW 标记{"nsfw": true}

同时,仓库对数据格式有硬性要求:所有数据必须是 UTF-8 编码;存储为 Parquet 时必须使用row_group_size=100index=False(jsonl / jsonl.gz 亦可)。

转换实现

reformat_csv_to_openassistant将圆桌抓取的 CSV 映射为标准四列,METADATA 中保留 5 个溯源字段:

new_df["METADATA"] = df.apply( lambda x: json.dumps( { "question_id": x["question_id"], "answer_id": x["answer_id"], "author_id": x["author_id"], "upvotes": x["upvotes"], "answer_creation_time": x["answer_creation_time"], }, ensure_ascii=False, ), axis=1, )

值得注意的是,转换阶段还内置了一道质量过滤:

new_df = new_df[~(new_df["RESPONSE"] == " ") | (new_df["RESPONSE"].isna())]

该行意图剔除回答内容为空(单个空格)或缺失的行,避免无效样本进入训练集。严格来说,按逻辑运算符优先级这里存在一个易混淆点(应为「剔除 RESPONSE 为空格或为 NaN 的行」),但从意图看这是一道明确的数据清洗步骤,读者可依据需求自行调整过滤条件。

主流程将zhihu.csv读入,转换后写为 Parquet:

df = pd.read_csv(input_csv) df = reformat_csv_to_openassistant(df) df.to_parquet("dataset.parquet", row_group_size=100, engine="pyarrow", index=False)

这正好与 data/datasets/README.md 给出的全仓库统一 Parquet 转换范式(df.to_parquet("dataset.parquet", row_group_size=100, engine="pyarrow", index=False))完全一致,说明该数据集严格遵守了 Open-Assistant 的数据规范。

发布到 Hugging Face:上传数据集

上传脚本

upload_hf.py 极其精简,仅 4 行:

from datasets import Dataset ds = Dataset.from_parquet("dataset.parquet") ds.push_to_hub("wangrui6/zhihu-kol")

Dataset.from_parquet将 Parquet 加载为 HF Datasets 对象,push_to_hub将其推送到wangrui6/zhihu-kol仓库(与 data/datasets/init.py 注册表中的目标一致)。对应 README 命令:

python upload_hf.py

前置登录与规范要点

在执行上传前,需要先完成 Hugging Face 身份认证。依据 data/datasets/README.md 的通用流程:

pip install huggingface_hub huggingface-cli login # 使用你的 access token 登录

登录成功后运行上传脚本即可。注意push_to_hub需要写入权限的 token(Write 级别),只读 token 无法完成推送。

另外两个需要留意的仓库规范:

  • 数据集许可:数据集必须具有宽松许可证(permissive license);
  • 隐私红线:不得包含儿童性虐待材料,不得包含个人隐私信息(姓名、地址、电话、政府 ID、医疗信息等)。

知乎 KOL 回答属于社区公开内容,但抓取与再发布时仍应自行评估内容合规性与授权边界——这是 README 未明说但值得实践者关注的事项。

与训练管线的衔接:数据集如何被消费

该数据集并非孤立存在,它已经被 Open-Assistant 的训练代码正式引用。在 model/model_training/custom_datasets/instruction.py 的INSTRUCTION_DATASETS注册表中可以看到:

"zhihu-kol": {"dataset_path": "wangrui6/zhihu-kol"},

InstructionDataset 加载逻辑

训练端通过InstructionDataset类消费该数据集,其关键行为包括:

  • 列名约定:默认读取INSTRUCTIONRESPONSE两列(构造函数参数instruction_column="INSTRUCTION"response_column="RESPONSE"),这正好对应本数据集转换脚本产出的列名;
  • 空值过滤:加载时丢弃q/a为空或 strip 后长度为 0 的样本,并统计num_invalid打印警告;
  • 词级过滤:调用_filter_by_words对问题与回答进行单词级过滤(见 model/model_training/custom_datasets/utils.py),剔除不适合训练的内容;
  • 随机打乱与拼包:以seed=42打乱样本顺序,并按fill_min_length将多条问答拼接成训练块(block),满足 SFT 的序列长度要求;
  • 数据格式适配__getitem__通过create_dataset_entry_qa(mode=..., questions=..., answers=..., lang=...)生成DatasetEntry。注意注册表中zhihu-kol未指定lang字段(对比recipesgrade_school_math_instructions等显式标注了"lang": "en"),因此中文内容不会被子采样逻辑按语言过滤——从源码结构可以推断,该数据集在训练时按默认语言处理路径参与混入。

数据流总结

至此,整个「知乎 KOL 问答数据」从采集到训练的全链路可以概括为:

知乎页面/API │ main.py / scrape_by_topic.py(requests + Playwright + BeautifulSoup) ▼ CSV(中文列名 or Content_Data 结构) │ convert_parquet.py(reformat + 空内容过滤) ▼ dataset.parquet(INSTRUCTION / RESPONSE / SOURCE / METADATA) │ upload_hf.py(push_to_hub) ▼ HF Hub: wangrui6/zhihu-kol │ model_training/custom_datasets/instruction.py(InstructionDataset) ▼ Open-Assistant SFT/RL 训练管线

这条链路完整覆盖了 Open-Assistant 数据贡献规范(data/datasets/README.md)中「创建数据集 → 转 Parquet → 登录 HF → 推送 → 注册到__init__.py」的每一步,zhihu-kol已注册在 data/datasets/init.py 的INSTRUCTION_DATASETS中,是一个端到端跑通的中文指令数据范例。

总结与扩展建议

围绕 data/datasets/zhihu-kol/README.md 描述的知乎 KOL 数据集,仓库提供了两套互补的抓取方案:

  • 单用户模式main.py):适合已确定 KOL 名单、按人精准采集,输出含 9 个中文元数据列的 CSV;
  • 圆桌批量模式scrape_by_topic.py):适合冷启动阶段从圆桌话题自动发现问题与回答,通过 Playwright 有头浏览器规避反爬,边抓边存。

两条路径最终都汇入统一的 Open-Assistant Instruction 标准格式,经 Parquet 化后上传 HF,并被训练管线原生消费。若需扩展该方案,可以关注以下几个方向:

  • 扩充 KOL 名单:结合scrape_people_roundtable产出的people.csv积累更多作者,再回灌到main.py逐个精抓;
  • 丰富元数据Content_Data中的upvotes可作为回答质量的代理指标,在convert_parquet.py中按阈值过滤低互动内容;
  • 补充格式规范:当前正文提取仅拼接<p>文本,若需要代码块、公式等富文本结构,可基于 BeautifulSoup 进一步增强解析规则;
  • 合规与隐私:数据再发布前需自行评估知乎内容的使用授权与个人信息脱敏。

对于希望在 Open-Assistant 上复刻中文问答数据采集流程的开发者,本数据集从抓取、清洗、转换到发布的完整代码(main.py、scrape_by_topic.py、convert_parquet.py、upload_hf.py)提供了可直接参考或移植的成熟范式。

【免费下载链接】Open-AssistantOpenAssistant is a chat-based assistant that understands tasks, can interact with third-party systems, and retrieve information dynamically to do so.项目地址: https://gitcode.com/gh_mirrors/op/Open-Assistant

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询