Featured image of post 全自动托管青年大学习

全自动托管青年大学习

利用Python自动化完成每期的青年大学习,将python脚本托管到GitHub action并设置定时任务之后即可完全解放双手。

准备工作

要想自动化地完成这一操作,首先我们得分析当我们在微信上点开青年大学习的时候,后台到底干了什么,这样我们才能知道如何去自动化地完成这一系列动作。我们怎么才能知道呢,抓包看一下嘛,遇事不决,先抓包。

抓包软件,实际上就是接管你的系统代理,所有数据包都经过这个软件之后,再到原本要去的地方,大概就这个意思。

image-20211128150137836

所以我们先要准备抓包工具

安装抓包软件

我用的是Charles,挺好用的软件,官网下载就好,安装一路点过就好了。

安装证书

软件安装完成后还要安装CA证书,点install一路下一步安装就好

image-20211128150509163

安装手机证书

由于青年大学习必须得用微信完成,大学习的网址用电脑浏览器打开会提示必须用微信打开,单纯的改浏览器UA根本没用,因为青年大学习还要用微信登陆,所以我们抓包的时候用手机操作,然后用Charles查看发送的数据包即可。

但是现在Charles仅仅接管了电脑的系统代理,不拍,刚刚的选项还有一个,给手机安装证书,点击之后手机与电脑连接统一局域网,然后手机代理设置为手动,代理主机设置为电脑即可。

image-20211128151111456

按照要求进行操作,代理主机地址就是192.168.5.6,端口8888,每个人都不一样,地址其实就是电脑的内网ip。

image-20211128151154194

然后按照要求手机访问chls.pro/ssl去下载证书文件,这时候电脑上会有提示,是否允许连接,选择allow即可,下载好证书之后在手机设置,隐私安全之类的里面安装证书即可。

现在Charles就可以对手机进行抓包了。

开始抓包

电脑端保持监听,手机正常操作打开青年大学习,一系列操作之后可以在电脑上看到,手机访问了这个网址:

image-20211128151816859

点击开始学习后,在api下的student多了commit,这就是学习是向后台提交的数据。

image-20211128152015847

编写代码测试

直接POST

可以看到,访问类型是POST,直接用python进行测试。

image-20211128152140203

1
2
3
4
5
import requests
url = "http://dxx.scyol.com/api/student/commit"
r = requests.post(url)
r.encoding = 'utf-8'
print(r.text)

运行结果如下,说明还是需要设置UA、token之类的东西。

image-20211128152441287

观察之前正常操作时发送的commit:

image-20211128152740705

添加UA和token

就用这个UA和token,重新编写代码测试:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import requests
url = "http://dxx.scyol.com/api/student/commit"
agent = {
        "User-Agent":
        "Mozilla/5.0 (Linux; Android 10;)XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",  #直接复制手机访问的UA
        'Content-Type': 'application/json',
        "token": "XXXXXXXXXXXXXXX",  #直接复制抓包获取到的token
}
r = requests.post(url, headers=agent)
r.encoding = 'utf-8'
print(r.text)

再次运行,还是有问题,说明还是缺少东西。

image-20211128153533837

想到青年大学习开始前还要填写一些信息,但是这些操作并没有涉及到填写信息,再次分析抓包数据,在/api/stages/currentInfo中发现个人信息数据。

image-20211128153811708

添加json数据

直接构造data,按照格式填入自己的数据:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import requests
url = "http://dxx.scyol.com/api/student/commit"
agent = {
        "User-Agent":
        "Mozilla/5.0 (Linux; Android 10;)XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",  #直接复制手机访问的UA
        'Content-Type': 'application/json',
        "token": "XXXXXXXXXXXXXXX",  #直接复制抓包获取到的token
}
data = {
        'name': 'xxx',
        'tel': 'xxxxxxxxxxxxx',
        'org': 'xxxxxxxxx',
        'lastOrg': 'xxxxxxxxxx',
        'orgName': 'xxxxxxxxxxxxx',
        'allOrgName': 'xxxxxxxxxxxxxxxx'
}
r = requests.post(url, headers=agent, data=json.dumps(data))
r.encoding = 'utf-8'
print(r.text)

再次运行测试,发现返回结果正常,搞定!

image-20211128154441692

利用github action自动化运行

