博客 / 詳情

返回

Puppeteer實踐:複雜的問題簡單化

最近遇到一個需求需要將上千條的數據寫入到基於Wordpress搭建的系統中,但是對於底層數據錄的寫入邏輯不是很清楚,通過sql各種寫入也沒有完全達到效果。

後面想了想或許可以換一個方向,不能從底層邏輯寫入數據那就通過正常操作寫入。由於數據量大所以需要自動化處理,這時候就想到了之前用過的Puppeteer,這個庫可以模擬操作瀏覽器的各種行為,包括獲取數據和操作提交等。對於這個場景很適合,不用管底層的實現邏輯,也不需要去扒源碼瞭解各種加密加簽的邏輯,只需要模擬操作提交數據即可。

複雜的問題瞬間簡單了,在這篇文章中記錄如何使用Puppeteer批量提交數量。

安裝Puppeteer

在這之前確保你已經安裝了Node.js。運行以下命令安裝Puppeteer:

npm install puppeteer

Puppeteer腳本

接下來編寫需要執行的腳本,創建一個名為puppeteer.js的文件,並添加以下代碼:

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: false 
  });
  const page = await browser.newPage();
  await page.goto('https://baidu.com');   
  await browser.close();
})();

puppeteer.launch() 是用於啓動一個瀏覽器實例,為後續的網頁操作和自動化測試提供基礎。可以接受一些配置選項,如指定瀏覽器的路徑、是否啓用無頭模式、設置視口大小等。完整配置還有很多,可查閲官網瞭解。

保持用户狀態

需要寫入的系統是需要登錄後才能操作且需要多次操作,所以在操作過程中需要記錄用户狀態。這一點我們可以在初始化瀏覽器實例的時候配置 userDataDiruserDataDir 用於指定一個目錄,該目錄用於存儲瀏覽器的用户數據,如緩存、Cookie、本地存儲數據等。可以讓 Puppeteer 在每次啓動瀏覽器時都使用相同的用户數據,從而保持用户狀態的連續性。

const browser = await puppeteer.launch({
    userDataDir: 'userA' 
});

模擬登錄

然後就是第一次的模擬登錄和後續操作校驗登錄狀態。通過 page.cookies() 獲取存儲的用户數據,如果不存在則模擬登錄。

// 從puppeteer中獲取cookie
const cookies = await page.cookies(); 
let isLogin = false
cookies.forEach(json => {
    if (json.name.includes('wordpress')) {
        isLogin = true
    }
});

console.log('[ isLogin ] >', isLogin)

if (!isLogin) {
    // 模擬輸入用户名密碼
    await page.type('#user_login', 'XXXX', { delay: 100 });
    await page.type('#user_pass', 'XXXX', { delay: 100 });
    // 模擬點擊
    await page.click('#rememberme', { delay: 110 });
    await page.click('#wp-submit', { delay: 120 });  
     // 等待頁面完全加載
    await page.waitForNavigation()   
}

數據處理

接下來就是業務數據處理了,首先將數據轉換成JSON方便批量處理。每次處理一批數組,這裏在for循環中使用 Promise 同步處理,待所有的數據都處理完成後關閉瀏覽器結束腳本。在 performAsyncOperation 中執行具體的數據操作過程。

const list = require('./list.js')

function performAsyncOperation(item) {
    return new Promise(async (resolve, reject) => {
        // todo item
        resolve();
    });
}

// 使用async函數來包裹異步操作
async function processItems() {
    for (const item of list) {
        // 使用await等待異步操作完成
        await performAsyncOperation(item); 
    }
    console.log('All items processed');
    await browser.close();
}

processItems()

這裏有一點特殊處理,要寫入的數據是在iframe中的元素,需要通過以下方式對iframe中的dom進行修改賦值。

const elementHandle = await page.waitForSelector('#content_ifr');
const frame = await elementHandle.contentFrame();
await frame.waitForSelector('p:nth-child(1)');
const description = item.description
// 在 iframe 中使用 evaluate 方法來修改元素內的 DOM
await frame.evaluate((description) => {
    // 在這裏可以編寫 JavaScript 代碼來修改 iframe 內的 DOM
    document.querySelector('p:nth-child(1)').textContent = description
}, description);

更新完一條數據後進行下一條數據的寫入,這裏頁面提交數據後界面發生了變化,需要重新回到開始的頁面繼續處理。回到開始的發佈頁面後執行成功回調繼續下一條數據處理,當所有的數據處理完成則結束腳本。

// 點擊發布
await page.click('#publish')
// 等待頁面更新
await page.waitForNavigation()
// 點擊回到發佈頁面
await page.click('.page-title-action', { delay: 300 })
// 成功回調繼續下一條處理
resolve();

總結

Puppeteer是一個強大的庫,它能夠讓開發者以編程方式控制Chrome或Chromium。這使數據獲取或操作頁面數據變得更加容易,特別是對於需要與JavaScript交互的頁面。

通過上面的例子,你應該對如何使用Puppeteer來處理數據有了一個基本的瞭解。Puppeteer的能力遠不止於此,你可以創建更復雜的腳本來模擬用户登錄、填寫表單、獲取簽名數據等。希望這篇文章對你有所幫助~


看完本文如果覺得有用,記得點個贊支持,收藏起來説不定哪天就用上啦~

專注前端開發,分享前端相關技術乾貨,公眾號:南城大前端(ID: nanchengfe)

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.