天天看點

puppeteer 包模拟登入 模拟iframe網站自動登入

之前寫了個chrome 擴充來完成公司内部的一個需求。在一個網站上實作了自動化程式,包括登入,後續操作,保持狀态,被踢出後再次登入等等。

但是這個網站突然前幾天更新了登入方式,在登入頁面嵌入了iframe,使用内嵌的iframe登入。我還是用chrome擴充試了一下,但是chrome擴充無法操作iframe。

隻能轉換思路,最終群友提供了一個線索,找到了一個google官方出的node包

puppeteer

,順利的完成了自動登入的流程。隻能說這個包真強大,群友玩的真多。

是以以下内容和代碼都為了解決一個問題:

使用 puppeteer 自動登入内嵌 iframe 頁面登入的的網頁,并監控到登入狀态失效後,自動再次登入

本文預設您會使用

node

npm

, 以下腳本基于node14.15.0,在node 12版本上運作通過

所需要的插件包
"devDependencies": {
    "carlo": "^0.9.46",
    "puppeteer-core": "^5.4.0"
  }
           

puppeteer

puppeteer-core

的差別

puppeteer

的核心是

puppeteer-core

puppeteer

會下載下傳

Chromium

,而

puppeteer-core

不會自動下載下傳

Chromium

puppeteer

運作時預設使用

puppeteer-core

來驅動

Chromium

puppeteer

還能配置

PUPPETEER_*

。我這裡使用了

puppeteer-core

,調用本地

google chrome

準備工作

const puppeteer = require('puppeteer-core');

//find_chrome子產品來源于GoogleChromeLabs的Carlo,可以檢視本機安裝Chrome目錄
const findChrome = require('./node_modules/carlo/lib/find_chrome');

const width = 1366; //浏覽器寬度
const height = 768; //浏覽器高度
let browser = null 
  , page = null 
  , init = false // 初次運作腳本
  , isOk = false; // 觸發登入事件開關
           

以上導入了必須的子產品,提前聲明了需要的資料

1 傳入配置 建立浏覽器對象

const newBrowser = async () => {
  init = true; // 已經建立了浏覽器對象
  let findChromePath = await findChrome({});
  let executablePath = findChromePath.executablePath;  //得到本機chrome路徑

  browser = await puppeteer.launch({
    executablePath, // 本地chrome路徑
    headless: false, // 啟用頁面GUI方式
    devtools: false, // F12打開控制台
    args: [
      `--disable-extensions-except=/Users/mac/project/debug/rechargenew`, // 不屏蔽這個擴充
      `--window-size=${width},${height}`, // 視窗大小
      `–disable-gpu` // 禁用 GPU加速
    ],
    defaultViewport: { width: width, height: height } // 頁面大小
  });

  page = await browser.newPage(); // 建立浏覽器

  newhtml()
}
           

此時到這裡桌面就會打開一個chrome浏覽器

2 打開指定的頁面

// 建立打開google頁面
const newhtml = async () => {

  await page.goto('http://www.xxxx.com/', {
    waitUntil: 'networkidle2'
  });

  startLogin()
}
           

運作到這裡會打開指定頁面

3 開啟自動登入

// 開始登入
const startLogin = async (callback) => {
  const startLogin = await page.$(".submit-btn");

  if (startLogin) {
    page.click(".submit-btn")
  }

  // 檢測到 iframe 請求傳回回來了 再等5秒鐘開始自動填寫賬号密碼登入
  page.on('response', async req => {
	// 判斷目前這個請求是不是請求 iframe 登入頁面
    if (req.url().indexOf('xxxx.xxxx.com/xxxx') >= 0 && !isOk) {
      isOk = true // 阻止重複運作
      setTimeout(async () => {
        await page.waitFor('[id*="xxxxx"]');//等待我的iframe出現
        const frame = (await page.frames())[2]
        frame.click("#tab-password")

        await frame.waitFor(3000);
        
        await frame.waitFor('.ruleForm-pwd .form-item1 input');//等待使用者名框出現
        await frame.type('.ruleForm-pwd .form-item1 input', 'xxxx');//輸入使用者名
        await frame.waitFor('.ruleForm-pwd .passwordInput input');//等待密碼輸入框出現
        await frame.type('.ruleForm-pwd .passwordInput input', 'xxxx');//輸入密碼

		// 點選登入
        setTimeout(() => {
          frame.click(".loginBtnWrap .loginBtn")

          setTimeout(() => {
            page.click(".banner-info .submit-btn")
          }, 2000);

        }, 1000);
      }, 5000);

    }
  });
}
           

