作者:SamAgnew消费资讯。但是,如果数据不是以专用RESTAPI的形式存在,那么通常很难以编程方式访问这些数据。使用jsdom等Node.js工具,您可以直接从网络上抓取和解析这些数据,并将其用于您自己的项目和应用程序。让我们以使用MIDI音乐数据训练神经网络来生成经典的任天堂音乐为例。我们需要一组旧任天堂游戏的MIDI音乐。可以使用jsdom从视频游戏音乐档案中抓取此数据。入门和依赖设置在继续之前,您需要确保您拥有最新版本的Node.js和npm。切换到您希望此代码所在的目录,并在终端中运行以下命令来创建项目的包:npminit--yes--yes该参数可以忽略任何您必须填写或跳过的提示。现在我们的程序有一个package.json以便通过发出HTTP请求从网页中获取数据,我们将使用Got库,对于HTML解析,我们将使用Cheerio。在终端中运行以下命令来安装这些库:npminstallgot@10.4.0jsdom@16.2.2jsdom是大量web标准的纯JavaScript实现,是许多JavaScript开发人员熟悉的工具。让我们深入了解如何使用它。检索数据以与jsdom一起使用首先让我们编写一些代码以从网页中获取HTML,然后看看如何开始解析。以下代码将向我们想要的网页发送GET请求,并使用该网页的HTML创建一个jsdom对象,我们将其命名为dom:constfs=require('fs');constgot=require('got');constjsdom=require("jsdom");const{JSDOM}=jsdom;constvgmUrl='https://www.vgmusic.com/music/console/nintendo/nes';got(vgmUrl).then(response=>{constdom=newJSDOM(response.body);console.log(dom.window.document.querySelector('title').textContent);}).catch(err=>{console.log(err);});将字符串传递给构造函数JSDOM时,将返回一个JSDOM对象,您可以从中访问许多可用的属性,例如window。正如这段代码所示,您可以使用查询选择器。例如querySelector('title').textContent将获取页面上
标签内的文本。如果将这段代码保存到一个名为index.js的文件中并使用命令nodeindex.js运行它,它会将网页的标题记录到控制台。将CSS选择器与jsdom一起使用如果您希望在查询中获得更具体的信息,可以使用HTML解析器来解析它。两种最常见的方法是按类或ID获取。如果想获取ID为“menu”的div,可以使用querySelectorAll('#menu'),如果想获取VGMMIDI表中的所有表头列,可以执行querySelectorAll('td.header')我们在这个页面上面需要的是指向我们需要下载的所有MIDI文件的超链接。您可以从querySelectorAll('a')开始获取页面上的每个链接。在index.js中将以下代码添加到您的代码中:>{console.log(link.href);});}).catch(err=>{console.log(err);});此代码记录页面上每个链接的URL。可以使用forEach函数浏览给定选择器中的所有元素。遍历页面上的每个链接都很棒,但如果您想下载所有MIDI文件,则需要更加具体。按HTML元素过滤在编写更多代码来解析您需要的内容之前,让我们看一下浏览器呈现的HTML。每个网页都是不同的,有时从中获取正确的数据需要一些创造力、模式识别和实验。我们的目标是下载许多MIDI文件,但此页面上有许多重复曲目和歌曲混音。我们只想下载其中一首重复的歌曲,并且由于我们的最终目标是使用此数据来训练神经网络以生成准确的任天堂音乐,因此我们不想在用户创建的混音上训练它。当您编写代码来解析网页时,通常可以使用现代浏览器中的开发人员工具。如果右击您感兴趣的元素,您可以检查该元素背后的HTML并获得更多信息。您可以编写过滤器函数来微调所需的选择器数据。这些函数遍历给定选择器的所有元素并返回true或false,具体取决于它们是否应包含在集合中。如果您查看上一步记录的数据,您可能会注意到页面上有很多链接没有href属性,因此无处可寻。我们确定它们不是我们正在寻找的MIDI,因此我们需要编写一个简短的函数来过滤掉那些并包含链接到.mid文件的href元素:constisMidi=(link)=>{//如果没有href属性,则返回false。if(typeoflink.href==='undefined'){returnfalse}returnlink.href.includes('.mid');};现在有一个问题,我们不想下载重复的或者用户生成的混合。正则表达式可用于确保仅获取文本中不带括号的链接,因为只有重复项和混合包含括号:constnoParens=(link)=>{//用于确定文本是否包含括号的正则表达式。constparensRegex=/^((?!\().)*$/;returnparensRegex.test(link.textContent);};尝试通过从querySelectorAll返回来将它们添加到index.js中的代码中创建一个数组HTML元素节点集合,然后对其应用过滤器函数:传播语法。constnodeList=[...dom.window.document.querySelectorAll('a')];nodeList.filter(isMidi).filter(noParens).forEach(link=>{console.log(link.href);});}).catch(err=>{console.log(err);});再次运行代码,它应该只打印.mid文件而不复制任何特定歌曲。从网页上下载我们想要的MIDI文件现在我们有了迭代每个我们需要的MIDI文件的工作代码,我们必须编写代码来下载所有这些文件。在迭代所有MIDI链接的回调函数中,添加以下代码以将MIDI下载流式传输到本地文件,并进行错误检查:nodeList.filter(isMidi).filter(noParens).forEach(link=>{constfileName=link.href;got.stream(`${vgmUrl}/${fileName}`).on('error',err=>{console.log(err);console.log(`${vgmUrl错误}/${fileName}`)}).pipe(fs.createWriteStream(`MIDIs/${fileName}`)).on('error',err=>{console.log(err);console.log(`Erroron${vgmUrl}/${fileName}`)}).on('finish',()=>console.log(`Downloaded:${fileName}`));});从目录和终端屏幕上,我能够看到所有已下载的2230个MIDI文件(在编写此代码时)。这样就完成了我们需要的所有MIDI文件的抓取。现在是时候仔细聆听并享受任天堂音乐了!广阔的万维网您可以通过编程方式从Web获取内容,从而为您需要的任何项目访问大量数据源。要记住的一件事是更改网页的HTML可能会破坏您的代码,因此如果您要在此基础上构建应用程序,请确保所有内容都是最新的。如果您正在寻找与刚刚从视频游戏音乐档案中获得的数据有关的内容,您可以尝试使用像Magenta这样的Python库来训练神经网络。