Puppeteer——自动化脚本设计

我被分配了一个繁琐的任务,就是要给100个相同的站点作一样的配置。曾经就有作过相同的事,那时还不会写脚本,全靠手动配置。机械的配置了两天的时间,身体感受被掏空。因此此次我决定仍是写一个脚本自动的进行配置。node

1、了解Puppeteer

中文版资料:https://juejin.im/entry/59ad6c4f5188250f4850dccclinux

官方文档(英文):https://github.com/GoogleChrome/puppeteergit

Puppeteer的API(英文):https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#github

 

2、环境

只安装了node环境chrome

 

3、开发阶段

3.1 初始化项目

  引用了https://juejin.im/entry/59ad6c4f5188250f4850dcccnpm

  项目都是以建立文件夹开始。windows

 $ mkdir thal $ cd thal $ mkdir thal $ cd thal

  初始化 NPM,填入一些必要的信息。api

 $ npm init $ npm init 

  安装 Puppeteer。因为 Puppeteer 并非稳定的版本并且天天都在更新,因此若是你想要最新的功能能够直接经过 GitHub 的仓库安装。ruby

 $ npm i --save puppeteer $ npm i --save puppeteer 

  Puppeteer 包含了本身的 chrome / chromium 用以确保能够无界面地工做。所以每当你安装/更新 puppeteer 的时候,他都会下载指定的 chrome 版本。async

3.2 编码

3.2.1 工程的目录结构

node_modeles中的内容是从git上拉下来的,src文件夹写得是我本身的代码,我执行的是addConfig里面的文件,common中是一些基础性配置,contentHub配置内容较多,因此我另建了一个contentHub文件夹。

 

3.2.2 common.js文件写的是经常使用的功能函数,这个是能够通用的。以前我不是说实现不了全选的功能吗,其实能够调用common中的setOption函数实现全选的功能

 1 const config = require('./config');
 2 
 3 //根据选择器sel选择id为val的子项
 4 async function setOption(page, sel, val) {
 5   await page.evaluate((sel, val) => {
 6     document.querySelector(`${sel} > option[value="${val}"]`).selected = true;
 7     element = document.querySelector(sel);
 8     var event = new Event('change', { bubbles: true });
 9     event.simulated = true;
10     element.dispatchEvent(event);
11   }, sel, val);
12 }
13 
14 //在id为sel的输入框中输入val
15 async function setTextVal(page, sel, val) {
16   await page.evaluate((sel, val) => {
17     document.querySelector(sel).value = val;
18     element = document.querySelector(sel);
19     var event = new Event('change', { bubbles: true });
20     event.simulated = true;
21     element.dispatchEvent(event);
22   }, sel, val);
23 }
24 
25 //判断选择器是否存在
26 async function isExist(page, selector) {
27   var is = await page.evaluate((sel) => {
28     const element = document.querySelector(sel);
29     if (!element) {
30       return false;
31     } else {
32       return true;
33     }
34   }, selector);
35 
36   return is;
37 }
38 
39 //导入单个配置
40 async function importSingleConfiguration(page, configType, configContent) {
41   const confirmBtn = 'input[value="Confirm"]';
42   const configTypeSel = '#edit-config-type';
43   await setOption(page, configTypeSel, configType);
44   await page.click('#edit-import');
45   await setTextVal(page, '#edit-import', configContent);
46   await page.click('#edit-submit');
47   await page.waitForNavigation();
48 
49   const is = await isExist(page, confirmBtn);
50   if (is) {
51     await page.click(confirmBtn);
52     await page.waitForNavigation();
53     await page.waitFor(3 * config.stepWait);
54   }
55 }
56 
57 //设置checkbox中子项的值
58 async function setCheckBoxVal(page, sel, val) {
59   await page.evaluate((sel, val) => {
60     document.querySelector(sel).checked = val;
61     element = document.querySelector(sel);
62     var event = new Event('change', { bubbles: true });
63     event.simulated = true;
64     element.dispatchEvent(event);
65   }, sel, val);
66 }
67 
68 module.exports = {
69   setOption: setOption,
70   setTextVal: setTextVal,
71   importSingleConfiguration: importSingleConfiguration,
72   isExist: isExist,
73   selectAll: selectAll,
74   setCheckBoxVal: setCheckBoxVal,
75 
76 }
View Code

 

3.2.3 config.js文件中申明了许多基础性配置

我要跳转的网站url,登陆的用户名和密码,站内页面跳转的路径等信息都配置在这个文件里面

const baseUrlArray = [
     {
         url: '',
         langcode: '',
     },
];
const baseUrl = baseUrlArray[0].url;

const getUrl = (index) => {
    const baseUrl = baseUrlArray[index].url;
    return {
        hubConnection: `${baseUrl}/example`,
    };
}

const getLangCode = (index) => {
    return baseUrlArray[index].langcode;
}

module.exports = {
    secondWait: 1000,
    stepWait: 5000,
    username: '',
    password: '',
    credentials: {
        username: '',
        password: '',
    },
    baseUrl: baseUrl,
    baseUrlArray: baseUrlArray,
    urls: getUrl(0),
    getUrl: getUrl,
    getLangCode: getLangCode,
}
View Code

 

3.2.4 login.js

 1 const config = require('./config');
 2 
 3 async function login(page, url = null) {
 4 
 5   //fill authenticate user name and password
 6   await page.authenticate(config.credentials);
 7 
 8   // goto login page
 9   await page.goto(url ? url : config.urls.login);
10   const agreeButton = await page.$('#block-popup .btn');
11   await agreeButton.click();
12 
13   //fill admin user name and password
14   await page.focus('#edit-name');
15   await page.keyboard.type(config.username);
16   await page.focus('#edit-pass');
17   await page.keyboard.type(config.password);
18 
19   const inputElement = await page.$('#edit-submit');
20   await inputElement.click();
21 
22   await page.waitForNavigation();
23 }
24 
25 module.exports = login;
View Code

 

3.2.5 好了,登陆成功了

 

4、收获

1.须要被其它页面引用的函数,常量必需要在module.exports={}中申明

2.headles: false是设置自动化操做是可视化的

3.在输入框中输入值并覆盖原有的值:

    4.调用其余页面函数的声明:const common = require('./common');

 

5、疑惑

1.关于全选的功能,puppeteer并不支持全选,虽然官方文档上面说了linux和windows支持全选,可是个人linux系统没有任何反应,估计并不支持。补充一下,我这里说的是实现不了ctrl+A的全选功能。

相关文章
相关标签/搜索