网页 抓取 innertext 试题(Chrome+Puppeteer+NodeJS)和HeadlessChrome一起装逼一起飞)

优采云 发布时间: 2022-03-13 02:13

  网页 抓取 innertext 试题(Chrome+Puppeteer+NodeJS)和HeadlessChrome一起装逼一起飞)

  JavaScript自动化爬虫入门指南(Chrome + Puppeteer + Node JS)和Headless Chrome假装一起飞

  

  Udemy 黑色星期五特卖 — 数以千计的 Web 开发和软件开发课程限时发售,仅售 10 美元!完整的详细信息和课程推荐可以在这里找到。

  简单的介绍

  本文将教您如何使用 JavaScript 自动化网络爬虫,技术上使用 Google 团队开发的 Puppeteer。Puppeteer 运行在 Node 上,可用于操作无头 Chrome。什么是无头 Chrome?通俗的讲,它使用提供的 API 来模拟用户的浏览行为,而无需打开 Chrome 浏览器。

  如果你还是不明白,你可以想象 Chrome 浏览器使用 JavaScript 完全自动化。

  前言

  确保您已安装 Node 8 及更高版本。如果没有,可以先从官网下载安装。请注意,“当前”处显示的版本号必须大于 8。

  如果您是 Node 新手,最好查看介绍性教程:Learn Node JS — The 3 Best Online Node JS Courses。

  安装 Node 后,创建一个项目文件夹并安装 Puppeteer。安装 Puppeteer 的过程会附带下载匹配版本的 Chromium 指定浏览器的执行路径):

  npm install --save puppeteer

复制代码

  示例 1 - 网页截图

  一旦安装了 Puppeteer,我们就可以开始编写一个简单的示例。这个例子是直接复制官方文档的,可以对给定的网站进行截图。

  首先创建一个任意名字的js文件,这里我们以test.js为例,输入如下代码:

  const puppeteer = require('puppeteer');

async function getPic() {

const browser = await puppeteer.launch();

const page = await browser.newPage();

await page.goto('https://google.com');

await page.screenshot({path: 'google.png'});

await browser.close();

}

getPic();

复制代码

  让我们逐行分析上面的代码。

  细心的读者会发现getPic()前面多了一个async前缀,表示getPic()方法是异步方法。async 和 await 成对出现,是 ES 2017 的新功能。由于它是异步方法,因此在调用后返回一个 Promise 对象。当 async 方法返回一个值时,对应的 Promise 对象会传递这个值来解析(如果抛出异常,则会将错误信息传递给 Reject)。

  在 async 方法中,可以使用 await 表达式暂停方法的执行,直到表达式中的 Promise 对象完全解析,然后继续向下执行。看不懂也没关系,后面我会详细解释,到时候你就明白了。

  接下来,我们将深入研究 getPic() 方法:

  const browser = await puppeteer.launch();

复制代码

  这段代码用于启动 puppeteer,本质上是打开一个 Chrome 实例,然后将这个实例对象赋给变量 browser。因为使用了 await 关键字,所以这里运行的代码会阻塞(暂停)直到 Promise 被解析(不管执行结果是否成功)

  const page = await browser.newPage();

复制代码

  接下来在上面得到的浏览器实例中新建一个页面,返回后将新创建的页面对象赋值给变量page。

  await page.goto('https://google.com');

复制代码

  使用上面得到的页面对象,用它来加载我们给的URL地址,然后暂停代码的执行,直到页面加载完毕。

  await page.screenshot({path: 'google.png'});

复制代码

  页面加载后,您可以对页面进行截图。screenshot() 方法接受一个对象参数,该参数可用于配置保存屏幕截图的路径。注意,不要忘记添加 await 关键字。

  await browser.close();

复制代码

  最后,关闭浏览器。

  运行示例

  在命令行输入以下命令执行示例代码:

  node test.js

复制代码

  这是示例的屏幕截图:

  

  不是很棒吗?这只是一个热身,这里是如何在非无头环境中运行代码。

  非无头?百闻不如一见,先自己试一试,把代码放在第4行:

  const browser = await puppeteer.launch();

复制代码

  用这句话替换它:

  const browser = await puppeteer.launch({headless: false});

复制代码

  然后再次运行:

  node test.js

