优秀的编程知识分享平台

网站首页 > 技术文章 正文

快速开发和分享一个自动打卡程序(自动打卡教程)

nanyue 2024-07-22 14:17:16 技术文章 67 ℃

前面我们通过四个步骤,使用Python开发了一个自动打卡程序:

一、调用Pyautogui库模拟鼠标操作,初步实现了一个简单得自动打卡程序。(文章链接)

二、调用Webbrowser库访问指定网页和登录,完善了自动打卡程序。(文章链接)

三、调用Random库实现了随机延时,避免每天自动打卡时间相同的问题。(文章链接)

四、使用Pystaller库打包Exe文件,将自动打卡程序分享给同事。(文章链接)

但同事没几分钟就跑过来说程序运行有问题:网页自动打开后,鼠标定位出问题了,账号和密码都没有成功输入。

查找原因,原来是自动打卡程序在开发过程中,使用了我个人电脑上账号输入框等网页元素的坐标去,而同事显示器的分辨率和我的不一样,账号输入框等网页元素的坐标并不相同,所以调用Pyautogui库模拟键鼠操作时给的坐标错误,导致程序运行出现问题。

针对这个问题,要提升自动打卡程序的适用范围,有两个解决思路:

一、改变所要操作网页元素的定位方法

主要思路:即不再是通过屏幕坐标来定位网页元素,而是通过网页元素在HTML文档中的路径表达式来获得它的定位,并使用Selenium或是Playwright等Web自动化框架来实现选择和操作网页元素。

那么,如何准确定位并选择网页元素呢?本文使用Selenium框架和XPath路径表达式为例来做演示。(Selenium自动化框架、XPath路径表达式和浏览器开发者工具的相关内容,需要大家做一些准备。具体可以参考《Selenium开发环境和相关工具准备》)。

大致分为3个步骤:

  • 通过浏览器开发者工具找到网页元素对应的代码

通过F12键调出开发者工具,使用元素选择箭头,点中左侧登录界面中的账号输入框,便能看到右侧代码栏中高亮显示的对应代码。

  • 分析识别代码中能够精确选择网页元素的XPath路径表达式

可以使用搜索栏来帮助分析识别,在上一步骤得到账号输入框的代码后(如下),Ctrl+F调出关键字搜索栏。

<input class="node_modules--anyshare-components-lib-Login-styles-desktop---input-login" value="" placeholder="请输入账号" data-reactid=".0.1.1.$content.0.0.0.1.1.0.0.0.1">

试探性输入input标签和class属性组成的XPath表达式,看看能不能选择到唯一的元素。

结果搜索栏中显示找到2个匹配项(如下图红框所示),并没能唯一确定要定位的账号输入框元素。

再次使用input标签和placeholder属性来尝试,这次只有1个匹配项,精确命中。

注意:可能在搜索栏中通过Div标签或者其他标签的路径表达式看起来也能唯一定位到网页元素,但是这些标签不能支持文字输入,所以还要结合后面的步骤一起尝试。

  • 使用Selenium框架选择和操作网页元素

主要代码如下所示:

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from time import sleep 

#创建 WebDriver 对象,指明使用chrome浏览器驱动,就是驱动压缩包解压的路径
wd = webdriver.Chrome(service=Service(r'E:\python-packages\selenium\chromedriver109_win32\chromedriver.exe'))

#implicitly_wait 函数是一种隐式等待,用于处理元素不存在以及元素加载时间不够的情况
wd.implicitly_wait(10)

# 调用WebDriver 对象的get方法 可以让浏览器打开指定网址
wd.get('https://www.baidu.com/')
#等待网页加载
sleep(3)

#根据Xpath定位账号输入框
element=wd.find_element(By.XPATH,'//input[@placeholder="请输入账号"]')
element.send_keys("wangwu")
......

#input('等待回车键结束程序')

由于程序运行完会自动关闭浏览器,速度很快,所以调试的时候最好加上一行input代码,等待用户输入后再退出程序。

上面场景比较简单,所以实现起来非常快速。但在实际选择和操作网页元素时,可能还会遇到需要要切换iFrame、自动翻滚网页等复杂情况,需要进行更细致的分析判断。

经过上面的改造,本单位同事通过文件拷贝方式,就能实现自动打卡程序的即插即用。但如果是其他单位,因为每个单位的打卡系统不一样,所以上述方法无效,应当考虑下面的解决思路。

二、允许用户自定义打卡操作步骤和内容

主要思路:通过一个用户可编辑的文本文件,将键鼠操作函数化、坐标位置和输入内容参数化。使得针对不同的打卡系统、不同的显示环境,用户可以灵活便捷地个性化维护设置打卡操作的步骤和内容。

大致有两部分工作:

  • 确定用户自定义操作的语法规则,并维护到指定文件

简单示例:在程序相同目录下新建一个名为action.txt的文本文件,内容如下:

文件规则:每一行前面是操作命令,后面是参数,中间使用空格分隔。

  • 改造程序,将原来固定的键鼠操作转变成函数
import pyautogui as gui
import webbrowser as web
import re
#按照URL打开网页
def open_url(url):
    web.open(url,new=0,autoraise=True)
    gui.sleep(3)
#鼠标移动
def mouse_move(x,y):
    gui.moveTo(x,y,duration=1)
    gui.sleep(1)
#鼠标单击
def mouse_leftclick():
    gui.leftClick()
    gui.sleep(0.5)
#输入字符
def input_str(str):
    gui.typewrite(str,interval=0.1)
    gui.sleep(0.5)
#休息等待
def sleep(sec):
    gui.sleep(sec)

#操作命令解析
def parse_act(txt):
#根据空格符和回车符分割文本
    action=re.split(' |\n',txt)
    if action[0]=='open_url':
        open_url(action[1])
    elif action[0]=='mouse_move':
        pos=re.split(',',action[1])
        mouse_move(int(pos[0]),int(pos[1]))
    elif action[0]=='mouse_leftclick':
        mouse_leftclick()
    elif action[0]=='input_str':
        input_str(action[1])
    elif action[0]=='sleep':
        sleep(int(action[1]))

if __name__=='__main__':
#按行读取文件内容
    with open("action.txt",'r') as act_file:
        line=act_file.readline()
        while line:
          #调用操作命令解析函数
            parse_act(line)
            line=act_file.readline()

上述代码虽然比较简单,但也涉及到文件的读取,使用正则表达式解析字符串等内容,大家感兴趣可以深度研究。

改造结束,只需要将程序打包好的exe文件和action.txt文件拷贝到其他电脑上(注意2个文件放在相同目录),然后按需自行维护action.txt中的操作步骤和输入参数,即可实现自动打卡。

最近发表
标签列表