在這裡使用

page.on('response')

監聽到特定的請求接口傳回後,開始填入賬号和密碼準備登入

有些地方需要用到延時器等待dom或者js操作完成,才能進行下一步,這樣較為保險。

檢測登入狀态是否失效

// 檢查是否被踢出登入  被踢出登入後重新登入
setInterval(() => {
  console.log(page.url());
  
  if (page.url().indexOf("xxx.xxx.com/index.html?") >= 0 && init) {
    isOk = false
    newhtml()
  }
  
}, 20000);
           

這裡開啟了一個定時器,判斷目前宿首頁面的url是否是登入頁面的url,如果是登入頁面的url,就判定目前登入狀态已經失效了,然後再次重新開機登入流程。

完整代碼:

const puppeteer = require('puppeteer-core');

//find_chrome子產品來源于GoogleChromeLabs的Carlo,可以檢視本機安裝Chrome目錄
const findChrome = require('./node_modules/carlo/lib/find_chrome');
const width = 1366;
const height = 768;
let browser = null
  , page = null
  , init = false // 初次運作
  , isOk = false; // 觸發登入事件開關

const newBrowser = async () => {
  init = true;
  let findChromePath = await findChrome({});
  let executablePath = findChromePath.executablePath;

  browser = await puppeteer.launch({
    executablePath,
    headless: false,
    devtools: false, // F12打開控制台
    args: [
      `--disable-extensions-except=/Users/mac/project/debug/rechargenew`, // 不屏蔽這個插件
      `--window-size=${width},${height}`, // 視窗大小
      `–disable-gpu`
    ],
    defaultViewport: { width: width, height: height } // 頁面大小
  });

  page = await browser.newPage();

  newhtml()
}
// 建立打開google頁面
const newhtml = async () => {

  await page.goto('http://www.xxxx.com/', {
    waitUntil: 'networkidle2'
  });

  startLogin()
}

// 開始登入
const startLogin = async (callback) => {
  const startLogin = await page.$(".submit-btn");

  if (startLogin) {
    page.click(".submit-btn")
  }

  // 檢測到 iframe 請求傳回回來了 再等5秒鐘開始自動填寫賬号密碼登入
  page.on('response', async req => {

    if (req.url().indexOf('xxxxx.xxxxxx.com/xxxx') >= 0 && !isOk) {
      isOk = true // 阻止重複運作
      setTimeout(async () => {
        await page.waitFor('[id*="xxxxx"]');//等待我的iframe出現
        const frame = (await page.frames())[2]
        frame.click("#tab-password")

        await frame.waitFor(3000);
        
        await frame.waitFor('.ruleForm-pwd .form-item1 input');//等待使用者名框出現
        await frame.type('.ruleForm-pwd .form-item1 input', 'xxxxxxx');//輸入使用者名
        await frame.waitFor('.ruleForm-pwd .passwordInput input');//等待密碼輸入框出現
        await frame.type('.ruleForm-pwd .passwordInput input', 'xxxxx');//輸入密碼
		// 點選登入
        setTimeout(() => {
          frame.click(".loginBtnWrap .loginBtn")

          setTimeout(() => {
            page.click(".banner-info .submit-btn")
          }, 2000);

        }, 1000);
      }, 5000);

    }
  });
}

newBrowser()

// 檢查是否被踢出登入  踢出登入後重新登入
setInterval(() => {
  console.log(page.url());

  if (page.url().indexOf("xxxxxxx.xxxxxxx.com/index.html?") >= 0 && init) {
    isOk = false
    newhtml()
  }
  
}, 20000);
           

注意點

  • 合理運用定時器和延時器,防止dom還未生成時,使用了相關代碼
  • --disable-extensions-except

    插件路徑的寫法,在mac中上面寫法是正确的。在window中,

    \

    字元需要替換成

    /

    ,這裡浪費了好多時間🐶
  • 擷取

    frame

    dom樹,

    page.frames()

    傳回的集合需要找到指定的frame,試了好多方法,最後直接暴力去2了

參考連接配接

新手必須看的

大佬翻譯的puppeteer文檔

puppeteer之iframe1

puppeteer之iframe2

puppeteer之iframe3

微信群大佬都在等着你

微信掃描二維碼加入微信群,交流學習,及時擷取代碼最新動态。

puppeteer 包模拟登入 模拟iframe網站自動登入

繼續閱讀