Project Icon

wtf_wikipedia

高效的Wikipedia数据结构化解析工具

wtf_wikipedia是一个专业的JavaScript库,用于解析和提取Wikipedia数据。这个工具可以将复杂的维基文本转换为结构化数据,提取纯文本、链接、图片和模板等信息。支持客户端和服务器端使用,能处理完整的Wikipedia数据转储,适合进行Wikipedia数据分析和应用开发。

wtf_wikipedia
从维基百科解析数据
npm install wtf_wikipedia
这是非常非常困难的。         我们没有开玩笑
我们为什么总是这样做?
我们把信息放在无法取出的地方。
import wtf from 'wtf_wikipedia'

let doc = await wtf.fetch('Toronto Raptors')
let coach = doc.infobox().get('coach')
coach.text() //'Darko Rajaković'

.text()

获取清洁的纯文本:

let str = `[[Greater_Boston|Boston]]'s [[Fenway_Park|baseball field]] has a {{convert|37|ft}} wall. <ref>Field of our Fathers: By Richard Johnson</ref>`
wtf(str).text()
// "Boston's baseball field has a 37ft wall."
let doc = await wtf.fetch('Glastonbury', 'en')
doc.sentences()[0].text()
// 'Glastonbury是英格兰萨默塞特郡的一个小镇和民政教区,位于一个干燥点...'

.json()

获取页面的所有数据:

let doc = await wtf.fetch('Whistling')

doc.json()
// { categories: ['口头交流', '声音技巧'], sections: [{ title: '技巧' }], ...}

默认的 .json() 输出是_非常详细的_,但你可以像这样挑选数据:

// 只获取链接:
doc.links().map((link) => link.json())
//[{ page: '戏剧迷信', text: '迷信' }]

// 只获取图片:
doc.images()[0].json()
// { file: 'Image:Duveneck Whistling Boy.jpg', url: 'https://commons.wiki...' }

// 特定章节的json:
doc.section('另见').links()[0].json()
// { page: '滑哨' }

在客户端运行:

<script src="https://unpkg.com/wtf_wikipedia"></script>
<script>
  wtf.fetch('Radiohead', { 'Api-User-Agent': '在此处命名你的脚本' }, function (err, doc) {
    let members = doc.infobox().get('current members')
    members.links().map((l) => l.page())
    //['Thom Yorke', 'Jonny Greenwood', 'Colin Greenwood'...]
  })
</script>

或在服务器端:

import wtf from 'wtf_wikipedia'
// 或者,
const wtf = require('wtf_wikipedia')

完整的维基百科转储

使用这个库,结合 dumpster-dive,你可以在一个下午内解析整个英文维基百科。

npm install -g dumpster-dive

好的,首先 🛀

维基文本 并非小事。

考虑以下几点:

这个库支持许多递归技巧、已弃用和晦涩的模板变体,以及非法的维基简写

