怎样用 Node.js 高效地从 Web 爬取数据?

分享
源码 2024-10-2 09:50:20 70 0 来自 中国
干系保举:《nodejs 教程》
由于Javascript有了巨大的改进,而且引入了称为NodeJS的运行时,因此它已成为最盛行和利用最广泛的语言之一。 无论是Web应用步伐照旧移动应用步伐,Javascript如今都具有准确的工具。 本文解说怎样用 Node.js 高效地从 Web 爬取数据。
条件条件

本文紧张针对具有肯定 JavaScript 履历的步伐员。如果你对 Web 抓取有深刻的相识,但对 JavaScript 并不认识,那么本文仍然可以大概对你有所资助。

  • ✅ 会 JavaScript
  • ✅ 会用 DevTools 提取元素选择器
  • ✅ 会一些 ES6 (可选)
你将学到

通过本文你将学到:

  • 学到更多关于 Node.js 的东西
  • 用多个 HTTP 客户端来资助 Web 抓取的过程
  • 利用多个颠末实践检验过的库来爬取 Web
相识 Node.js

Javascript 是一种简单的今世编程语言,最初是为了向浏览器中的网页添加动态结果。当加载网站后,Javascript 代码由浏览器的 Javascript 引擎运行。为了使 Javascript 与你的浏览器举行交互,浏览器还提供了运行时环境(document、window等)。
这意味着 Javascript 不能直接与盘算机资源交互或对其举行操纵。比方在 Web 服务器中,服务器必须可以大概与文件体系举行交互,如许才能读写文件。
Node.js 使 Javascript 不光可以大概运行在客户端,而且还可以运行在服务器端。为了做到这一点,其首创人 Ryan Dahl 选择了Google Chrome 浏览器的 v8 Javascript Engine,并将其嵌入到用 C++ 开辟的 Node 步伐中。以是 Node.js 是一个运行时环境,它允许 Javascript 代码也能在服务器上运行。
与其他语言(比方 C 或 C++)通过多个线程来处置处罚并发性相反,Node.js 利用单个主线程并并在事故循环的资助下以非壅闭方式实行使命。
要创建一个简单的 Web 服务器非常简单,如下所示:
const http = require('http');const PORT = 3000;const server = http.createServer((req, res) => {  res.statusCode = 200;  res.setHeader('Content-Type', 'text/plain');  res.end('Hello World');});server.listen(port, () => {  console.log(`Server running at PORT{port}/`);});如果你已安装了 Node.js,可以试着运行上面的代码。 Node.js 非常恰当 I/O 麋集型步伐。
HTTP 客户端:访问 Web

HTTP 客户端是可以大概将哀求发送到服务器,然后吸取服务器响应的工具。下面提到的全部工具底的层都是用 HTTP 客户端来访问你要抓取的网站。
Request

Request 是 Javascript 生态中利用最广泛的 HTTP 客户端之一,但是 Request 库的作者已正式声明弃用了。不外这并不意味着它不可用了,相当多的库仍在利用它,而且非常好用。用 Request 发出 HTTP 哀求黑白常简单的:
const request = require('request')request('https://www.reddit.com/r/programming.json', function (  error,  response,  body) {  console.error('error:', error)  console.log('body:', body)})你可以在 Github 上找到 Request 库,安装它非常简单。你还可以在 https://github.com/request/re... 找到弃用关照及其寄义。
Axios

Axios 是基于 promise 的 HTTP 客户端,可在浏览器和 Node.js 中运行。如果你用 Typescript,那么 axios 会为你覆盖内置范例。通过 Axios 发起 HTTP 哀求非常简单,默认环境下它带有 Promise 支持,而不是在 Request 中去利用回调:
const axios = require('axios')axios    .get('https://www.reddit.com/r/programming.json')    .then((response) => {        console.log(response)    })    .catch((error) => {        console.error(error)    });如果你喜欢 Promises API 的 async/await 语法糖,那么你也可以用,但是由于顶级 await 仍处于 stage 3 ,以是我们只好先用异步函数来代替:
async function getForum() {    try {        const response = await axios.get(            'https://www.reddit.com/r/programming.json'        )        console.log(response)    } catch (error) {        console.error(error)    }}你所要做的就是调用 getForum!可以在 https://github.com/axios/axios 上找到Axios库。
Superagent