复制代码

  是不是更酷了?配置了 {headless: false} 后,可以直观的看到代码是如何控制 Chrome 浏览器的。

  这里还有一个小问题。之前我们的截图有点不完整,是因为页面对象的默认截图尺寸有点小。我们可以通过以下代码重置页面的视口大小,然后截图:

  await page.setViewport({width: 1000, height: 500})

复制代码

  这要好得多:

  

  最终代码如下:

  const puppeteer = require('puppeteer');

async function getPic() {

const browser = await puppeteer.launch({headless: false});

const page = await browser.newPage();

await page.goto('https://google.com');

await page.setViewport({width: 1000, height: 500})

await page.screenshot({path: 'google.png'});

await browser.close();

}

getPic();

复制代码

  示例 2 - 抓取数据

  通过上面的例子,你应该已经掌握了Puppeteer的基本用法,我们来看一个稍微复杂一点的例子。

  在开始之前,先看看。你会发现 Puppeteer 可以做很多事情,比如模拟鼠标点击、填写表单数据、输入文本、读取页面数据等等。

  在接下来的教程中,我们将爬取一本名为 Books To Scrape 网站 的书,这个网站 是专门为开发者做爬虫练习的。

  还是在之前创建的文件夹中,新建一个js文件,这里以scrape.js为例,然后输入如下代码:

  const puppeteer = require('puppeteer');

let scrape = async () => {

// Actual Scraping goes Here...

// Return a value

};

scrape().then((value) => {

console.log(value); // Success!

});

复制代码

  有了前面例子的经验,这段代码应该不难理解。如果你还是不明白……没关系。

  首先引入puppeteer依赖,然后定义一个scrape()方法来编写爬虫代码。这个方法返回一个值,然后我们会处理这个返回值(示例代码直接打印这个值)

  首先在scrape方法中加入下面这行来测试:

  let scrape = async () => {

return 'test';

};

复制代码

  在命令行输入node scrape.js,如果没有问题,控制台会打印一个测试字符串。测试通过后,我们继续细化scrape方法。

  第一步:前期准备

  与示例 1 一样,首先获取浏览器实例,创建一个新页面,然后加载 URL:

  let scrape = async () => {

const browser = await puppeteer.launch({headless: false});

const page = await browser.newPage();

await page.goto('http://books.toscrape.com/');

await page.waitFor(1000);

// Scrape

browser.close();

return result;

};

复制代码

  我们再分析一下上面的代码:

  首先我们创建一个浏览器实例并将headless设置为false,这样我们就可以直接看到浏览器的运行情况:

  const browser = await puppeteer.launch({headless: false});

复制代码

  然后新建一个标签页:

  const page = await browser.newPage();

复制代码

  使用权:

  await page.goto('http://books.toscrape.com/');

复制代码

  以下步骤是可选的,让代码暂停 1 秒以确保页面可以完全加载:

  await page.waitFor(1000);

复制代码

  任务完成后,关闭浏览器,返回执行结果。

  browser.close();

return result;

复制代码

  步骤 1 结束。

  第 2 步:攀爬

  打开Books to Scrape 网站后,你一定发现里面有很多书,但数据都是假的。让我们开始简单,我们首先抓取页面上第一本书的数据并返回其标题和价格信息(红色边框选择的那个)。

  

  检查文档,我注意到这个方法模拟了一个页面点击:

  page.click(选择器[,选项])

  在这里可以使用开发者工具查看元素的选择器,在图片上右击选择inspect:

  

  上述操作会打开开发者工具栏,之前选中的元素也会高亮显示。这时候点击前面的三个小点,选择复制-复制选择器:

  

  有了元素选择器后,再加上前面找到的元素点击方法,得到如下代码:

  await page.click('#default > div > div > div > div > section > div:nth-child(2) > ol > li:nth-child(1) > article > div.image_container > a > img');

复制代码

  然后你会观察到浏览器点击第一本书的图片,页面会跳转到详情页。

  在详情页,我们只关心书名和价格信息——见图中红框。

  

  要获取此数据,您需要使用 page.evaluate() 方法。此方法可用于执行浏览器内置的 DOM API,例如 querySelector()。

  首先创建 page.evaluate() 方法并将其返回值保存在 result 变量中:

  const result = await page.evaluate(() => {

// return something

});

复制代码

  同样,要在方法中选择我们要使用的元素,再次打开开发者工具,选择需要检查的元素:

  

  标题是一个简单的 h1 元素,使用以下代码获得:

  let title = document.querySelector('h1');

