伍佰目录 短网址
  当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

用 Node.js 爬虫下载音乐

来源:本站原创 浏览:51次 时间:2023-07-10
用 Node.js 爬虫下载音乐

疯狂的技术宅 前端先锋

翻译:疯狂的技术宅
作者:Sam Agnew
来源:twilio.com
正文共:1968 字
预计阅读时间:12 分钟

互联网上有许多可供人类消费的信息。但是如果这些数据不是以专用的 REST API 的形式出现,通常很难以编程方式对其进行访问。使用 jsdom 之类的 Node.js 工具,你可以直接从网页上抓取并解析这些数据,并用于你自己的项目和应用。

让我们以用 MIDI 音乐数据来训练神经网络 来生成听起来经典的任天堂音乐【https://www.twilio.com/blog/generating-nintendo-music-over-the-phone-with-magenta-and-twilio】为例。我们需要一套来自旧任天堂游戏的 MIDI 音乐。通过使用 jsdom 可以从视频游戏音乐档案(https://vgmusic.com/music/console/nintendo/nes/)中抓取这些数据。

入门和依赖项设置

在继续之前,你需要确保自己有 Node.js 和 npm 的最新版本。

切换到你希望此代码存在的目录,并在终端中运行以下命令创建项目的程序包:

1npm init --yes

--yes 参数可以忽略所有你必须填写或跳过的提示。现在我们的程序有了 package.json

为了通过发出 HTTP 请求从网页获取数据,我们将使用 Got 库,对于 HTML 的解析,我们将用 Cheerio。

在终端中运行以下命令安装这些库:

1npm install got@10.4.0 jsdom@16.2.2

jsdom 是大量 Web 标准的纯 JavaScript 实现,也是许多 JavaScript 开发人员熟悉的工具。让我们深入了解该如何使用它。

用 Got 检索要与 jsdom 一起使用的数据

首先让我们编写一些从网页中获取 HTML 的代码,然后看看如何开始解析。以下代码将向我们想要的网页发送一个 GET 请求,并使用该页面的 HTML 创建一个 jsdom 对象,我们将其命名为 dom:

 1const fs = require('fs'); 2const got = require('got'); 3const jsdom = require("jsdom"); 4const { JSDOM } = jsdom; 5 6const vgmUrl= 'https://www.vgmusic.com/music/console/nintendo/nes'; 7 8got(vgmUrl).then(response => { 9  const dom = new JSDOM(response.body);10  console.log(dom.window.document.querySelector('title').textContent);11}).catch(err => {12  console.log(err);13});

当向构造函数 JSDOM 传递一个字符串时,将返回一个 JSDOM 对象,你可以从中访问许多可用的属性,例如 window。如该代码所示,你可以用查询选择器(query selector)。

例如 querySelector('title').textContent 将获取页面上 <title> 标记内的文本。如果将此代码保存到名为 index.js 的文件并用命令 node index.js 运行,它会把网页的标题记录到控制台。

通过 jsdom 使用 CSS 选择器

如果你想在查询中获得更具体的信息,可以用 HTML 解析器(https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors)进行解析。最常见的两个方法是按 class 或 ID 获取。如果要获取 ID 为 “menu” 的div,则可以用 querySelectorAll('#menu'),并且如果要获取 VGM MIDI 表格中的所有标题列,则可以执行 querySelectorAll('td.header')

我们在此页面上想要的是我们需要下载的所有 MIDI 文件的超链接。可以用 querySelectorAll('a')开始获取页面上的每个链接。在 index.js 中的代码中添加以下内容:

1got(vgmUrl).then(response => {2  const dom = new JSDOM(response.body);3    dom.window.document.querySelectorAll('a').forEach(link => {4    console.log(link.href);5  });6}).catch(err => {7  console.log(err);8});

此代码记录页面上每个链接的 URL。可以用 forEach 函数浏览给定选择器中的所有元素。遍历页面上的每个链接都很棒,但是如果要下载所有 MIDI 文件,则需要更具体一些。

通过 HTML 元素过滤

在编写更多代码去解析所需的内容之前,先来看一下浏览器渲染出来的 HTML。每个网页都是不同的,有时从其中获取正确的数据需要一些创造力、模式识别和实验。

