puppeteer入门实践

puppeteer初识

puppeteer是一个node库,他能提供一系列操做Chrome的API,经过这些API咱们能够用程序代码来操纵Chrome去完成各类操做。javascript

他运行在node环境,由Chorme官方团队在维护,既然是操做浏览器,那么咱们能够手动进行的操做在pupeteer上都能进行。前端

另外pupeteer的英文就是木偶的意思,咱们使用他就像操做木偶玩耍同样,能够轻松的作到:java

  • 生成页面 PDF。
  • 抓取页面并生成预渲染内容。
  • 自动提交表单,进行 UI 测试,键盘输入等。
  • 建立一个时时更新的自动化测试环境。 使用最新的 JavaScript 和浏览器功能直接在最新版本的Chrome中执行测试。
  • 捕获网站的 timeline trace,用来帮助分析性能问题。
  • 测试浏览器扩展。
  • ......

固然puppeteer不止能够作这些,经过在代码中注入js脚本,咱们几乎能够作到全部咱们能够用代码实现的功能。node

在puppeteer中,Chrome默认运行在"无头"模式,而所谓的无头模式,不过是不加载浏览器的UI界面,实际上并不会影响咱们的操做。npm

使用无头模式,在无界面的状况下按照咱们编写的代码去运行Chrome,能够减小人为因素的影响,使运行更加稳定。编程

固然咱们能够经过他的属性值headless来控制让页面友好的显示出来,甚至能够控制页面显示多大。json

在前端咱们能够用它来爬取一些页面数据进行分析,能够进行网络请求的拦截来达到某种业务效果,总之puppeteer很是的好用。网页爬虫

既然puppeteer是调用的API来操做的浏览器,那么咱们能够想到,puppeterr下的浏览器,与咱们平时所见到的浏览器有什么不同呢?浏览器

又是什么在吊起了浏览器进程,让咱们可使用代码与浏览器进行通讯的呢?markdown

首先让咱们了解一下puppeteer对浏览器的总体架构的分解

  • Browser: 其实对应一个浏览器实例,有了这个实例以后咱们就能够接着去打开一个浏览器窗口了。
  • BrowserContext:而一个浏览器实例,是能够打开好几个窗口的,他们能够拥有各自的cookie ,session 。
  • Page:表示一个窗口中的一个页面,固然一个窗口能够打开不少个页面。
  • Frame:页面中的 一个框架,每一个页面有一个主框架,主要由 iframe 标签建立产生的
  • ExecutionContext: 是 javascript 的执行环境,每个 Frame 都一个默认的 javascript 执行环境

其次,node库中的这些API,他们实现的原理实际上是经过Chrome DevTools Protocol(CDP) 协议与浏览器进行通讯的。

而node所作的就是将底层经过协议控制的浏览器操做,进行简化封装,让咱们能够简单的使用。

好比下面是经过CDP来进行页面的跳转:

const cdp = new CDP();
await cdp.connect(wsEndpoint);
const targetsResponse = await cdp.send('Target.getTargets');
const pageTarget = targetsResponse.targetInfos.find((t) => t.type === 'page');
const attachResponse = await cdp.send('Target.attachToTarget', { targetId: pageTarget.targetId, flattentrue });
const sessionId = attachResponse.sessionId;
const navigateResponse = await cdp.send('Page.navigate', { url'https://m.jk.cn' }, sessionId);
console.log('navigateResponse', navigateResponse);
复制代码

而使用puppeteer提供的API的话咱们两行代码足以搞定:

const page = await browser.newPage();
await page.goto('https://m.jk.cn');
复制代码

整体来看对话,他先是将咱们平常用到的浏览分红了各个部分,而后实例化出一个浏览器对象,包括浏览器上下文,各个页面等。能够看到,puppeteer实际上是对CDP操做浏览器对代码进行了简化,再由node封装导出API供咱们使用。

再把与浏览器通讯对CDP操做进行简化封装,最后使用node进行导出API,省去了中间复杂的CDP通讯过程,让咱们直接使用代码的方式操做浏览器。

puppeteer实践

咱们使用浏览器,大多的操做都是在页面上进行点击操做,键盘输入操做等,其实浏览器自己提供的还有截图,保存页面pdf等功能。

在经过puppeteer对功能的封装简化以后,咱们使用几行代码即可以完成截图,保存pdf。

值得一提的是,使用puppeteer几乎全部操做都是异步的,会返回Promise,咱们可使用.then去处理,可是在node环境下咱们可使用async,await优雅处理

所以咱们的运行环境Nodejs 的版本不能低于 v7.6.0, 须要支持 async,await。

首先在项目目录下

npm install puppeteer --save
复制代码

这样咱们就能够开始使用puppeteer以编程的方式去操做浏览器啦。

const puppeteer = require('puppeteer');
(async () => {
    const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.goto('https://www.baidu.com');
    await page.screenshot({path: 'baidu.png'});
    await browser.close();
  })();
