Node.js + electron-vue 使用selenium-webdriver 對瀏覽器進行操作

在使用electron-vue寫自動化測試軟件的時候,遇到了一些關於使用selenium-webdriver的坑,來記錄一下
一、環境配置

由於vue並沒有實際運行在node的運行時中,所以,在vue中引入selenium-webdriver會引發 no such module 的報錯,這個錯誤當時困擾了我很久,因爲確實沒有意識到是不同運行時環境的問題。所以,基於這一點,我選擇了在本地起一個node服務,通過訪問node,來對selenium進行操作

const app = require('express')
const { Builder, By } = require('selenium-webdriver')

const server = app()

server.use((req, res, next) => {
  if (req.path !== '/' && !req.path.includes('.')) {
    res.set({
    // 由於vue啓動時會自己佔用一個端口,所以我們在服務端進行配置解決跨域問題
      'Access-Control-Allow-Credentials': true,
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Headers': 'X-Requested-With,Content-Type,access-token',
      'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS',
      'Content-Type': 'application/json; charset=utf-8'
    })
  }
  req.method === 'OPTIONS' ? res.status(204).end() : next()
})

var port = 10099
var host = 'localhost'
server.listen(port, host, () => {
  console.log(`server running @ http://${host}:${port}`)
})

server.get('/openWeb', function (req, res) {
// 這個是對selenium進行操作的函數,會在稍後貼出
  jsOpenWeb()
})

這種解決方案的問題在於,需要通過命令行來啓動本地的node服務,我這邊使用electron可以在background.js中添加node child_process代碼

// 命令行啓動node服務,可以放在app.on('ready') 中
function startServer () {
  const cmdStr = 'node localServer.js'
  var exec = require('child_process').exec(cmdStr, function (error, stdout, stderr) {
    console.log(error)
    console.log(stdout)
  })
  exec.on('close', function (code) {
    console.log(code)
  })
}
二、操作瀏覽器

參考selenium文檔

相關的代碼可以參考以上文檔,但是,在js的sdk中,幾乎所有的操作均是異步執行,即所有的函數均返回Promise對象,這裏是第二個卡住我的地方,因爲我一開始並沒有理解Promise是什麼,直到和做前端的同學聊天時才得知,這是一個用於異步操作的對象,於是將原來的同步執行代碼均換爲異步執行

/**
*1.說明一下,中間註釋的部分爲之前在Chrome中測試網站會有彈窗,註釋部分爲濾除彈窗用的
*2.由於涉及到正在做抓取的網站,所以,我把域名換成百度了,都差不多,不過需要着重注意
   在一個頁面有frame的時候,一定要將焦點通過switchTo函數切換到frame中,否則,
   無法獲取網頁元素。如果沒有frame存在,直接摘掉switchTo().frame() 代碼塊即可操作
*/
function jsOpenWeb () {
  const broswer = new Builder().forBrowser('internet explorer').build()
  broswer.get('https://www.baidu.com')
  // broswer.wait(until.alertIsPresent()).then(() => {
    // broswer.switchTo().alert().accept().then(() => {
      //broswer.findElement(By.id('fraInterface')).then((value) => {
        console.log(value)
        broswer.switchTo().frame(value).then(() => {
        //下面兩行代碼效果一樣的
        //通過元素id找到該元素並寫入值
          broswer.findElement(By.id('kw')).sendKeys('搜索內容')
        //通過元素name找到該元素並寫入值
          broswer.findElement(By.name('')).sendKeys('搜索內容')
        })
     // })
   // })
  // })
}
三、報錯處理

1.記得把所有需要的瀏覽器驅動(IEDriverServer/ChromDriver)等等加入到環境變量中,Mac(usr/bin) Win(控制面板->系統與安全->系統->高級系統設置->高級->環境變量,將driver的路徑填寫進去就可以)

2.關於元素未找到的錯誤:
這個問題有網速相關,有frame嵌套的原因,但是在js的sdk中,更多的是沒有異步執行的關係,比如你實際上並沒有切入到frame中,就要去獲取frame中的一個input是肯定不行的,所以,建議多打斷點和log

3.IE下,input元素輸入速率過慢:
如果出現了在給input寫入值的時候,幾秒鐘才蹦出一個字符的這種現象時,請檢查你的IEDriver,看看是否是32位的,如果不是,請換成32位

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章