python+selenuim实现web自动打卡
python+selenuim实现web自动打卡#
摘要:
大概就是在XX背景下,需要每天登录网站填报体温,所在地信息等,分析登录时发送请求逻辑,通过python-selenium实现自动打卡。
思路#
通过selenium操作浏览器,完成登录->填充表单信息->定时重复打卡。
- 登录: 使用机器完成登录有两种方法,一种通过定位验证码位置通过ocr识别字符,登录后保存cookie,之后往浏览器中填入cookie即可跳过登录, 其次就是手动维护cookie。分析得到当发起登录请求时,客户端将生成随机字符串塞入Request-Header的cookie中,
ASP.NET_SessionId=ryhrbiqalg14hgrxhmhd4ie5
,服务端在Response-Header的Set-Cookie中塞入CenterSoftWeb=xxxxx; expires=Sun, 23-Jan-2022 07:45:06 GMT; path=/; HttpOnly
,由此组成完整的可跳过登录的cookie - 填充表单信息 通过selenium操作浏览器中元素,完成一系列逻辑操作,(需要下载浏览器所对应的驱动driver,chrome+chromedriver)
- 定时重复打卡 Crontab+shell 即可实现每日定时启动
关于selenium-python,请到网站查看
具体实现#
定位验证码位置,由机器识图,首先启动操作selenium在当前运行环境下获取浏览器截图,再将图片导入ps中定位验证码四角位置像素值。
获取到四角位置时,即可保存验证码图片传入ocr机器识别。
#保存截图
browser.save_screenshot('verification/'+stunumber+'.png')
#填入信息
browser.find_element_by_id("StudentId").send_keys(stunumber)
browser.find_element_by_xpath("/html/body/div[1]/div[2]/div/div[2]/form/div[2]/div[2]/input").send_keys(pwd)
#图片剪切
left = 781
top = 336
right = 870
bottom = 369
picture = Image.open('verification/'+stunumber+'.png')
picture = picture.crop((left, top, right, bottom))
picture.save('verification/'+stunumber+'-ed.png')
#ocr识别 接入的是api
yzm_code = moyunocr.getYzm('verification/'+stunumber+'-ed.png')
#获取cookie写入文件
dictCookies = browser.get_cookies()
jsonCookies = json.dumps(dictCookies)
with open('cookies/'+stunumber+'_cookie.txt', 'w') as f:
f.write(jsonCookies)
存储的cookie内容#
ps:获取到的Cookie通过json库对象转为文本了,因此格式与官方定义的cookie格式略有差别。
[
{"domain": "dxg.cxxu.edu.cn", "expiry": 1615705350, "httpOnly": true, "name": "CenterSoftWeb", "path": "/", "secure": false, "value": "08CBB2BBDCB3E268D3EE9D0C8046B4C979910509ACF95A1F302336B2826DCAD9CE60311213F70E114CAF84ED18695CB3C6260D17B502F8D42ADC8966B6886C5C78D8B479AC5F152E8CC526E9517C1CF3783D3462632A5EDC0104C19C58AFCE9B020937BD766C253F8A327AE72F11F5ECD4F91E72021B3ECC9C7232BFBCAEF0BA38ACD4246EA9CD293CD7ADFD1BC682DF7FEB194CB8E433804D93B3CF00B299E55DA5530BF7D32523977316BAF9486DBAB85221C5348E587F05220BC9A44EE8901C33ADD15097D87E8305C0FEF8A4A3B9D2B358172EA280D622DE78B53CAE5EE88379B2600F38740BD2D33CFC0192CCD9B2DCE5C8BE4124A4466623C8A96B2499B25C16C9EA128D19C88BA0FD8BC4746F"},
{"domain": "dxg.cxxu.edu.cn", "httpOnly": true, "name": "ASP.NET_SessionId", "path": "/", "secure": false, "value": "qe45ulzkfahnqjvvexj45kcr"}
]
What Cookie#
基于HTTP协议本身是无状态的,无法辨别每次的请求是否由同一个用户发起,因此可以通过在每次请求头中放入可识别状态的信息。由此引生出cookie与token等两种身份验证方式,可简单理解为 身份识别器。
Cookie发起请求时存在于Request-Header中。
格式:
cookie为一组 name=value形式的数据并以';'分割的列表 例:PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1
,
What Set-Cookie#
Set-Cookie HTTP响应头用于将Cookie从服务器发送到用户代理,以便用户代理稍后可以将其发送回服务器。要发送多个Cookie,应在同一响应中发送多个Set Cookie头
Attributes属性
属性项 | 描述 | 是否必须 |
---|---|---|
cookie-name=cookie-value | name自定但要唯一,value依据业务存值 | 是 |
Expires=date | 1.cookie的最长生存期,2.不设置则是会话cookie 3.截止日期与设置cookie的客户端相关,过期删除 | 否 |
Max-Age=number | 类似Expires但优先级比Expires高 | 否 |
Domain=domain-value | 1.定义接收cookie的主机 2.[.example.com]写法包含子级域名但可能被忽略 | 否 |
Path=path-value | 1.cookie生效路径 URL中必须存在的路径 | 否 |
Secure | 只有在用https进行请求时才将cookie发送到服务器 | 否 |
HttpOnly | 禁止JavaScript访问cookie | 否 |
SameSite=samesite-value | 控制cookie是否随跨源请求一起发送 可选[Strict(禁止跨域),Lax(在用户从外部网站导航到原网站时发送cookie,默认 ),None(允许跨域,同时设置Secure)] |
否 |
请求携带Cookie#
with open('cookies/'+stunumber+'_cookie.txt', 'r', encoding='utf8') as f:
listCookies = json.loads(f.read())
# 往browser里添加cookies
for cookie in listCookies:
cookie_dict = {
'domain': '.mnnu.edu.cn',
'name': cookie.get('name'),
'value': cookie.get('value'),
"expires": '',
'path': '/',
'httpOnly': False,
'HostOnly': False,
'Secure': False
}
browser.add_cookie(cookie_dict)
browser.refresh()
Linux下selenium配置#
前提:由于linux浏览器无法界面化,因此在初始化browser时需要额外指定配置
chrome_options = webdriver.ChromeOptions()
# 无头模式
chrome_options.add_argument('--headless')
# 禁用GPU加速
chrome_options.add_argument('--disable-gpu')
browser = webdriver.Chrome(chrome_options=chrome_options, executable_path='/root/chromedriver')
#全局隐式等待时间
browser.implicitly_wait(10)
脚本监听cookie过期#
遍历指定文件夹下cookie文件的最后一次修改时间与现在时间的间隔,当间隔超过6天时邮件提醒更新
SIX_DAY_SECONDS=6*24*60*60
SEVEN_DAY_SECONDS=7*24*60*60
def listFile(rootpath):
todayStamp = time.time()
todayTime = dateFormat(todayStamp)
logging.info("==========="+todayTime+"====START====")
fileList = os.listdir(rootpath)
email_msg =""
for i in range(0,len(fileList)):
fullpath = os.path.join(rootpath,fileList[i])
# 判断是否是文件
if os.path.isfile(fullpath):
# 获取最后修改日期
lastTimeStamp = os.path.getmtime(fullpath)
# 相差秒数
diffSeconds = daysDiff(todayStamp,lastTimeStamp)
if SEVEN_DAY_SECONDS-diffSeconds <=0:
logging.info(stunumber+ "您的cookie已经过期")
if diffSeconds<=SEVEN_DAY_SECONDS :
if diffSeconds>=SIX_DAY_SECONDS :
logging.info(stunumber+"您的cookie即将过期 有效时间还剩:"+str((SEVEN_DAY_SECONDS-diffSeconds)//3600)+"小时")
# 发送邮件提醒
email_msg+=stunumber+"您的cookie即将过期 有效时间还剩:"+str((SEVEN_DAY_SECONDS-diffSeconds)//3600)+"小时\n"
else:
logging.info(stunumber+"您的cookie有效时间还剩:"+str((SEVEN_DAY_SECONDS-diffSeconds)//3600)+"小时")
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现