兰大自动打卡

参考博主伍尔夫的猫的博文如何通过Python自动完成移动校园“每日健康”打卡和博主CookiePie的文章Python—利用Requests实现每日微信自动打卡,拿来主义可耻,所以还是自己写一篇博客记录一下解决问题的过程,主要是为了学习,顺便激励自己好好写论文,坚持写代码,早日去实习。

一、前期准备

1、抓包

不细说了,安装Fiddler或者在浏览器端的话直接用谷歌开发者工具。(我是在浏览器端完成的,小程序端会复杂些)

2、安装selenium

我用的也是Pycharm,参考这个博主的Python配置Selenium+Chrome环境和Selenium+PhantomJS环境

3、配置Phantomjs

如果参考上面安装过程中测试代码没有问题就可以跳过了

1
driver = webdriver.Chrome()

如果会报错,那么奖励你,继续看Python配置Selenium+Chrome环境和Selenium+PhantomJS环境,其中,第5点说明了无界面的浏览器包PhantomJS的应用。如果还会报错,可以将selenium的版本修改为了selenium2.48.0版本,亲测可以。

代码

代码参考了原博主的,然后根据学校的网站进行抓包分析,思路和原博主基本上是一致的。

  1. 抓包分析
  2. 模拟登录
  3. 伪装Header发送Cookie,data

但是!!!,正是由于抓取的post包里面有Authorization

Snipaste_2021-11-19_21-26-02

并且它还是刷新的,如果Header中没有授权码,则服务器默认收到的是非法数据。所以耗费了一天时间才搞定。所以重点记录解决这个问题的思路,因为我看的好几篇博客并没有遇见这个问题,只需要Cookie和User-Agent就可以了。

直接说Authorization,先读读这个权限认证基础:区分Authentication,Authorization以及Cookie、Session、Token ,说实话我这个菜鸡开始也不是很懂,不过看见这个,那没事了。

Snipaste_2021-11-19_21-11-58

也就是说我们需要去找到服务端返回给客户端的token,也就是刷新的Authorization。所以

  1. 找到它

  2. 获取并使用它

  3. 更新它

    那么我们已经在包里面找到它了,但是实际上还是没有找到它…因为我们需要将它的值获取到且随着它更新,而不是复制出来。

