《最新出炉》系列初窥篇-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自己定义控件系列教程-----仿新版优酷评论剧集卡片滑动控件
我们先来看看优酷的控件是怎么回事? 仅仅响应最后也就是最顶部的卡片的点击事件,假设点击的不是最顶部的卡片那么就先把它放到最顶部.然后在移动到最前面来.重复如次. 知道了这几条那么我们就非常好做了. 里 ...
随机推荐
- Java并发(十三)----共享存在的问题
1.小故事 老王(操作系统)有一个功能强大的算盘(CPU),现在想把它租出去,赚一点外快 小南.小女(不同的线程)来使用这个算盘来进行一些计算,并按照时间给老王支付费用 但小南不能一天24小时使用算盘 ...
- 文心一言 VS 讯飞星火 VS chatgpt (66)-- 算法导论6.5 5题
五.试分析在使用下列循环不变量时,HEAP-INCREASE-KEY 的正确性:在算法的第4~6行 while循环每次迭代开始的时候,子数组 A[1..A.heap-size]要满足最大堆的性质.如果 ...
- 2021-7-11 Vue的自定义指令简单实例
获取焦点简单实例,用Vue.directive(ps:指令)定义,命名不要是关键字,用v-加自定义指令名称调用,而内部用钩子函数inserted来实现 <!DOCTYPE html> &l ...
- C#/.net/DotNet/Emgu.CV裁剪照片头像
头像裁剪有利于人脸识别批量照片预处理,安防领域可以快速通过视频定位人脸,进行抓拍,做人脸识别相关功能的可能会应用到人脸裁剪,以下是我在实践中应用的代码,如有需要复制粘贴即可使用. using Emgu ...
- PostgreSql: 安装与链接
环境介绍 使用宝塔面板,在阿里云中安装PostgreSql,并使用DataGrip在本地进行链接 postgresql 配置 安装postgresql 在宝塔中安装postgresql 管理器 在此处 ...
- TypeChat源码分析:基于大语言模型的定制化 AI Agent 交互规范
TypeChat源码分析:基于大语言模型的定制化 AI Agent 交互规范 本文深入介绍了微软最近发布的 TypeChat 项目,该项目允许开发者定义大语言模型返回的响应结构.通过分析源代码,探讨了 ...
- SQL-去除最大值与最小值求均值的问题
背景 今天有同事问我一道关于数据库SQL的面试题,我刚开始随便给了一个思路,后来思索发现这个思路有漏洞,于是总结下来,仅供参考. 问题: 薪水表中是员工薪水的基本信息,包括雇员编号,和薪水,查询除去最 ...
- 从redis未授权访问到获取服务器权限
从redis未授权访问到获取服务器权限 好久没写博客了,博客园快荒芜了.赶紧再写一篇,算是一个关于自己学习的简要的记录把. 这里是关于redis未授权访问漏洞的一篇漏洞利用: 首先是redis,靶场搭 ...
- 用ChatGPT三分钟免费做出数字人视频- 提升自媒体魅力
本教程收集于:AIGC从入门到精通教程汇总 操作指引 ChatGPT产生文案=>腾讯智影数字人播报=>粘贴文案=>导出视频. 说明:部分资源只有会员才能用~,非会员可生成5分钟视频. ...
- MindSponge分子动力学模拟——Constraint约束
技术背景 在前面的几篇博客中,我们已经介绍了MindSponge的基本使用方法,比如定义一个分子系统.计算分子的单点能以及迭代器的使用等.有了这些基础的教程,用户以及可以执行一些比较简单的模拟任务,比 ...