与 Axios 一样,Superagent 是另一个强大的 HTTP 客户端,它支持 Promise 和 async/await 语法糖。它具有像 Axios 如许相当简单的 API,但是 Superagent 由于存在更多的依赖关系而且不那么盛行。
用 promise、async/await 或回调向 Superagent 发出HTTP哀求看起来像如许:
const superagent = require("superagent")const forumURL = "https://www.reddit.com/r/programming.json"// callbackssuperagent    .get(forumURL)    .end((error, response) => {        console.log(response)    })// promisessuperagent    .get(forumURL)    .then((response) => {        console.log(response)    })    .catch((error) => {        console.error(error)    })// promises with async/awaitasync function getForum() {    try {        const response = await superagent.get(forumURL)        console.log(response)    } catch (error) {        console.error(error)    }}可以在 https://github.com/visionmedi... 找到 Superagent。
正则表达式:困难的路

在没有任何依赖性的环境下,最简单的举行网络抓取的方法是,利用 HTTP 客户端查询网页时,在收到的 HTML 字符串上利用一堆正则表达式。正则表达式不那么机动,而且许多专业人士和业余爱好者都难以编写准确的正则表达式。
让我们试一试,假设此中有一个带有效户名的标签,我们须要该用户名,这类似于你依赖正则表达式时必须实行的操纵
const htmlString = '<label>Username: John Doe</label>'const result = htmlString.match(/<label>(.+)<\/label>/)console.log(result[1], result[1].split(": ")[1])// Username: John Doe, John Doe在 Javascript 中,match()  通常返回一个数组,该数组包含与正则表达式匹配的全部内容。第二个元素(在索引1中)将找到我们想要的 <label> 标记的 textContent 或 innerHTML。但是结果中包含一些不须要的文本( “Username: “),必须将其删除。
如你所见,对于一个非常简单的用例,步调和要做的工作都许多。这就是为什么应该依赖 HTML 剖析器的缘故因由,我们将在背面讨论。
Cheerio:用于遍历 DOM 的核心 JQuery

