《最新出炉》系列初窥篇-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自己定义控件系列教程-----仿新版优酷评论剧集卡片滑动控件
我们先来看看优酷的控件是怎么回事? 仅仅响应最后也就是最顶部的卡片的点击事件,假设点击的不是最顶部的卡片那么就先把它放到最顶部.然后在移动到最前面来.重复如次. 知道了这几条那么我们就非常好做了. 里 ...
随机推荐
- 用python selenium提取网页中的所有<a>标签中的超级链接地址
urls = driver.find_elements_by_xpath("//a") for url in urls: print(url.get_attribute(" ...
- [nginx]lua控制请求头
前言 nginx原生提供expires.add_header两个指令控制请求头,在Lua API中也有类似的指令. 添加请求头 指令:ngx.req.set_header 语法:ngx.req.set ...
- 【go笔记】使用WaitGroup控制协程退出
前言 正常情况下,主协程一旦退出,其子协程也会全部中止并退出.为了阻塞主协程,可以使用time.Sleep(),也可以使用WaitGroup. 用法说明 // 导入sync import " ...
- 浏览器Xbox 云游戏教程
我这里使用的是韩国的地方因为延迟和网速会比较快 Xbox 云游戏韩国网站 Xbox.com에서 Xbox Cloud Gaming(베타) 首先插件商店下载一个油猴插件 在系统语言和时区改为韩国 在 ...
- 6、Spring之基于xml的自动装配
6.1.场景模拟 6.1.1.创建UserDao接口及实现类 package org.rain.spring.dao; /** * @author liaojy * @date 2023/8/5 - ...
- 一个超经典 WinForm 卡死问题的最后一次反思
一:背景 1. 讲故事 在我分析的 200+ dump 中,同样会遵循着 28原则,总有那些经典问题总是反复的出现,有很多的朋友就是看了这篇 一个超经典 WinForm 卡死问题的再反思 找到我,说 ...
- 使用 AutoGPTQ 和 transformers 让大语言模型更轻量化
大语言模型在理解和生成人类水平的文字方面所展现出的非凡能力,正在许多领域带来应用上的革新.然而,在消费级硬件上训练和部署大语言模型的需求也变得越来越难以满足. Hugging Face 的核心使命是 ...
- AI绘画工具MJ新功能有点东西,小白也能轻松一键换装
先看最终做出来的效果 直接来干货吧.Midjourney,下面简称MJ 1.局部重绘功能来袭 就在前两天,MJ悄咪咪上线了这个被众人期待的新功能:局部重绘. 对于那些追求创新和个性化的设计师来说,局部 ...
- Mysql进击篇-存储引擎、索引、sql优化、视图、锁、innoDb、管理
1.存储引擎 (1)连接层 最上层是一些客户端和连接服务,主要完成一些类似于连接处理,授权认证.以及相关的安全方案,服务器也会为安全接入的每个客户端验证它所具有的操作权限 (2)服务层 第二层架构主要 ...
- 探秘移动端BI:发展历程与应用前景解析
什么是移动端BI 维基百科 上对于 移动端商业智能的定义是这样的 > Mobile BI is a system that presents historical and real-time i ...