python+selenuim实现web自动打卡

python+selenuim实现web自动打卡

摘要:

​ 大概就是在XX背景下,需要每天登录网站填报体温,所在地信息等,分析登录时发送请求逻辑,通过python-selenium实现自动打卡。

思路

​ 通过selenium操作浏览器,完成登录->填充表单信息->定时重复打卡。

  1. 登录: 使用机器完成登录有两种方法,一种通过定位验证码位置通过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
  2. 填充表单信息 通过selenium操作浏览器中元素,完成一系列逻辑操作,(需要下载浏览器所对应的驱动driver,chrome+chromedriver)
  3. 定时重复打卡 Crontab+shell 即可实现每日定时启动

关于selenium-python,请到网站查看

具体实现

image-20220116144155199

​ 定位验证码位置,由机器识图,首先启动操作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"}
]

cookie文档

​ 基于HTTP协议本身是无状态的,无法辨别每次的请求是否由同一个用户发起,因此可以通过在每次请求头中放入可识别状态的信息。由此引生出cookie与token等两种身份验证方式,可简单理解为 身份识别器。

​ Cookie发起请求时存在于Request-Header中。

格式:

​ cookie为一组 name=value形式的数据并以';'分割的列表 例:PHPSESSID=298zf09hf012fh2; csrftoken=u32t4o3tb3gg43; _gat=1

​ 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)+"小时")
posted @ 2022-01-16 21:59  成见  阅读(805)  评论(0)    收藏  举报
zz