网页上的MIDI文件
我们的目标是下载许多 MIDI 文件,但是这个网页上有很多重复的曲目以及歌曲的混音。我们只希望下载重复歌曲中的一首,并且因为我们的最终目标是用这些数据来训练神经网络以生成准确的 Nintendo 音乐,所以我们不想在用户创建的混音上对其进行训练。

当你编写代码解析网页时,通常可以用现代浏览器中的开发者工具。如果右键单击你感兴趣的元素,则可以检查该元素后面的 HTML 并获取更多信息。

检查元素
你可以编写过滤器函数来微调所需的选择器数据。这些函数遍历给定选择器的所有元素,并根据是否应将它们包含在集合中而返回 true 或 false。

如果查看了上一步中记录的数据,可能会注意到页面上有很多链接没有 href 属性,因此无处可寻。可以确定它们不是我们要寻找的 MIDI,所以需要写一个简短的函数来过滤掉那些 MIDI,并包含确实能够链接到 .mid 文件的 href 元素:

1const isMidi = (link) => {2  // Return false if there is no href attribute.3  if(typeof link.href === 'undefined') { return false }45  return link.href.includes('.mid');6};

现在有一个问题,我们不想下载重复项或用户生成的混音。可以用正则表达式来确保仅获取文本中不带括号的链接,因为只有重复项和混音项包含括号:

1const noParens = (link) => {2  // Regular expression to determine if the text has parentheses.3  const parensRegex = /^((?!\().)*$/;4  return parensRegex.test(link.textContent);5};

试着将它们添加到你的 index.js 中的代码中,通过从 querySelectorAll 返回的 HTML 元素节点集合中创建一个数组,然后把过滤器函数应用到其中:

 1got(vgmUrl).then(response => { 2  const dom = new JSDOM(response.body); 3 4  // Create an Array out of the HTML Elements for filtering using spread syntax. 5  const nodeList = [...dom.window.document.querySelectorAll('a')]; 6 7  nodeList.filter(isMidi).filter(noParens).forEach(link => { 8    console.log(link.href); 9  });10}).catch(err => {11  console.log(err);12});

再次运行代码,它仅应打印 .mid 文件,而不复制任何特定歌曲。

从网页下载我们想要的 MIDI 文件

现在我们有了遍历所需的每个 MIDI 文件的工作代码,必须编写代码来下载所有这些文件。

在用于遍历所有 MIDI 链接的回调函数中,添加以下代码以将 MIDI 下载流式传输到本地文件,并进行错误检查:

1  nodeList.filter(isMidi).filter(noParens).forEach(link => {2    const fileName = link.href;3    got.stream(`${vgmUrl}/${fileName}`)4      .on('error', err => { console.log(err); console.log(`Error on ${vgmUrl}/${fileName}`) })5      .pipe(fs.createWriteStream(`MIDIs/${fileName}`))6      .on('error', err => { console.log(err); console.log(`Error on ${vgmUrl}/${fileName}`) })7      .on('finish', () => console.log(`Downloaded: ${fileName}`));8  });

从要保存 MIDI 文件的目录中运行代码,从终端屏幕上能够看到下载的所有 2230 个 MIDI 文件(在编写此代码时)。这样我们就完成所有需要的 MIDI 文件的抓取了。

Logging the results of the file downloads
现在可以仔细倾听并欣赏任天堂音乐了!

浩瀚的万维网

你可以通过编程的方式从网页上获取内容,无论你需要什么项目,都可以访问大量的数据源。要记住的一件事是,被更改过网页的 HTML 可能会破坏你的代码,所以如果你要在此基础上构建应用程序,请确保所有内容保持最新。

如果你正在寻找与刚刚从视频游戏音乐档案库中获取的数据有关的内容,则可以尝试使用 Python 库,例如 Magenta to train a neural network with it(https://www.twilio.com/blog/training-a-neural-network-on-midi-music-data-with-magenta-and-python)。

原文链接

https://www.twilio.com/blog/web-scraping-and-parsing-html-in-node-js-with-jsdom

  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net