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的全選功能。

相關文章
相關標籤/搜索