那么到这里,我当时有两个思路:

  1. 我有一个大胆(笨比)的想法,就是webdriver.Chrome()既然是模拟浏览器操作,那么我们

    • 模拟登录后,得到新的网页
    • 然后点击“健康打卡”又可以进入打卡界面
    • 终于只需要点击上报就ok啦! 这不是有手就行!? 然后我写了如下代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    driver = webdriver.Chrome()
    driver.maximize_window()
    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="loginForm"]/div[4]/button').click()
    sleep(2)
    cookie_ = driver.get_cookies()[0]
    print(driver.current_url)
    sleep(1)
    driver.switch_to.window(driver.window_handles[0])
    el = driver.find_element_by_xpath('//*[@id="my-apps"]/li[3]')
    ActionChains(driver).move_to_element(el).perform() #鼠标移动到该元素停留
    sleep(2)
    buttonElement = driver.find_element_by_xpath('//*[@id="my-apps"]/li[3]/a/div[2]/p[2]/span[1]')
    ActionClick = ActionChains(driver).click(buttonElement)
    ActionClick.perform()
    frame1 = driver.find_element_by_id("iframe")
    # 切换到iframe1这个内嵌网页
    driver.switch_to.frame(frame1)
    ActionChains(driver).move_by_offset(843, 100).click().perform() # 鼠标左键点击, 200为x坐标, 100为y坐标
    sleep(3)
    driver.quit()
    return cookie_['name'] + '=' + cookie_['value']

    首先简简单单的就到了第二步,准备点击健康打卡,结果tmd它不是button,没办法click(),而且只有鼠标在这个模块上放一秒,它才会出现进入这个元素。所以我机智的(暴力的)通过强大的driver模拟了这一操作过程。终于,到了最后一步了,只需要点击新出现弹窗里面的“进入”就可以了,结果tmd(真的忍不住)这个弹窗就很神奇,它的元素是定位不到的!(试了很多解决方法不行)无奈之下,想到了我的老本行——暴力,把鼠标移动到这个“进入”的坐标位置点击左键即可。然后用snipaste截图测位置测了半天没找到,只能放弃。

  2. 暴力无奈之下,只能另寻他路。结果突然发现这个Authorization就是token,并且它还保存在sessionStorage里面,真的得来全不费功夫。真的需要认真读文档和博客,而不是自己瞎弄。后面就是打开切换到这个内嵌iframe上,然后获取到token值,这样就解决问题了。代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    import requests
    import json
    from selenium import webdriver
    from time import sleep
    from selenium.webdriver.common.action_chains import ActionChains

    def get_cookie(url_, user_):
    list = []
    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="loginForm"]/div[4]/button').click()
    sleep(1)
    cookie_ = driver.get_cookies()[0]
    sleep(1)
    driver.switch_to.window(driver.window_handles[0])
    el = driver.find_element_by_xpath('//*[@id="my-apps"]/li[3]')
    ActionChains(driver).move_to_element(el).perform()
    sleep(1)
    buttonElement = driver.find_element_by_xpath('//*[@id="my-apps"]/li[3]/a/div[2]/p[2]/span[1]')
    ActionClick = ActionChains(driver).click(buttonElement)
    ActionClick.perform()
    frame1 = driver.find_element_by_id("iframe")
    # 切换到iframe1这个内嵌网页
    driver.switch_to.frame(frame1)
    sleep(1)
    token = driver.execute_script('return sessionStorage.getItem("token");')
    driver.quit()
    list.append(cookie_['name'] + '=' + cookie_['value'])
    list.append(token)

    return list

    user = {'name': '账号', 'password': '密码'}
    list = get_cookie(
    'http://my.lzu.edu.cn:8080/login?service=http://my.lzu.edu.cn', user) ##网页打卡入口
    headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.45 Safari/537.36',
    'Authorization': list[1],

    'Cookie': list[0]
    }

    data = {
    'bh': 'xxxxxxxxxx',
    'xykh': 'xxxxxxxx',
    'twfw': 0,
    'jkm': 0,
    'sfzx': 1,
    'sfgl': 0,
    'szsf': '',
    'szds': '',
    'szxq': '',
    'sfcg': 0,
    'cgdd': '',
    'gldd': '',
    'jzyy': '',
    'bllb': 0,
    'sfjctr': 0,
    'jcrysm': '',
    'xgjcjlsj': '',
    'xgjcjldd': '',
    'xgjcjlsm': '',
    'zcwd': 0.0,
    'zwwd': 0.0,
    'wswd': 0.0,
    'sbr': 'xxx',
    'sjd': '',
    'initLng': '',
    'initLat': '',
    'dwfs': ''
    } ##= 这个就是抓取的Post包的data,更新自己的数据信息


    url = 'https://appservice.lzu.edu.cn/dailyReportAll/api/grtbMrsb/submit' ##提交信息时候的php
    key = 'Server酱的key'
    try:
    s = requests.session()
    response = s.post(url=url, headers=headers, data=data)
    html = response.text
    except:
    url = 'https://sc.ftqq.com/%s.send?text=登录页访问超时,打卡失败' % key
    requests.get(url)
    if json.loads(response.text)['message'] == '成功':
    #url = 'https://sc.ftqq.com/%s.send?text=自动打卡成功' % key
    #requests.get(url)
    else:
    url = 'https://sc.ftqq.com/%s.send?text=自动打卡失败' % key
    requests.get(url)

    最后就是用Windows任务计划程定时调用执行Python脚本

    还用了Server酱来提示打卡成功和打卡失败,over!