今日任務: DOM 陣列操作
下圖為自己簽署當中,Assign 標籤的頁面,假設我們想要把元素放到指定的位子,和之前一樣,我們需要先透過 selector 找到頁面上的元素,再將滑鼠移動到指定的位子然後點擊。大家可以發現,左側所有的欄位,它們的 selector (在這邊是 class )都是一樣的,所以才對今天的任務下了「DOM陣列操作」的命名。
在本日任務中,將會示範把簽名(Signature)放入頁面的過程。
動作A:索取到頁面左側所有的元素
- Inspect 左側元素,發現它們的 class 是 "sc-hARARD.dlziMd"
- 在A區塊寫下
const fields = page.$$(".sc-hARARD.dlziMd") console.log("The length of fields is ", fields.length) //利用console.log看看fields裡面有幾個元素,預期是六個。
執行程式,卻得到0個結果,然後也沒有 Error Message 。這是因為它尋找對應元素時,該元素還沒有被 loading 到頁面上,所以我們的確會得到0這個答案。
為了確定頁面有先 load 進我們的目標元素,我們可以在剛剛的程式碼上方加入
awiat page.waitForSelector(".sc-hARARD.dlziMd")
這次就會是6個了。
動作B: 點選簽名欄位(Signature)
在有了 fields 變數之後,要對 Signature 進行操作就變得非常簡單,我們在B區塊當中寫下
await fields[0].click
結果卻什麼都沒有反應,坦白說這是我預期之外的事情XD,因為我自己之前是這樣子做但是很順利地就成功點擊了,不過沒關係,在 Issues 上也有人有相同的困擾,他們也提供了一些方法來代替click。
(link:https://github.com/puppeteer/puppeteer/issues/3347 (ctrl+f: evaluate))
(link:https://github.com/puppeteer/puppeteer/issues/2526 (ctrl+f: querySelectorAll 第三個))
參考了上面的兩個連結,看到有一個我們之前都沒有用過的函式,evaluate
,其中,我們參考上方圖片當中提供的做法,其程式碼為
await page.evaluate(() => { document.querySelectorAll('.qv64e')[1].click(); });
我們可以利用 evaluate
把想要執行的動作包在裡面,而因為我們的動作是單純的 click
事件,並不需要回傳什麼東西,所以箭頭(=>)符號前面放一個空的小括號就可以了,在 Puppeteer的技術文件當中也有提到一些有回傳值的例子,大家可以看看。
總之,上方程式碼和我們想要做的事情非常的相近,可以代替 page.click
,而且也能同時透過陣列的形式指定操作元素,非常的方便。
所以我們把B區塊的程式碼改成
await page.evaluate(() => { document.querySelectorAll('.sc-hARARD.dlziMd')[0].click(); });
這時候應該就可以得到我們預期的畫面了
動作C: 點選 Eric (如果有遇到沒有姓名標籤的情況,這要先建立一個自己的簽名,建一次就一勞永逸了)
- Inspect 發現它的class是 "sc-jQMNup.bugmmO"
- 在C區塊再次嘗試基本的
click
動作XD(希望這次不要沒有反應),不過因為自己有以前的經驗,知道會需要等待頁面 loading 元素,所以我們也加上waitForSelector
await page.waitForSelector(".sc-jQMNup.bugmmO") await page.click(".sc-jQMNup.bugmmO")
這時候右上方就會跳出 Apply 按鈕
動作D: 點擊Apply按鈕
- Inspect 發現它的 class 是 "sc-fjdhpX.cXKOsV"
- 在D區塊寫下,
這時候會發現自己的滑鼠變成十字,這是在提示我們可以進行下一個動作了,要移動滑鼠到指定位置,並左鍵頁面。await page.click(".sc-fjdhpX.cXKOsV")
動作E: 左鍵頁面
在E區塊寫下:
await page.waitFor(1)
await page.mouse.click(500,175) // 大家可以針對自己喜歡的位置做調整
這裡的程式碼很直覺,page.mouse.click(500,175)
,後面的座標就是我們希望它點的地方。至於為甚麼會需要 waitFor(1)
,是因為我發現如果少了這行程式碼,click
事件就沒有如預期的做出我們想要做的事情。一般而言,是不希望看到使用 waitFor(x)
這種函式,因為它會降低程式的執行效率,不過在這裡的情況比較不同,我們不像是之前可以 waitForSelector
可以等待元素出現之後立即下一個動作,我們現在是要對滑鼠做動作,並沒有像是 waitForMouse
之類的函式,所以我們就折衷使用 waitFor(1)
來確保mouse.click
可以順利被觸發。
下圖為執行成果:
有將簽名檔順利地放上我們的檔案就算是完成今日的任務了,以下是目前的程式碼,
今天的總結:
- 在點擊陣列中其中一個元素時,雖然沒有順利地被執行,但也因此多認識了
page.evaluate
的辦法。(參考動作A) - 有時候要 Assign 頁面元素給變數時,可以利用
waitForSelector
確保元素有真的存在。(參考動作C) page.mouse.click(x,y)
的用法(參考動作E)
下回預告: 做到這邊的大家應該都已經非常熟悉 Puppeteer 的語法了,在明天我們就會把剩下的一點點的操作完成了!