现在虽说可以直接运行完成学习,但是手动运行跟手机上直接操作好像没有什么区别,所以 再次用万能的action:

编写workflow:

将编写好的代码保存后上传到github仓库,由于代码中有许多隐私信息,所以创建私有仓库,也可以在公有仓库中用env,但是麻烦,不用!

在仓库根目录下创建.github文件夹,在里面创建workflow文件夹,再在里面放入.yml文件就可以啦

 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
name: action

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  schedule:
  - cron:  '00 05 * * *' # 每天早上五点自动运行,这里是标准UTC时间,换算之后是北京时间13点运行。
  workflow_dispatch:  # Allow manual triggering
    Scheduled:
      inputs:
        description: 'Scheduled Time'  # TO-DO
        required: false

jobs:
  qndxx:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Set up Python 3.9
      uses: actions/setup-python@v2
      with:
        python-version: 3.9
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install requests        
    - name: 'action'
      run: |
                python main.py

这个文件会在每天中午一点自动运行,定时设置可以自己修改,一般一周运行两次就好了。

添加邮件提醒

每次运行之后结果对不对呢,这点我们没法第一时间知道,我不允许这样的情况出现,所以再次修改Python代码,添加发送邮件功能:

一般来说自己给自己发,寄件邮箱和收件邮箱用同一个就好了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
def Send_Email(str):
    msg = MIMEText(f'运行返回结果:{str}')  # 构造邮件,内容为青年大学习
    msg["Subject"] = "青年大学习自动化反馈"  # 设置邮件主题
    msg["From"] = 'action bot'  # 寄件者
    msg["To"] = 'xxx'  # 收件者
    from_addr = 'xxxxxxxxxx@qq.com'
    password = 'xxxxxxxxxxxxxxxx'  # 这里用申请的授权码,不是qq邮箱密码。
    smtp_server = 'smtp.qq.com'  # smtp服务器地址
    to_addr = 'xxx@xxx.xxx'  # 收件人地址
    try:
        server = smtplib.SMTP_SSL(smtp_server, 465, timeout=2)
        server.login(from_addr, password)  # 登录邮箱
        server.sendmail(from_addr, to_addr, msg.as_string())
        server.quit()
        print('success')
    except Exception as e:
        if e == None:
            print('Faild:%s' % e)
            pass

完整代码

 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
import requests
import json
import smtplib
from email.mime.text import MIMEText


def Send_Email(str):
    msg = MIMEText(f'运行返回结果:{str}')  # 构造邮件,内容为青年大学习
    msg["Subject"] = "青年大学习自动化反馈"  # 设置邮件主题
    msg["From"] = 'action bot'  # 寄件者
    msg["To"] = 'xxx'  # 收件者
    from_addr = 'xxxxxxxxxx@qq.com'
    password = 'xxxxxxxxxxxxxxxx'  # 这里用申请的授权码,不是qq邮箱密码。
    smtp_server = 'smtp.qq.com'  # smtp服务器地址
    to_addr = 'xxx@xxx.xxx'  # 收件人地址
    try:
        server = smtplib.SMTP_SSL(smtp_server, 465, timeout=2)
        server.login(from_addr, password)  # 登录邮箱
        server.sendmail(from_addr, to_addr, msg.as_string())
        server.quit()
        print('success')
    except Exception as e:
        if e == None:
            print('Faild:%s' % e)
            pass
        
        
def main():
    url = "http://dxx.scyol.com/api/student/commit"
    agent = {
            "User-Agent":
            "Mozilla/5.0 (Linux; Android 10;)XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",  #直接复制手机访问的UA
            'Content-Type': 'application/json',
            "token": "XXXXXXXXXXXXXXX",  #直接复制抓包获取到的token
    }
    data = {
            'name': 'xxx',
            'tel': 'xxxxxxxxxxxxx',
            'org': 'xxxxxxxxx',
            'lastOrg': 'xxxxxxxxxx',
            'orgName': 'xxxxxxxxxxxxx',
            'allOrgName': 'xxxxxxxxxxxxxxxx'
    }
    r = requests.post(url, headers=agent, data=json.dumps(data))
    r.encoding = 'utf-8'
    Send_Email(r.text)
    
    
if __name__=='__main__':
    main()

运行效果

image-20211128160143876

Licensed under CC BY-NC-SA 4.0
Built with Hugo
主题 StackJimmy 设计