《最新出炉》系列初窥篇-Python+Playwright自动化测试-30-处理日历时间控件-下篇
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的调用做一下铺垫和入门。
《最新出炉》系列初窥篇-Python+Playwright自动化测试-30-处理日历时间控件-下篇的更多相关文章
- 《手把手教你》系列技巧篇(三十八)-java+ selenium自动化测试-日历时间控件-下篇(详解教程)
1.简介 理想很丰满现实很骨感,在应用selenium实现web自动化时,经常会遇到处理日期控件点击问题,手工很简单,可以一个个点击日期控件选择需要的日期,但自动化执行过程中,完全复制手工这样的操作就 ...
- 《手把手教你》系列技巧篇(三十七)-java+ selenium自动化测试-日历时间控件-上篇(详解教程)
1.简介 我们在实际工作中,有可能遇到有些web产品,网页上有一些时间选择,然后支持按照不同时间段范围去筛选数据.网页上日历控件一般,是一个文本输入框,鼠标点击,就会弹出日历界面,可以选择具体日期.这 ...
- wxpython 支持python语法高亮的自定义文本框控件的代码
在研发闲暇时间,把开发过程中比较重要的一些代码做个珍藏,下面的代码内容是关于wxpython 支持python语法高亮的自定义文本框控件的代码,应该是对大家也有用. import keywordimp ...
- Python:GUI之tkinter学习笔记1控件的介绍及使用
相关内容: tkinter的使用 1.模块的导入 2.使用 3.控件介绍 Tk Button Label Frame Toplevel Menu Menubutton Canvas Entry Mes ...
- 第十一篇 -- 如何实现MFC窗口的最大化以及控件随最大化
这一篇介绍的是怎么实现MFC窗口的最大最小化,以及里面控件大小也随之改变 第一步:实现窗口最大最小化 首先右击窗口空白处,打开properties,将里面的MaximizeBox和MinimizeBo ...
- Python -- Gui编程 -- Tkinter的使用 -- 基本控件
1.按钮 tkBtton.py import tkinter root = tkinter.Tk() btn1 = tkinter.Button(root, anchor=tkinter.E,\ te ...
- kettle系列-[KettleUtil]kettle插件,类似kettle的自定义java类控件
该kettle插件功能类似kettle现有的定义java类插件,自定java类插件主要是支持在kettle中直接编写java代码实现自定特殊功能,而本控件主要是将自定义代码转移到jar包,就是说自定义 ...
- appium+python:自己写的一个滑动控件的方式
#调用方式roll_ele("ID","ele_id","7","up",3)#将控件分为7格,从底部倒数第二格向上滑动 ...
- selenium python 时间控件的输入问题
对于时间的选择问题,查到的大部分为两种情况: 1.存在readonly属性的 2.没有readonly属性的 可直接赋值send_keys() 测试用例中刚好是没有readonly属性的 且定位不到弹 ...
- android自己定义控件系列教程-----仿新版优酷评论剧集卡片滑动控件
我们先来看看优酷的控件是怎么回事? 仅仅响应最后也就是最顶部的卡片的点击事件,假设点击的不是最顶部的卡片那么就先把它放到最顶部.然后在移动到最前面来.重复如次. 知道了这几条那么我们就非常好做了. 里 ...
随机推荐
- 【技术实战】Vue技术实战【五】
需求实战一 效果展示 代码展示 <template> <div class="home-component"> <div class="pr ...
- OpenLayers文档
https://openlayers.org/en/latest/apidoc/module-ol_interaction_DragZoom-DragZoom.html#changed
- 【go笔记】使用标准库flag解析命令行参数
前言 Go语言标准库中提供了一个包flag可以解析命令行参数. 示例代码:文件读取 package main import ( "fmt" "flag" &qu ...
- [ABC146E] Rem of Sum is Num
2023-02-27 题目 题目传送门 翻译 翻译 难度&重要性(1~10):4 题目来源 AtCoder 题目算法 数学 解题思路 先对整个序列求前缀和 \(sum_k=\sum_{i=1} ...
- ABP Framework 7.4 RC 新增功能简介:增强微服务架构支持
ABP Framework 版本号:7.4.0-rc.1 发布时间:2023.8.16 阅读原文:ABP.IO Platform 7.4 RC Has Been Published 翻译:iEricL ...
- 每天一道面试题:Spring的Bean生命周期
Spring的Bean生命周期包括以下步骤: 1.实例化(Instantiation):当Spring容器接收到创建Bean的请求时,它会先实例化Bean对象.这个过程可以通过构造函数.工厂方法或者反 ...
- KRpano项目微信出现"关于潜在的违法或违规内容"
最近,部分小伙伴反应某些KRPano项目在微信中,出现"关于潜在的未发或违规内容"而无法播放的问题,会看到下图中的提示: 出现原因 这个问题是由于KRPano项目中的webvr.j ...
- SQL Server查询数据库中的表
SQL Server查询数据库中的表 SSMS中用不了MySQL中的show 查询当前数据库中所有表名: SELECT name FROM sysobjects WHERE (xtype = 'U') ...
- Solution -「ARC 103B」Robot Arms
Description Link. 给定 \(n\) 组坐标.构造长度为 \(m\) 的序列 \(\{c_n\}\) 和 \(n\) 组包含 LRUD 的路径,满足对于每一组坐标: \(c_i\) 表 ...
- tiptop查询通配符
*:表示任何符合的字符,例:A*,表示要找出全部为 A 开头的资料. ?:表示任一符合的字符,例:A?,表示要找出第一码为 A,第二码为任何 字符,但总共只有二码之数据. 注:以上二功能仅可在文字字段 ...