它能做什么:

  • 检测并解析重定向消歧义页面
  • 信息框解析为格式化的键值对象
  • 处理递归模板和链接 - 如 [[.. [[...]] ]]
  • 逐句纯文本和链接解析
  • 解析和格式化内部链接
  • File:XYZ.png 文件名创建图像缩略图 URL
  • 正确解析动态模板,如 {{CURRENTMONTH}}{{CONVERT ..}}
  • 解析图像标题分类
  • 将"DMS 格式"的(59°12'7.7"N)地理坐标转换为经纬度
  • 解析并合并引用和参考元数据
  • 消除 xml、latex、css 和表格排序垃圾内容

它不能做什么:

  • 外部"嵌入"页面数据 [1]
  • AST 输出
  • 信息框或图库中 HTML 的智能(或"美化")格式化 [1]
  • 维护完美的页面顺序 [1]
  • 逐句参考(而是按"章节"元素)
  • 维护模板或信息框的 CSS 样式
  • 跨不同章节的大型表格 [1]

它的构建尽可能灵活。在所有情况下,都尝试以周到的方式处理失败。

HTML 抓取如何?

维基媒体的官方解析器将维基文本转换为 HTML。

如果你更喜欢这种屏幕抓取工作流程,你可以像这样提取页面的各个部分。

这很酷!

但通过这种方式获取结构化数据仍然是一个复杂、奇怪的过程。 手动_探索_ HTML 有时与扫描维基文本本身一样棘手和容易出错。

这个库的贡献者们已经得出这个结论,正如许多其他人一样

这个库对 Parsoid 的贡献者表示感谢。

好的,

将你的维基文本转换为 Doc 对象

import wtf from 'wtf_wikipedia'

let txt = `
==木材在流行文化中==
* 哈利·波特的魔杖
* 辛普森一家的栅栏
`
wtf(txt)
// Document {text(), json(), lists()...}

doc.links()

let txt = `口哨在许多电视节目中都有出现,例如 [[Lassie (1954 TV series)|''莱西'']],以及《[[The X-Files|X档案]]》的片头主题。`
wtf(txt)
  .links()
  .map((l) => l.page())
// [ 'Lassie (1954 TV series)',  'The X-Files' ]

doc.text()

返回文章的纯文本格式

let txt =
  "[[Greater_Boston|波士顿]]的[[Fenway_Park|棒球场]]有一面 {{convert|37|ft}} 高的墙。<ref>{{cite web|blah}}</ref>"
wtf(txt).text()
//"波士顿的棒球场有一面 37 英尺高的墙。"

doc.sections():

章节是指 '==像这样==' 的标题

wtf(page).sections()[1].children() // 遍历嵌套的章节
wtf(page).section('see also').remove() // 删除一个章节

doc.sentences()

let s = wtf(page).sentences()[4]
s.links()
s.bolds()
s.italics()
s.text()
s.wikitext()

doc.categories()

await wtf.fetch('Whistling').categories()
//['口头交流', '声乐', '声音技巧']

doc.images()

let img = wtf(page).images()[0]
img.url() // 完整大小的维基媒体托管的URL
img.thumbnail() // 默认300px
img.format() // jpg, png, ..

获取

你可以从任何维基API抓取和解析文章。这包括任何语言、任何维基项目,以及大多数第三方维基。

// 第三方维基
let doc = await wtf.fetch('https://muppet.fandom.com/wiki/Miss_Piggy')

// 法语维基百科
doc = await wtf.fetch('Tony Hawk', 'fr')
doc.sentence().text() // 'Tony Hawk是一名职业滑板运动员和演员...'

// 接受数组或维基媒体页面ID
let docs = wtf.fetch(['Whistling', 2983], { follow_redirects: false })

// 德语维基导游中的文章
wtf.fetch('Toronto', { lang: 'de', wiki: 'wikivoyage' }).then((doc) => {
  console.log(doc.sentences()[0].text()) // 'Toronto是安大略省的首府'
})

你也可以使用维基百科页面ID作为参数,而不是页面标题:

let doc = await wtf.fetch(64646, 'de')

fetch方法会跟随重定向。

API插件

wtf.getCategoryPages(title, [options])

获取属于给定分类的所有页面和子分类:

wtf.extend(require('wtf-plugin-api'))
let result = await wtf.getCategoryPages('Category:Politicians_from_Paris')
/*
{
  [
    {"pageid":52502362,"ns":0,"title":"William Abitbol"},
    {"pageid":50101413,"ns":0,"title":"Marie-Joseph Charles des Acres de L'Aigle"}
    ...
    {"pageid":62721979,"ns":14,"title":"Category:Councillors of Paris"},
    {"pageid":856891,"ns":14,"title":"Category:Mayors of Paris"}
  ]
}
*/

wtf.random([options])

从给定语言或域名获取随机的维基百科文章

wtf.extend(require('wtf-plugin-api'))
wtf.random().then((doc) => {
  console.log(doc.title(), doc.categories())
  //'Whistling'  ['口头交流', '声音技巧']
})

查看 wtf-plugin-api

教程

插件

这些插件添加了各种新功能:

wtf.extend(require('wtf-plugin-classify'))
await wtf.fetch('Toronto Raptors').classify()
// 'Organization/SportsTeam'

wtf.extend(require('wtf-plugin-summary'))
await wtf.fetch('Pulp Fiction').summary()
// '一部1994年美国犯罪片'

wtf.extend(require('wtf-plugin-person'))
await wtf.fetch('David Bowie').birthDate()
// {year:1947, date:8, month:1}

wtf.extend(require('wtf-plugin-i18n'))
await wtf.fetch('Ziggy Stardust', 'fr').infobox().json()
// {nom:{text:"Ziggy Stardust"}, oeuvre:{text:"The Rise and Fall of Ziggy Stardust"}}
插件
classify人/地点/事物
summary简短描述文本
person出生/死亡信息
api从API获取更多数据
i18n改进多语言模板覆盖
wtf-mlb获取棒球数据
wtf-nhl获取冰球数据
nsfw标记色情/图形/成人文章
image.images()的附加方法
html输出html
wikitext输出wikitext
markdown输出markdown
latex输出latex

良好实践:

维基百科API相当欢迎使用,但如果你要大量使用,建议遵循以下三点 -

  • 传递一个Api-User-Agent作为某种标识,以便他们可以轻松限制不良脚本
  • 将多个页面打包成一个请求(比如,每组5个?)
  • 串行运行,或至少,缓慢运行
wtf
  .fetch(['Royal Cinema', 'Aldous Huxley'], {
    lang: 'en',
    'Api-User-Agent': 'spencermountain@gmail.com',
  })
  .then((docList) => {
    let links = docList.map((doc) => doc.links())
    console.log(links)
  })

完整API

  • .title() - 获取/设置页面的标题(从第一句话中获取)
  • .pageID() - 获取/设置页面的维基媒体ID(如果有的话)
  • .wikidata() - 获取/设置页面的维基数据ID(如果有的话)
  • .domain() - 获取/设置我们所在的维基域名(如果有的话)
  • .url() - (尝试)生成当前文章的URL
  • .lang() - 获取/设置当前语言(用于URL方法)
  • .namespace() - 获取/设置页面的维基媒体命名空间(如果有的话)
  • .isRedirect() - 判断页面是否只是重定向到另一个页面
  • .redirectTo() - 此页面重定向到的目标页面
  • .isDisambiguation() - 判断是否为引导你到多个可能页面之一的占位页面
  • .isStub() - 判断页面是否被标记为不完整
  • .categories() - 返回文档的所有分类
  • .sections() - 返回文档的章节列表
  • .paragraphs() - 返回所有章节中的段落列表
  • .sentences() - 返回文档中的所有句子列表
  • .images() - 返回文档中找到的所有图片
  • .links() - 返回文档所有部分中的所有链接列表
  • .lists() - 页面中每行以项目符号开头的章节
  • .tables() - 返回文档中所有结构化表格的列表
  • .templates() - 任何类型的结构化数据元素,通常包裹在{{这样}}中
  • .infoboxes() - 特定类型的模板,通常出现在页面右上角
  • .references() - 返回文档中"引用"的列表
  • .coordinates() - 页面上出现的地理位置
  • .text() - 页面的纯文本、人类可读输出
  • .json() - 页面主要数据的"可字符串化"输出
  • .wikitext() - 原始维基标记
  • .description() - 获取/设置页面的简短描述(如果有的话)
  • .pageImage() - 获取/设置页面的代表性图片(如果有的话)
  • .revisionID() - 获取/设置页面的最新编辑ID(如果有的话)
  • .timestamp() - 获取/设置页面最近编辑的时间(如果有的话)

章节

  • .title() - 章节名称,位于==这些标签==之间
  • .index() - 此章节在整个文档中的序号
  • .indentation() - 在目录中的深度层级
  • .sentences() - 返回此章节中的句子列表
  • .paragraphs() - 返回此章节中的段落列表
  • .links() - 所有段落和模板中的所有链接列表
  • .tables() - 所有HTML表格列表
  • .templates() - 此章节中的所有模板列表
  • .infoboxes() - 此章节中找到的所有信息框列表
  • .coordinates() - 此章节中找到的所有坐标模板列表
  • .lists() - 此章节中的所有列表
  • .interwiki() - 指向其他语言维基的任何链接
  • .images() - 返回此章节中任何图片的列表
  • .references() - 返回此章节中"引用"的列表
  • .remove() - 从文档中移除当前章节
  • .nextSibling() - 当前父级下的下一个章节:例如,1920年代 → 1930年代
  • .lastSibling() - 当前父级下的上一个章节:例如,1930年代 → 1920年代
  • .children() - 比当前章节更具体的任何章节:例如,历史 → [史前时期, 1920年代, 1930年代]
  • .parent() - 比当前章节更广泛的章节:例如,1920年代 → 历史
  • .text() - 此章节的可读纯文本
  • .json() - 返回所有章节数据
  • .wikitext() - 原始维基标记

段落

  • .sentences() - 返回此段落中的句子对象列表
  • .references() - 所有句子中的任何引用或参考
  • .lists() - 此段落中找到的任何列表
  • .images() - 此段落中找到的任何图片
  • .links() - 所有句子中的所有链接列表
  • .interwiki() - 指向其他语言维基的任何链接
  • .text() - 生成此段落的可读纯文本
  • .json() - 以JSON格式生成此段落的一些通用数据
  • .wikitext() - 原始维基标记

句子

  • .links() - 所有链接列表
  • .bolds() - 所有粗体文本列表
  • .italics() - 所有斜体格式文本列表
  • .text() - 生成可读纯文本
  • .json() - 返回所有句子数据
  • .wikitext() - 原始维基标记

图片

  • .url() - 返回全尺寸图片的URL
  • .thumbnail() - 返回缩略图URL(传入size参数可自定义大小)
  • .links() - 来自图片说明的任何链接(如果存在)
  • .format() - 获取文件格式(例如jpg
  • .text() - 无操作
  • .json() - 返回此图片的一些通用元数据
  • .wikitext() - 原始维基标记

模板

  • .text() - 此模板是否生成任何可读的纯文本?
  • .json() - 获取此模板的所有数据
  • .wikitext() - 原始维基标记

信息框

  • .links() - 此信息框中的任何内部或外部链接
  • .keyValue() - 从此信息框生成简单的键值对字符串
  • .image() - 从此信息框获取主图片
  • .get() - 通过键查找属性
  • .template() - 使用的信息框类型,例如"Infobox Person"
  • .text() - 为此信息框生成可读纯文本
  • .json() - 为此信息框生成一些通用的"可字符串化"数据
  • .wikitext() - 原始维基标记

列表

  • .lines() - 获取列表中每个成员的数组
  • .links() - 获取此列表中提到的所有链接
  • .text() - 为此列表生成可读纯文本
  • .json() - 为此列表生成一些通用的易解析数据
  • .wikitext() - 原始维基标记

参考

  • .title() - 为此参考生成面向人类的文本
  • .links() - 获取此参考中提到的任何链接
  • .text() - 不返回任何内容
  • .json() - 为此参考生成一些通用元数据
  • .wikitext() - 原始维基标记

表格

  • .links() - 获取此表格中提到的任何链接
  • .keyValue() - 为此表格生成简单的键值对对象列表
  • .text() - 不返回任何内容
  • .json() - 为此表格生成一些有用的元数据
  • .wikitext() - 原始维基标记

配置

添加新方法:

你可以使用wtf.extend()向库中的任何类添加新方法

wtf.extend((models) => {
  // 将此方法添加进去...
  models.Doc.prototype.isPerson = function () {
    return this.categories().find((cat) => cat.match(/people/))
  }
})

await wtf.fetch('Stephen Harper').isPerson()

添加新模板:

你的维基使用{{foo}}模板吗?为它添加一个自定义解析器:

wtf.extend((models, templates) => {
  // 创建一个自定义解析函数
  templates.foo = (tmpl, list, parse) => {
    let obj = parse(tmpl) //或者使用自定义正则表达式
    list.push(obj)
    return 'new-text'
  }

  // 数组语法允许轻松标记参数
  templates.foo = ['a', 'b', 'c']

  // 数字语法用于按参数编号返回 '{{name|zero|one|two}}'
  templates.baz = 0

  // 用字符串替换模板 '{{asterisk}}' -> '*'
  templates.asterisk = '*'
})

默认情况下,如果没有模板的解析器,它将被忽略并生成一个空字符串。 但是,可以配置一个后备解析函数来处理这些模板:

wtf('some {{weird_template}} here', {
  templateFallbackFn: (tmpl, list, parse) => {
    let obj = parse(tmpl) //或者使用自定义正则表达式
    list.push(obj)
    return '[unsupported template]' // 或返回null以忽略此模板
  },
})

你可以使用第三个参数确定哪些模板被理解为"信息框":

wtf.extend((models, templates, infoboxes) => {
  Object.assign(infoboxes, { person: true, place: true, thing: true })
})

注意事项:

第三方维基

默认情况下,已安装的MediaWiki应用程序提供公共API。 这意味着大多数维基都有一个开放的API,即使他们没有意识到这一点。一些维基可能会关闭这个功能。

通常可以通过访问http://mywiki.com/api.php找到它

要从第三方维基获取页面:

wtf.fetch('Kermit', { domain: 'muppet.fandom.com' }).then((doc) => {
  console.log(doc.text())
})

一些维基会将其API的路径从./api.php更改为其他位置。如果你的API有不同的路径,你可以这样设置:

wtf.fetch('2016-06-04_-_J.Fernandes_@_FIL,_Lisbon', { domain: 'www.mixesdb.com', path: 'db/api.php' }).then((doc) => {
  console.log(doc.template('player').json())
})

为了使图像URL正常工作,维基还应启用Special:Redirect。 一些维基(如Wikia)有意禁用了这个功能。

国际化和多语言:

wikitext(令人惊讶地)在所有语言、维基,甚至在从右到左的语言中都被使用。 这个解析器在处理这方面也做得相当不错。

库中包含了Wikipedia I18n语言信息,涵盖_重定向、信息框、分类和图像_,覆盖范围相当广泛。

要改善I18n模板的覆盖范围,请使用wtf-plugin-i18n

如果你发现你的语言缺少某些内容,请提交PR。

构建:

该库提供独立的客户端和服务器端构建,以保持文件大小。

浏览器版本使用fetch(),而服务器版本使用require('https')

性能:

它不是最快的解析器,也不太可能在速度上超过C或Java中的单程解析器

使用dumpster-dive,这个库可以在MacBook上用约4小时解析完整的英文Wikipedia。

这大约是每线程每秒100页。

另请参阅:

其他替代JavaScript解析器:

以及更多

MIT

项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

白日梦AI

白日梦AI提供专注于AI视频生成的多样化功能,包括文生视频、动态画面和形象生成等,帮助用户快速上手,创造专业级内容。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

讯飞绘镜

讯飞绘镜是一个支持从创意到完整视频创作的智能平台,用户可以快速生成视频素材并创作独特的音乐视频和故事。平台提供多样化的主题和精选作品,帮助用户探索创意灵感。

Project Cover

讯飞文书

讯飞文书依托讯飞星火大模型,为文书写作者提供从素材筹备到稿件撰写及审稿的全程支持。通过录音智记和以稿写稿等功能,满足事务性工作的高频需求,帮助撰稿人节省精力,提高效率,优化工作与生活。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号