众所周知,因为疫情的原因,很多高校和公司都要求员工每日在微信上进行打卡,来汇报自己的当前身体状态和所处地区。但绝大多数情况下,每天打卡的信息其实是不会变的,我们要做的就是进入公众号——自动登录点进打卡页面——完成打卡,这样重复的操作。
这样的操作在手机上需要花费的时间应该不足一分钟,但依旧每天都会有懒得或者忘了进行操作的人。所以就想到能不能用python写一个脚本,在PC端进行自动打卡呢?
(本操作仅提供思路参考,大家还是要重视防疫打卡操作)
以下所有操作均以某高校页面为例
目录
3.代码实现(账号密码+Selenium+Requests版本)
1.代码前准备
由于微信的普及,所以基本各高校和公司每日打卡都是在微信端进行,所以我们需要通过微信找到我们的登录页。
![](https://i-blog.csdnimg.cn/blog_migrate/deb4b54198a1af0bb95cda492a4e30c1.png)
![](https://i-blog.csdnimg.cn/blog_migrate/29e4a5145fb8eb1b85900c73b2221187.png)
我们最终希望用Requests模拟发包登录,而平时都是直接用微信进行自动登录。显然在只用脚本的情况下没办法实现微信自动登录跳转,所以我们需要先找到能输入账号密码的页面。(此时没有用Cookie是因为实验之后发现,Cookie有效期不到2小时,没办法支撑每日用同一个Cookie登录打卡)
此时,我们通过PC微信找到该链接:http://****app.i****.info/NYDXY/#/,但是如果直接用浏览器打开该链接,会跳转”请用微信客户端打开链接“的页面。
![](https://i-blog.csdnimg.cn/blog_migrate/af68d97f5344c4d966eb004bfc4557d3.png)
因此,需要想办法绕过该限制,思路有两个:1.通过Fiddler等抓包软件,找找有没有其他登录页面。2.模拟微信浏览器的请求头和Cookie进入。但是正如前文所说,经过尝试思路2,确实能够完成全流程,但该页面Cookie有效期很短,没办法每日均进行自动打卡,因此我们选择尝试思路1,还是通过账号密码登录。
沿着思路1,我们打开Fiddler,启动抓包。然后回到PC微信,和刚才同样的操作进入打卡页面自动登录,再回到Fiddler,发现刚才进入打卡页面的所有操作已经被记录在软件里了。接下来就是通过url和请求头等信息,来判断是否存在其他的登录页面。
![](https://i-blog.csdnimg.cn/blog_migrate/7e19de989d8299dc59e87c228a326a75.jpeg)
经过分析和尝试,前两个链接都会提示400或其他错误,但尝试到第三个链接时,会跳转到学校的统一登陆页面,同时还在下方发现微信快捷登录图表。通过该页面输入账号密码后,浏览器自动跳转到了我们所需的打卡页面了。此时,我们实现了PC端模拟登录微信打卡页面。
![](https://i-blog.csdnimg.cn/blog_migrate/e012d881f3ef02ea34a21868278f4ef6.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/a7f875ff592965a72c52adc96f7e43ec.png)
第二步,我们需要看我们打卡到底在浏览器端是如何完成的。在手动进行打卡操作之后,经过浏览器的F12,看到有四个php提供了post操作,而通常我们的表单数据都是由post方法完成的。排除掉之前就存在的第一二个php,所以我们强烈怀疑就是通过这剩余两个php完成的打卡操作。
![](https://i-blog.csdnimg.cn/blog_migrate/1b38840036bf6456d1402125b29900b8.png)
具体来看发现,最后一个jump.php实际上返回的是个人基本信息,以供自动填充用的,提交的表单也与打卡无关。
![](https://i-blog.csdnimg.cn/blog_migrate/8c9149cab76736917c2b20e68ad6dd11.png)
但到了倒数第二个jump.php,通过其提交的Form数据,我们发现就是通过这个php我们完成了打卡操作。因此得知,我们的最终目标,就是通过该php来完成我们的自动打卡。至此,我们的代码前分析全部完成,接下来进入代码环节。
![](https://i-blog.csdnimg.cn/blog_migrate/614ff25c2201479fdccbdf94ac51739d.png)
2.代码实现(Cookie+纯requests版本)
( 此版本使用requests包进行python代码实现)
因为我们已经通过浏览器进行过登录,获得了Cookie,所以我们先尝试通过Cookie进行直接打卡。先通过浏览器F12获得Cookie和其余请求头,然后根据需要放在Python文件中。(这里的请求头大家可以选择需要的来放,一般加上Cookie和User-Agent即可,如果失败还可以尝试将User-Agent换为Android或ios的模拟请求)
![](https://i-blog.csdnimg.cn/blog_migrate/68b3c794d15729d2709926115975ae32.jpeg)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36',
'Cookie': '浏览器上找到的Cookie'
}
然后再根据From Data的数据,按照字典格式一一放进Python文件中去。
![](https://i-blog.csdnimg.cn/blog_migrate/a79febbce1d0701634e4587145bc5d3b.png)
![](https://i-blog.csdnimg.cn/blog_migrate/c9ebdb611aff2873d26775f62a46d2c5.png)
最后再尝试post即可。发现最后返回值和浏览器返回值相同,打卡成功。
url = 'http://****app.i****.info/jinzhi/jump.php'
s = requests.session()
response = s.post(url=url, headers=headers, data=data)
response.encoding = 'utf-8'
print(response.text)
![](https://i-blog.csdnimg.cn/blog_migrate/64070f5e37ab46e1b45308698e486cde.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/49acb9b4fb54bd693cf7e8c94a921f0e.png)
3.代码实现(账号密码+Selenium+Requests版本)
前文已经实现在知道Cookie的前提下,可以直接通过固定php页面进行表单上传打卡。但是由于Cookie有效期极短,所以我们明显需要有一个每次打卡前自动获取Cookie的方法。
回到一开始的Login页面,同样我们通过F12抓包,看每次登录时提交的表单具体值有些什么。在用户名和密码,我们尝试性的输入123456之后点击提交,会发现在login文件下会POST一个表单,里面所包含的就是每次登录要传给服务器的信息了。
![](https://i-blog.csdnimg.cn/blog_migrate/c524191e5d7b31702104ce097e532120.png)
但是从表单我们看到,除了我们填写的账号密码,还有包括lt,execution等信息。经过查找,我们发现这些信息是在加载网页时就自动生成的,所以我们可以通过request.session()的方法进入页面后,再通过正则表达式将所需信息找出来,和账号密码一起形成表单。
![](https://i-blog.csdnimg.cn/blog_migrate/d52b56f0c07a1c466f16749bd034b9fa.png)
但是我们还可以看到,password明显是经过加密处理后的信息,所以我们不能直接明文提交密码,要想办法将密码进行处理。而这个加密后的密码,是我们点击提交后网页自动将我们的明文密码进行的加密,所以大概率就是一个js的处理,因此需要找到网页上加密的js文件。查找login页面和js之后,最终找到是encrypt.js这个文件完成了明文密码的加密。
![](https://i-blog.csdnimg.cn/blog_migrate/93edb04418eb85a18db13fa03e956658.png)
按逻辑来说,我们此时就可以查找传递该js所需参数,得到加密后的密码,连同其他信息一起post给login就可以完成我们的登录和cookie获取了。但是这个js真是又长又混淆,以现在的水平暂时不能找到其所需参数。所以换了个思路,通过Selenium来模拟登录,直接获取Cookie。
(这里如果可以看懂这个js加密的话,是完全可以不依靠Selenium获取Cookie的,大家有兴趣可以尝试一下)
Selenium就比较简单了,通过分析登录页面,找到需要Input的地方,获取Xpath,再通过Selenium填写,并获取Cookie就可以了。
![](https://i-blog.csdnimg.cn/blog_migrate/bc38b6428c3371deb5fc903f6e9a0129.png)
def get_cookie(url_, user_):
driver = webdriver.Chrome()
driver.get(url_)
driver.find_element_by_xpath('//*[@id="username"]').send_keys(user_['name'])
driver.find_element_by_xpath('//*[@id="password"]').send_keys(user_['password'])
driver.find_element_by_xpath('//*[@id="casLoginForm"]/p[4]/button').click()
sleep(3)
cookie_ = driver.get_cookies()[0]
driver.quit()
return cookie_['name']+'='+cookie_['value']
获取cookie后,和之前操作相同,提交表单即可,完整代码如下。
import requests
from selenium import webdriver
from time import sleep
def get_cookie(url_, user_):
driver = webdriver.Chrome()
driver.get(url_)
driver.find_element_by_xpath('//*[@id="username"]').send_keys(user_['name'])
driver.find_element_by_xpath('//*[@id="password"]').send_keys(user_['password'])
driver.find_element_by_xpath('//*[@id="casLoginForm"]/p[4]/button').click()
sleep(2)
cookie_ = driver.get_cookies()[0]
driver.quit()
return cookie_['name']+'='+cookie_['value']
user = {'name': '', 'password': ''}
cookie = get_cookie('https://authserver.*****.edu.cn/authserver/login?service=http://*****app.i*****.info/jinzhi/index.php', user)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.193 Safari/537.36',
'Cookie': cookie
}
data = {
'mymethod': 'POST',
'myurl': 'https://*****api.*****.edu.cn/api/v1/ncp/student/daka/update',
'id': '',
't1': '否',
't2': '',
't3': '否',
'stsfyc': '否',
'stsfycxq': '',
'dqszdpro': '{"code":""}',
'dqszdcity': '{"code":""}',
'dqszdreg': '{"code":""}',
'sfdgyq': '否',
'dgyqqt': '[]'
}
url = 'http://*****app.i*****.info/jinzhi/jump.php'
s = requests.session()
response = s.post(url=url, headers=headers, data=data)
html = response.text
print(html)
4.总结
其实在类似需求中,代码部分相对而言占比更少,重要的地方在于找到提交的表单数据和页面链接,和能否完成加密解密。本文由于js加密的限制,只能通过Selenium来获取Cookie进而实现表单提交。在之后的版本中,希望能够通过分析js文件,完成参数传递加密,最终只用Requests包完成打卡操作。
与本文类似的应用场景还有很多,都可以用相同的思路去解决,本文作为供大家选择的参考,如果各位读者有更好的思路欢迎多多交流。