复制代码

上面的这几行代码就已经实现了咱们从打开浏览器,跳转页面,截图,到关闭浏览器的全部过程

先经过 puppeteer.launch() 建立一个浏览器实例 Browser 对象 而后经过 Browser 对象建立页面 Page 对象 而后 page.goto() 跳转到指定的页面 调用 page.screenshot() 对页面进行截图 关闭浏览器 一样的,若是咱们要获取页面的pdf咱们只须要调用他提供的page下的API

await page.pdf({
      path: 'page.pdf',
      printBackground:true,
      format: 'A4'
    });
复制代码

能够看到,每一个API均可以传入参数,这些参数能够肯定咱们要将获取到的文件保存在哪path,printBackground是否须要背景图,以及要什么样的尺寸format。

更多的参数属性能够参考官方提供的参数说明。

经过puppeteer咱们能够调用简单的API完成一些普通的浏览器操做,除了这些他还能作的事情其实还不少,咱们能够模拟用户实现登陆,或是爬取页面的数据。

结合入门的基础操做,这里以登陆咱们豌豆app为列作一个模拟登陆的demo,如下为部分代码:

(async () => {
  try{
    const browser = await puppeteer.launch({
      headless:false,
      slowMo:300
    });
    const page = await browser.newPage();
    await page.emulate(puppeteer.devices['iPhone 6']);
    await page.goto('https://m.wandougongzhu.cn/user/login');
    await page.tap('.link-btn');
    await page.type('#app > div > div > div:nth-child(3) > input', '12345678901', {delay:300});
    await page.type('#app > div > div > div:nth-child(4) > input', '***********', {delay:300});
    await page.screenshot({ path: 'full.png', fullPage: true });
    await page.tap('#app > div > div > div.btn-box > div');
    await page.waitForTimeout(2000);
    await page.screenshot({ path: 'login.png', fullPage: true });
    await browser.close();
  } catch (error) {
    console.log(error);
  }
})();
复制代码

为了方便展现,咱们能够设置headless为false这样就能够显示浏览器的页面,接着咱们分析一下代码

page.emulate调用此方法可让页面展现为一种手机模式 page.tap是对页面上对DOM元素进行点击,这里咱们点击使用帐号密码登陆 page.type这个方法能够获取页面上对文本输入DOM,获取焦点,并输入内容,这里咱们输入帐号密码 而后获取页面上对登陆按钮,进行点击登陆 在使用page.waitForTimeout作一个页面加载对等待,最后截图关闭

这样咱们就实现了以代码对方式模拟用户进行登陆操做,而且咱们能够设置输入信息对间隔时间,这样能够绕过一些页面对反自动化对规则,保证代码对稳定性。

基于这种操做咱们能够实现一些自动化的测试,好比一些表单的提交,按钮的点击测试,数据的输入等等。

经过上面的demo咱们能够看出,puppeteer的操做大可能是针对与页面上的DOM元素展开的,只要获取到页面上的DOM元素咱们就能够展开一系列的操做。

如今的一些网页大多数都是采用js进行后期的渲染加载,使用puppeteer这种获取到DOM以后在对DOM进行操做对方法,会更稳定一些。

puppeteer 实现爬虫

puppeteer是根据页面上的真实存在的DOM进行各类操做的,那么只要咱们能够获取到DOM元素,咱们就能够获取到元素在页面上展现的值。

根据这个思路,咱们就能够结合js完成一个简单的网页爬虫,经过注入的js代码,切换页面,获取页面DOM元素,进而拿到数据。

(async () => {
  let data = [];
  const browser = await puppeteer.launch({
    headless: false,
  });
  const page = await browser.newPage();
  for (let mo = 1; mo < 4; mo++) {
    for (let pg = 1; pg <= 10; pg++) {
      mo = mo.toString().padStart(2, "0");
      await page.goto(
        "https://www.bilibili.com/v/music/cover/?spm_id_from=333.5.b_7375626e6176.3#" +
          `/all/click/0/${pg}/2021-${mo}-01,2021-${mo}-28`
      );
      await page.waitForSelector(".vd-list-cnt > ul > li > div > div.r > a");
      let titles = await page.$$eval(".vd-list-cnt > ul > li > div > div.r > a", 
      (links) => links.map((item) => item.innerText)
      );
      console.log(titles);
      data = data.concat(titles);
    }
  }
  fs.writeFile("data.json", JSON.stringify(data, null, "\t"), function (err) {
    if (err) {
      console.log(err);
    }
  });
})();
复制代码

上面就是结合js进行的简单的爬虫,一切咱们在页面上看到的,均可以使用puppeteer去爬取,而且能够稳定的爬取到数据,避免一些页面的渲染都在js中,使用日常的爬虫很难在拿到数据。

经过这个简单的爬虫相信你们对puppeteer的印象又加深了很多,但愿你们经过puppeteer与js代码的结合,能够完成一些业务上的难题。

相关文章
相关标签/搜索