Cheerio 是一个高效轻便的库,它使你可以在服务器端利用 JQuery 的丰富而强大的 API。如果你从前用过 JQuery,那么将会对 Cheerio 感到很认识,它消除了 DOM 全部不划一和与浏览器干系的功能,并公开了一种有效的 API 来剖析和操纵 DOM。
const cheerio = require('cheerio')const $ = cheerio.load('<h2r/programming 论坛,实行获取帖子名称列表。</p>起首,通过运行以下下令来安装 Cheerio 和 axios:npm install cheerio axios。
然后创建一个名为 crawler.js 的新文件,并复制粘贴以下代码:
const axios = require('axios');const cheerio = require('cheerio');const getPostTitles = async () => {    try {        const { data } = await axios.get(            'https://old.reddit.com/r/programming/'        );        const $ = cheerio.load(data);        const postTitles = [];        $('div > p.title > a').each((_idx, el) => {            const postTitle = $(el).text()            postTitles.push(postTitle)        });        return postTitles;    } catch (error) {        throw error;    }};getPostTitles().then((postTitles) => console.log(postTitles));getPostTitles() 是一个异步函数,将对旧的 reddit 的 r/programming 论坛举行爬取。起首,用带有 axios HTTP 客户端库的简单 HTTP GET 哀求获取网站的 HTML,然后用 cheerio.load() 函数将 html 数据输入到 Cheerio 中。
然后在浏览器的 Dev Tools 资助下,可以得到可以定位全部列表项的选择器。如果你利用过 JQuery,则必须非常认识 $('div> p.title> a')。这将得到全部帖子,由于你只渴望单独获取每个帖子的标题,以是必须遍历每个帖子,这些操纵是在 each() 函数的资助下完成的。
要从每个标题中提取文本,必须在 Cheerio 的资助下获取 DOM元素( el 指代当前元素)。然后在每个元素上调用 text() 可以大概为你提供文本。
如今,打开终端并运行 node crawler.js,然后你将看到约莫存有标题的数组,它会很长。尽管这是一个非常简单的用例,但它展示了 Cheerio 提供的 API 的简单性子。
如果你的用例须要实行 Javascript 并加载外部源,那么以下几个选项将很有资助。
JSDOM:Node 的 DOM

JSDOM 是在 Node.js 中利用的文档对象模子的纯 Javascript 实现,如前所述,DOM 对 Node 不可用,但是 JSDOM 是最靠近的。它或多或少地模拟了浏览器。
由于创建了 DOM,以是可以通过编程与要爬取的 Web 应用或网站举行交互,也可以模拟单击按钮。如果你认识 DOM 操纵,那么利用 JSDOM 将会非常简单。
const { JSDOM } = require('jsdom')const { document } = new JSDOM(    '<h2Puppeteer 比上述工具更有效,由于它可以使你像真正的人在与浏览器举行交互一样对网络举行爬取。这就具备了一些从前没有的大概性:

  • 你可以获取屏幕截图或天生页面 PDF。
  • 可以抓取单页应用并天生预渲染的内容。
  • 自动实行许多差别的用户交互,比方键盘输入、表单提交、导航等。
它还可以在 Web 爬取之外的其他使掷中发挥紧张作用,比方 UI 测试、辅助性能优化等。
通常你会想要截取网站的屏幕截图,大概是为了相识竞争对手的产物目次,可以用 puppeteer 来做到。起首运行以下下令安装 puppeteer,:npm install puppeteer
这将下载 Chromium 的 bundle 版本,根据操纵体系的差别,该版本约莫 180 MB 至 300 MB。如果你要禁用此功能。
让我们实行在 Reddit 中获取 r/programming 论坛的屏幕截图和 PDF,创建一个名为 crawler.js的新文件,然后复制粘贴以下代码:
const puppeteer = require('puppeteer')async function getVisual() {    try {        const URL = 'https://www.reddit.com/r/programming/'        const browser = await puppeteer.launch()        const page = await browser.newPage()        await page.goto(URL)        await page.screenshot({ path: 'screenshot.png' })        await page.pdf({ path: 'page.pdf' })        await browser.close()    } catch (error) {        console.error(error)    }}getVisual()getVisual() 是一个异步函数,它将获 URL 变量中 url 对应的屏幕截图和 pdf。起首,通过 puppeteer.launch() 创建浏览器实例,然后创建一个新页面。可以将该页面视为通例浏览器中的选项卡。然后通过以 URL 为参数调用  page.goto() ,将先前创建的页面定向到指定的 URL。终极,浏览器实例与页面一起被烧毁。
完成操纵并完成页面加载后,将分别利用 page.screenshot() 和  page.pdf() 获取屏幕截图和 pdf。你也可以侦听 javascript load 事故,然后实行这些操纵,在生产环境级别下剧烈发起如许做。
在终端上运行 node crawler.js  ,几秒钟后,你会留意到已经创建了两个文件,分别名为  screenshot.jpg 和 page.pdf。
Nightmare:Puppeteer 的替换者

Nightmare 是类似 Puppeteer 的高级浏览器自动化库,该库利用 Electron,但听说速率是其前身 PhantomJS 的两倍。
如果你在某种水平上不喜欢 Puppeteer 或对 Chromium 捆绑包的巨细感到沮丧,那么 nightmare 是一个抱负的选择。起首,运行以下下令安装 nightmare 库:npm install nightmare
然后,一旦下载了 nightmare,我们将用它通过 Google 搜刮引擎找到 ScrapingBee 的网站。创建一个名为crawler.js的文件,然后将以下代码复制粘贴到此中:
const Nightmare = require('nightmare')const nightmare = Nightmare()nightmare    .goto('https://www.google.com/')    .type("input[title='Search']", 'ScrapingBee')    .click("input[value='Google Search']")    .wait('#rso > div:nth-child(1) > div > div > div.r > a')    .evaluate(        () =>            document.querySelector(                '#rso > div:nth-child(1) > div > div > div.r > a'            ).href    )    .end()    .then((link) => {        console.log('Scraping Bee Web Link': link)    })    .catch((error) => {        console.error('Search failed:', error)    })起首创建一个 Nighmare 实例,然后通过调用 goto() 将该实例定向到 Google 搜刮引擎,加载后,利用其选择器获取搜刮框,然后利用搜刮框的值(输入标签)更改为“ScrapingBee”。完成后,通过单击 “Google搜刮” 按钮提交搜刮表单。然后告诉 Nightmare 比及第一个链接加载完毕,一旦完成,它将利用 DOM 方法来获取包含该链接的定位标记的 href 属性的值。
末了,完成全部操纵后,链接将打印到控制台。
总结


  • Node.js 是 Javascript 在服务器端的运行时环境。由于事故循环机制,它具有“非壅闭”性子。
  • HTTP客户端(比方 Axios、Superagent 和 Request)用于将 HTTP 哀求发送到服务器并吸取响应。
  • Cheerio 把  JQuery 的优点抽出来,在服务器端 举行 Web 爬取是唯一的目标,但不实行 Javascript 代码。
  • JSDOM 根据尺度 Javascript规范 从 HTML 字符串中创建一个 DOM,并允许你对实在行DOM操纵。
  • Puppeteer and Nightmare  是高级(high-level )浏览器自动化库,可让你以编程方式去操纵 Web 应用,就像真实的人正在与之交互一样。
原文地址:https://www.scrapingbee.com/blog/web-scraping-javascript/
作者:Shenesh Perera
更多编程干系知识,请访问:编程教学!!
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-11-21 23:18, Processed in 0.182512 second(s), 32 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表