最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Node 系列 - 006 - Puppeteer

    正文概述 掘金(jsliang)   2021-06-19   956

    在前面的 5 篇文章打底下,咱们应该接入点接地气的业务了。

    本篇开始将接触前端多语言功能,将讲解如何使用 Puppeteer 控制 Chrome/Chromium,从而达到下载文件的目的。

    一 目录

    不折腾的前端,和咸鱼有什么区别

    目录
    一 目录二 前言三 Puppeteer 3.1 抓取快照 3.2 下载文件四 参考文献

    二 前言

    Puppeteer 是一个 Node 库,它提供了一个高级 API 来通过 DevTools 协议控制 Chromium 或 Chrome。

    就跟它在 GitHub 简介中介绍的一样:你在浏览器中手动执行的绝大多数操作都可以使用 Puppeteer 来完成!

    • 抓取页面快照
    • 生成页面 PDF
    • 自动操作页面 DOM
    • ……

    详细例子小伙伴可以翻看本文下方参考文献的 GitHub 或者中文文档,这里不一一举例(免得被吐槽复制 README.md)

    三 Puppeteer

    • 安装:npm i puppeteer

    jsliang 安装的时候报错:

    • (node:7584) ExperimentalWarning: The fs.promises API is experimental

    我的 Node.js 版本是 node@10.16.0,所以需要升级 Node.js。

    查了下资料有 2 种方法升级,一种是下载最新版覆盖安装,另一种是通过 nvm/nvmw 方式去管理。

    jsliang 网络还不错,直接下载个最新文档版吧:Node 官网

    安装完毕后查看下最新版本:

    • node -vv14.17.1

    这时候再安装 Puppeteer,显示安装成功,package.json 显示:"puppeteer": "^10.0.0"

    安装完毕,开始搞事~

    3.1 抓取快照

    我们拿抓取页面快照做个简单举例:

    import program from 'commander';
    import common from './common';
    import './base/console';
    import puppeteer from 'puppeteer';
    
    program
      .version('0.0.1')
      .description('工具库')
    
    program
      .command('jsliang')
      .description('jsliang 帮助指令')
      .action(() => {
        common();
      });
    
    program
      .command('test')
      .description('测试频道')
      .action(async () => {
        // 启动浏览器
        const browser = await puppeteer.launch({
          headless: false, // 打开实体浏览器
        });
    
        // 创建新标签页并打开
        const page = await browser.newPage();
        await page.goto('https://www.baidu.com/s?wd=jsliang');
    
        // 获取快照并存储到本地
        await page.screenshot({
          path: './src/baidu.png',
        });
    
        // 关闭窗口
        await browser.close();
      });
    
    program.parse(process.argv);
    

    执行完 npm run test 之后,src 文件夹里面会出现图片文件 baidu.png,打开展示如下:

    Node 系列 - 006 - Puppeteer

    这样我们就初步了解 Puppeteer 啦,当然它还可以导出 PDF 等,自行翻下文【参考文献】中的内容对 Puppeteer 进一步了解吧。

    3.2 下载文件

    既然我们可以获取到截图,那么我们能操作 DOM 也就不足为奇,咱们获取下线上的文件吧!

    拿文档举例,咱们先创建一个 Excel 文件:

    Node 系列 - 006 - Puppeteer

    创建方式可以自己去玩玩,就不做讲解了,文档地址:https://www.kdocs.cn/

    然后,我们下个环节就是需要将这个 Excel 下载下来(假设已经请人做好翻译工作了),就是这样的 Excel:

    Node 系列 - 006 - Puppeteer

    然后咱们搞个简单的吧:

    Node 系列 - 006 - Puppeteer

    OK,文件有了,咱们怎样才能下载下来呢?现在情况是:

    • 试想一下如果我们通过 Puppeteer 打开,那是无头浏览器啊,跟无痕差不多了,如果正常登录的话,需要重新登录、进入链接,然后才是点击按钮,进行下载。

    所以,这里用到文档的免登录链接:

    Node 系列 - 006 - Puppeteer

    这里提供上面的 Demo 地址,小伙伴们可以拿来练习,但是不确保这个链接会不会哪天就被我删了,所以按照上面步骤自行设置一个吧!

    • 【文档 Excel 试用文件.xlsx】:https://www.kdocs.cn/l/sdwvJUKBzkK2

    OK,罗里吧嗦讲了那么多前置条件,下面咱们进入正题 —— 如何获取到线下文件:

    1. 操作浏览器打开 https://www.kdocs.cn/l/sdwvJUKBzkK2
    2. 睡眠 6.66s(确保浏览器打开链接并加载页面)
    3. 然后触发【更多菜单】按钮的点击
    4. 睡眠 2s(确保更多菜单按钮点击到)
    5. 设置下载路径(确保下载位置,要不然弹窗就不好处理)
    6. 最后触发【下载】按钮的点击
    7. 睡眠 10s(确保资源下载到)
    8. 关闭窗口

    上面唯一要关注的点是第 5 点,因为我们 Windows 点击下载是会有弹窗的(并不是默认下载),所以需要提前设置好下载路径(代码中会体现)。

    Node 系列 - 006 - Puppeteer

    那么,上代码!

    import { inquirer } from '../base/inquirer';
    import { Result } from '../base/interface';
    import { sortCatalog } from './sortCatalog';
    import { downLoadExcel } from './downLoadExcel';
    
    const common = (): void => {
      // 问题路线:看 questionList.ts
      const questionList = [
        // q0
        {
          type: 'list',
          message: '请问需要什么服务?',
          choices: ['公共服务', '文件管理']
        },
        // q1
        {
          type: 'list',
          message: '当前公共服务有:',
          choices: ['文件排序']
        },
        // q2
        {
          type: 'input',
          message: '需要排序的文件夹为?(绝对路径)',
        },
        // q3
        {
          type: 'list',
          message: '请问需要什么支持?',
          choices: ['多语言', 'Markdown 转 Word'],
        },
        // q4
        {
          type: 'list',
          message: '请问需要什么支持?',
          choices: [
            '下载多语言资源',
            '导入多语言资源',
            '导出多语言资源',
          ],
        },
        // q5
        {
          type: 'input',
          message: '资源下载地址(HTTP)?',
          default: 'https://www.kdocs.cn/l/sdwvJUKBzkK2',
        }
      ];
    
      const answerList = [
        // q0
        async (result: Result, questions: any) => {
          if (result.answer === '公共服务') {
            questions[1]();
          } else if (result.answer === '文件管理') {
            questions[3]();
          }
        },
        // q1
        async (result: Result, questions: any) => {
          if (result.answer === '文件排序') {
            questions[2]();
          }
        },
        // q2
        async (result: Result, _questions: any, prompts: any) => {
          const sortResult = await sortCatalog(result.answer);
          if (sortResult) {
            console.log('排序成功!');
            prompts.complete();
          }
        },
        // q3
        async (result: Result, questions: any) => {
          if (result.answer === '多语言') {
            questions[4]();
          }
        },
        // q4
        async (result: Result, questions: any) => {
          if (result.answer === '下载多语言资源') {
            questions[5]();
          }
        },
        // q5
        async (result: Result, _questions: any, prompts: any) => {
          if (result.answer) {
            const downloadResult = await downLoadExcel(result.answer);
            if (downloadResult) {
              console.log('下载成功!');
              prompts.complete();
            }
          }
        },
      ];
    
      inquirer(questionList, answerList);
    };
    
    export default common;
    
    

    看到上面的代码我后悔了,为啥 Inquirer.ts 被我改造的那么恶心,弄得 jsliang 还需要特地写个文件来表明问题序列然后才捋顺问题顺序:

    // common 板块的问题咨询路线
    export const questionList = {
      '公共服务': { // q0
        '文件排序': { // q1
          '需要排序的文件夹': 'Work 工作', // q2
        },
      },
      '文件管理': { // q0
        '多语言': { // q3
          '下载多语言资源': { // q4
            '下载地址': 'Work 工作', // q5
          },
          '导入多语言资源': { // q4
            '导入地址': 'Work 工作',
          },
          '导出多语言资源': { // q4
            '导出全量资源': 'Work 工作',
            '导出单门资源': 'Work 工作',
          }
        },
        'Markdown 转 Word': '暂未支持', // q3
      },
    };
    

    写完后转入写功能上:

    import puppeteer from 'puppeteer';
    import path from 'path';
    import fs from 'fs';
    
    export const downLoadExcel = async (link: string): Promise<boolean> => {
      // 启动浏览器
      const browser = await puppeteer.launch({
        headless: false, // 打开实体浏览器
        devtools: true, // 打开开发模式
      });
    
      // 1. 创建新标签页并打开
      const page = await browser.newPage();
      await page.goto(link);
    
      // 2. 睡眠 6.66s - 确保页面正常打开
      await page.waitForTimeout(6666);
    
      // 3. 触发【更多菜单】按钮的点击
      const moreBtn = await page.$('.header-more-btn');
      moreBtn?.click();
    
      // 4. 睡眠 1s - 确保按钮点击到
      await page.waitForTimeout(2000);
    
      // 5. 设置下载路径
      const dist = path.join(__dirname, './dist');
      if (!fs.existsSync(dist)) {
        fs.mkdirSync(dist);
      }
      await (page as any)._client?.send('Page.setDownloadBehavior', {
        behavior: 'allow',
        downloadPath: dist,
      });
    
      // 6. 触发【下载】按钮的点击
      const elements = await page.$$('.header-menu-item');
      let downloadBtn;
      if (elements.length) {
        downloadBtn = elements[8];
      }
      if (!downloadBtn) {
        console.error('没找到下载按钮');
        await browser.close();
      }
      await downloadBtn?.click();
    
      // 7. 睡眠 10s - 确保资源下载到
      await page.waitForTimeout(10000);
    
      // 8. 关闭窗口
      await browser.close();
    
      return await true;
    };
    

    这样子运行之后,如果控制台不报错,那么 VS Code 展示为:

    Node 系列 - 006 - Puppeteer

    可以看到 common 目录下的确有 dist/Excel 试用文件.xlsx 了,咱们就可以接入 node-xlsx 这个库来操作 Excel 啦~

    下期见!

    四 参考文献

    • Github: Puppeteer
    • Puppeteer
    • puppeteer 前端利器
    • Puppeteer 之爬虫入门


    起源地下载网 » Node 系列 - 006 - Puppeteer

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元