1.簡介
理想很豐滿現實很骨感,在應用playwright實現web自動化時,經常會遇到處理日期控制元件點選問題,手工很簡單,可以一個個點選日期控制元件選擇需要的日期,但自動化執行過程中,完全複製手工這樣的操作就有點難了或者是有些複雜囉嗦而且麻煩不過相對於selenium來說,playwright已經很好了。宏哥上一篇已經講解了如何處理日曆時間控制元件,但是有些網站不知道出於什麼原因,對於第一種方法可能會遇到輸入框是readonly的情況,禁止輸入文字。那麼第一種方法就不適用了,但是隻要我們換個思路然後稍微的變通地處理一下,就又可以使用了。
2.問題
宏哥第一種方法地思路就是把它當做輸入框,直接輸入日期即可,想法是很美好的,但是有時候實行起來卻不執行,這個時候我們就要仔細去看看前端的程式碼了,程式碼如下:
<div class="col-lg-3 form-input"> <input id="createTime" class="form-control" type="text" readonly="readonly" name="tatsudoDate" onclick="WdatePicker()" aria-required="true"> </div>
從上邊的程式碼可以看出屬性readonly人家根本不允許你輸入,你就行不通了。
3.想法
既然這樣了,我們就稍微變通一下,不要一條道走到黑。這個時候我們可以移除readonly的屬性,問題就輕輕鬆鬆解決了,程式碼如下:
# 原生js,移除元素的readonly屬性 js1 = 'document.getElementById("createTime").removeAttribute("readonly");' page.evaluate(js1) # 直接給輸入框輸入日期 js2 = 'document.getElementById("createTime").value="2023-11-11";' page.evaluate(js2)
4.專案實戰
網上找了半天也沒有找到這樣的例子,以前12306的日曆是這種。最近升級了,已經不是這種了。不找了索性宏哥自己在本地做一個這樣的小demo給小夥伴或者童鞋們來演示一下。
4.1程式碼準備
4.1.1前端HTML程式碼
前端HTML程式碼如下:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script src="dateJs.js"></script> <link rel="stylesheet" type="text/css" href="date.css"> </head> <body> <div id="wrapper" style="position: relative;top: 100px;left:600px;"> <button class="button1"><a id="myAnchor" href="https://www.cnblogs.com/du-hong/">北京-宏哥</a></button></br> <input type="text" id="Dateinput" readonly=""/> <div class="calendar" id="calender" style="display: none;"> </div> </div> </body> </html>
4.1.2CSS樣式
HTML滑塊CSS樣式程式碼如下:
* { margin: 0; padding: 0; } body { font-size: 13px; } .calendar { width: 330px; } .calendar .title { position: relative; width: 100%; height: 30px; line-height: 30px; background: #17a4eb; } .title div { position: absolute; } .prev { left: 10px; } .now { left: 40%; } .next { right: 10px; } input { height: 30px; width: 326px; } table { width: 100%; border-collapse: collapse; } table th { border: 1px solid #ccc; } table td { text-align: center; border: 1px solid #ccc; } .red { background-color: #a1cbdb; } .blue { background-color: #e4e3e3; } .button1 { background-color: #f44336; border: none; color: white; padding: 15px 32px; text-align: center; text-decoration: none; display: inline-block; font-size: 28px; margin-bottom: 100px; text-decoration: none; color: white; } #myAnchor { text-decoration: none; color: white; }
4.1.3日曆JS
日曆JS程式碼如下:
window.onload = function () { //獲取日期 輸入框 var oInput = document.getElementById('Dateinput'); //獲取日曆 var oCalender = document.getElementById('calender'); //獲取當前日期 var oDate = new Date(); //獲取當年 年 var year = oDate.getFullYear(); //獲取當前 月 var month = oDate.getMonth() + 1; //日曆框不能重複建立 var flag = false; //日期輸入框 獲取焦點時 載入日曆 oInput.onfocus = function () { showDate(year, month); } //顯示日曆 function showDate(year, month) { if (false == flag) { //1.日曆標題 var oTitle = document.createElement('div'); oTitle.className = 'title'; //1.1日曆標題文字 var prevM = 0; var nextM = 0; prevM = month - 1; nextM = month + 1; //當月份為1時 上一個月為12 if (month == 1) { prevM = 12; }//當月份為12時 下一個月為1 else if (month == 12) { nextM = 1; } var titleHtml = ""; titleHtml += '<div class="prev" id="prev"><span>'; titleHtml += prevM + '</span>月</div>'; titleHtml += '<div class="now">'; titleHtml += '<span class="span">'; titleHtml += year; titleHtml += '</span>年'; titleHtml += '<span class="span">' + month; titleHtml += '</span>月</div>'; titleHtml += '<div class="next" id="next"><span>'; titleHtml += nextM + '</span>月</div>'; oTitle.innerHTML = titleHtml; //將日曆標題 拼接到日曆 oCalender.appendChild(oTitle); //1.2獲取日曆 表頭元素(以便新增事件) var oSpans = oCalender.getElementsByTagName('span'); var prevMonth = oSpans[0]; var nextMonth = oSpans[3]; var nowMonth = oSpans[2]; var nowYear = oSpans[1]; //2.建立星期 表頭 var otable = document.createElement('table'); var othead = document.createElement('thead'); var otr = document.createElement('tr'); //2.1表頭內容填充 var arr = ['日', '一', '二', '三', '四', '五', '六']; for (var i = 0; i < arr.length; i++) { //建立th var oth = document.createElement('th'); oth.innerHTML = arr[i]; otr.appendChild(oth); } //2.2將表頭加入到日曆 othead.appendChild(otr); otable.appendChild(othead); oCalender.appendChild(otable); //3.新增 當前日曆 全部日期 //3.1.先獲得當期月 有多少天 var dayNum = 0; if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { dayNum = 31; } else if (month == 4 || month == 6 || month == 9 || month == 11) { dayNum = 30; } else if (month == 2 && isLeapYear(year)) { dayNum = 29; } else { dayNum = 28; } //3.2.建立 6行7列 日期容器 var otbody = document.createElement('tbody'); for (var i = 0; i < 6; i++) { var otr = document.createElement('tr'); for (var j = 0; j < 7; j++) { var otd = document.createElement('td'); otr.appendChild(otd); } otbody.appendChild(otr); } otable.appendChild(otbody); //3.3獲得 1號對應的是星期幾 //3.3.1.將當月1號賦值給日期變數 oDate.setFullYear(year); //注意 js日期的月份是從0 開始計算 oDate.setMonth(month - 1); oDate.setDate(1); //3.3.2.計算1號在第一行日期容器中的位置,依次給日期容器填充內容 //注意 js中 getDay方法是獲取當前日期是星期幾 var week = oDate.getDay(); var otds = oCalender.getElementsByTagName('td'); for (var i = 0; i < dayNum; i++) { otds[i + week].innerHTML = i + 1; } //讓當前日期顯示紅色、後面的顯示藍色 showColor(otds); //給左右月份繫結點選事件 monthEvent(); //判斷最後一行是否全為空 lastTr(otds); flag = true; document.getElementById('calender').style.display = "block"; } } //判斷是否是閏年 function isLeapYear(year) { if (year % 100 == 0 && year % 400 == 0) { return true; } else if (year % 100 != 0 && year % 4 == 0) { return true; } else { return false; } } //判斷日期容器最後一行是否有值 function lastTr(otds) { var flag = true; for (var i = 35; i < 42; i++) { if (otds[i].innerHTML != '') { flag = false; } } //全是空的 if (flag) { for (var i = 35; i < 42; i++) { otds[i].style.display = 'none'; } } } //當前日期顯示紅色、前面的顯示灰色 function showColor(otds) { //當前日期 var nowday = new Date().getDate(); var nowyear = new Date().getFullYear(); var nowmonth = new Date().getMonth(); var oCalendar = document.getElementById("calender"); ospans = oCalendar.getElementsByTagName('span'); var contralYear = ospans[1].innerHTML; var contralMonth = ospans[2].innerHTML; var oindex = 0; for (var i = 0; i < otds.length; i++) { if (nowday == otds[i].innerHTML && nowyear == contralYear && nowmonth + 1 == contralMonth) { otds[i].className = 'red'; oindex = i; } } } //給左右月份繫結點選事件 function monthEvent() { var oCalendar = document.getElementById("calender"); var prevDiv = document.getElementById("prev"); var nextDiv = document.getElementById("next"); var prevMonth = prevDiv.getElementsByTagName("span"); var nextMonth = nextDiv.getElementsByTagName("span"); prevDiv.onclick = function () { flag = false; oCalendar.innerHTML = ''; showDate(year, parseInt(prevMonth[0].innerHTML)); } nextDiv.onclick = function () { flag = false; oCalendar.innerHTML = ''; showDate(year, parseInt(nextMonth[0].innerHTML)); } } }
5.自動化程式碼實現
5.1程式碼設計
5.2參考程式碼
# coding=utf-8? # 1.先設定編碼,utf-8可支援中英文,如上,一般放在第一行 # 2.註釋:包括記錄建立時間,建立人,專案名稱。 ''' Created on 2023-10-27 @author: 北京-宏哥 QQ交流群:705269076 公眾號:北京宏哥 Project: 《最新出爐》系列初窺篇-Python+Playwright自動化測試-29-處理日曆時間控制元件-下篇 ''' # 3.匯入模組 from playwright.sync_api import Playwright, sync_playwright, expect def run(playwright: Playwright) -> None: browser = playwright.chromium.launch(headless=False) context = browser.new_context() page = context.new_page() page.goto("C:/Users/DELL/Desktop/test/Calendar/Calendar.html") page.wait_for_timeout(3000) # 原生js,移除元素的readonly屬性 js1 = 'document.getElementById("Dateinput").removeAttribute("readonly");' page.evaluate(js1) # 直接給輸入框輸入日期 js2 = 'document.getElementById("Dateinput").value="2023-11-11";' page.evaluate(js2) page.wait_for_timeout(2000) context.close() browser.close() with sync_playwright() as playwright: run(playwright)
5.3執行程式碼
1.執行程式碼,右鍵Run'Test',控制檯輸出,如下圖所示:
2.執行程式碼後電腦端的瀏覽器的動作(成功將23年的光棍節輸入進去了)。如下圖所示:
6.小結
好了,時間不早了,今天就分享到這裡,感謝大家耐心的閱讀,這一篇內容其實是為後邊文章的JavaScript的呼叫做一下鋪墊和入門。