复制代码

  事实上,我们需要的只是元素的文本部分。我们可以在它之后添加 .innerText。代码如下:

  let title = document.querySelector('h1').innerText;

复制代码

  获取价格信息也是如此:

  

  price 元素上只有一个 price_color 类。您可以使用该类作为选择器来获取与价格对应的元素:

  let price = document.querySelector('.price_color').innerText;

复制代码

  这样,标题和价格就在那里,将它们放入一个对象并返回:

  return {

title,

price

}

复制代码

  回看刚才的操作,我们得到了标题和价格信息,保存在一个对象中返回,并将返回的结果赋值给result变量。所以,现在你的代码应该是这样的:

  const result = await page.evaluate(() => {

let title = document.querySelector('h1').innerText;

let price = document.querySelector('.price_color').innerText;

return {

title,

price

}

});

复制代码

  然后只需要返回结果,返回的结果会打印到控制台:

  return result;

复制代码

  最后,合并后的代码如下:

  const puppeteer = require('puppeteer');

let scrape = async () => {

const browser = await puppeteer.launch({headless: false});

const page = await browser.newPage();

await page.goto('http://books.toscrape.com/');

await page.click('#default > div > div > div > div > section > div:nth-child(2) > ol > li:nth-child(1) > article > div.image_container > a > img');

await page.waitFor(1000);

const result = await page.evaluate(() => {

let title = document.querySelector('h1').innerText;

let price = document.querySelector('.price_color').innerText;

return {

title,

price

}

});

browser.close();

return result;

};

scrape().then((value) => {

console.log(value); // Success!

});

复制代码

  在控制台中运行代码:

  node scrape.js

// { title: 'A Light in the Attic', price: '£51.77' }

复制代码

  如果操作正确,您将在控制台中看到正确的输出。至此,您已经完成了网络爬虫。

  示例 3 - 后期完美

  稍微想一想,你会发现标题和价格信息是直接显示在首页的,所以不需要进入详情页去抓取这些数据。在这种情况下,我们不妨进一步想一想,能不能抓取到所有书籍的书名和价格信息?

  所以,爬取的方式其实有很多种,需要自己去发现。另外,上面提到的直接从主页抓取数据也不一定可行,因为某些标题可能无法完全显示。

  提出问题

  目标 - 抓取首页所有书籍的书名和价格信息,并以数组的形式保存并返回。正确的输出应如下所示:

  

  去吧,伙计,实现几乎和上面的例子一样。如果你觉得太难,可以参考以下提示。

  暗示:

  其实最大的不同就是需要遍历整个结果集。代码的一般结构如下:

  const result = await page.evaluate(() => {

let data = []; // 创建一个空数组

let elements = document.querySelectorAll('xxx'); // 选择所有相关元素

// 遍历所有的元素

// 提取标题信息

// 提取价格信息

data.push({title, price}); // 将数据插入到数组中

return data; // 返回数据集

});

复制代码

  如果提示后还是不行,好吧,下面是参考答案。在以后的教程中,我会在以下代码的基础上做一些扩展,也会涉及到一些更高级的爬取技术。您可以在此处提交您的电子邮件地址进行订阅,我们会在有新内容更新时通知您。

  参考答案:

  const puppeteer = require('puppeteer');

let scrape = async () => {

const browser = await puppeteer.launch({headless: false});

const page = await browser.newPage();

await page.goto('http://books.toscrape.com/');

const result = await page.evaluate(() => {

let data = []; // 创建一个数组保存结果

let elements = document.querySelectorAll('.product_pod'); // 选择所有书籍

for (var element of elements){ // 遍历书籍列表

let title = element.childNodes[5].innerText; // 提取标题信息

let price = element.childNodes[7].children[0].innerText; // 提取价格信息

data.push({title, price}); // 组合数据放入数组

}

return data; // 返回数据集

});

browser.close();

return result; // 返回数据

};

scrape().then((value) => {

console.log(value); // 打印结果

});

复制代码

  结论:

  感谢收看!如果您对学习 NodeJS 感兴趣,可以前往 Learn Node JS — The 3 Best Online Node JS Courses。

  每周都会发布4篇关于web开发的技术文章文章,欢迎订阅!或者你可以在 Twitter 上关注我

  掘金翻译项目是一个翻译优质互联网技术文章的社区,文章来源是掘金上的英文分享文章。内容涵盖、、、、、、等领域。如果想看到更多优质翻译,请继续关注掘金翻译计划、官方微博、知乎栏目。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线