forked from tianzhengs/Beijing_Daxuexi_Simple
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request tianzhengs#8 from startkkkkkk/dev
Multi-Account Support Fix
- Loading branch information
Showing
3 changed files
with
137 additions
and
106 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,99 +1,46 @@ | ||
import json | ||
import os | ||
import re | ||
import time | ||
import traceback | ||
|
||
import requests | ||
from study import study | ||
|
||
from utility import encrypt, cap_recognize | ||
|
||
username = os.environ["USERNAME"] | ||
password = os.environ["PASSWORD"] | ||
def getAccounts(): | ||
result = [] | ||
|
||
if not (username and password): | ||
raise Exception("请设置Secret: USERNAME和PASSWORD") | ||
usernameRaw = os.getenv("USERNAME", "") | ||
if len(usernameRaw.split('\n'))==1: | ||
# Single User | ||
passwd = os.environ["PASSWORD"] | ||
if usernameRaw and passwd: | ||
result.append((usernameRaw, passwd, os.getenv("ORGID", "172442"))) | ||
else: | ||
# Multiple Users | ||
account_lines = usernameRaw.split('\n') | ||
for lnum, line in enumerate(account_lines): | ||
if len(line.split(' ')) != 3: | ||
raise Exception(f"第{lnum}行账号格式错误") | ||
result.append(line.split(' ')) | ||
|
||
if not result: | ||
raise Exception("没有被配置的账号!请设置Secret: USERNAME和PASSWORD") | ||
return result | ||
|
||
try: | ||
org_id = str(int(os.environ["ORGID"])) # check type | ||
except: | ||
org_id = '172442' | ||
|
||
url = '' | ||
ua = os.getenv('UA', | ||
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.163 Safari/537.36 Edg/80.0.361.111') | ||
try_time = 0 | ||
while try_time < 4: | ||
try: | ||
bjySession = requests.session() | ||
bjySession.timeout = 5 # set session timeout | ||
bjySession.headers.update({"User-Agent": ua, }) | ||
touch = bjySession.get(url="https://m.bjyouth.net/site/login") | ||
cap_url = "https://m.bjyouth.net" + re.findall( | ||
r'src="/site/captcha.+" alt=', touch.text)[0][5:-6] | ||
cap_text = cap_recognize(bjySession.get(url=cap_url).content) | ||
print(f'验证码识别: {cap_text}') | ||
_csrf_mobile = bjySession.cookies.get_dict()['_csrf_mobile'] | ||
login_password = encrypt(password) | ||
login_username = encrypt(username) | ||
login_r = bjySession.post('https://m.bjyouth.net/site/login', | ||
data={ | ||
'_csrf_mobile': _csrf_mobile, | ||
'Login[username]': login_username, | ||
'Login[password]': login_password, | ||
'Login[verifyCode]': cap_text | ||
}) | ||
print(f'Login:[{login_r.status_code}]{login_r.text}') | ||
if login_r.text == '8': | ||
print('Login:识别的验证码错误') | ||
continue | ||
if 'fail' in login_r.text: | ||
try_time += 9 | ||
raise Exception('Login:账号密码错误') | ||
r = json.loads(bjySession.get("https://m.bjyouth.net/dxx/index").text) | ||
if 'newCourse' not in r: | ||
print(r) | ||
url = r['newCourse']['url'] | ||
title = r['newCourse']['title'] | ||
course_id = r['newCourse']['id'] | ||
break | ||
except: | ||
time.sleep(3) | ||
try_time += 1 | ||
print(traceback.format_exc()) | ||
|
||
if not url: | ||
print('Fail in login, terminating...') | ||
exit(1) | ||
|
||
r2 = bjySession.get('https://m.bjyouth.net/dxx/my-integral?type=2&page=1&limit=15') | ||
have_learned = json.loads(r2.text) | ||
if f"学习课程:《{title}》" in list(map(lambda x: x['text'], have_learned['data'])): | ||
print(f'{title} 在运行前已完成') | ||
exit(0) | ||
|
||
pattern = re.compile(r'https://h5.cyol.com/special/daxuexi/(\w+)/m.html\?t=1&z=201') | ||
result = pattern.search(url) | ||
if not result: | ||
print(f'Url pattern not matched: {url}') | ||
exit(1) | ||
|
||
end_img_url = f'https://h5.cyol.com/special/daxuexi/{result.group(1)}/images/end.jpg' | ||
study_url = f"https://m.bjyouth.net/dxx/check?id={course_id}&org_id={org_id}" | ||
|
||
r = bjySession.get(study_url) | ||
if r.text: | ||
print( | ||
f'Unexpected response: {r.text}' | ||
) | ||
exit(1) | ||
|
||
r = bjySession.get('https://m.bjyouth.net/dxx/my-integral?type=2&page=1&limit=15') | ||
have_learned = json.loads(r.text) | ||
if f"学习课程:《{title}》" in list(map(lambda x: x['text'], have_learned['data'])): | ||
print(f'{title} 成功完成学习') | ||
exit(0) | ||
else: | ||
print(f'完成{title}, 但未在检查中确认 {f"学习课程:《{title}》"}' not in { | ||
list(map(lambda x: x['text'], have_learned['data']))}) | ||
exit(1) | ||
accounts = getAccounts() | ||
print(f'账号数量:{len(accounts)}') | ||
successful = 0 | ||
failed = 0 | ||
count = 0 | ||
for username, password, org_id in accounts: | ||
count+= 1 | ||
print(f'--User {count}--') | ||
if study(username, password, org_id, ua): | ||
successful += 1 | ||
else: | ||
failed += 1 | ||
|
||
print(f'成功:{successful},失败:{failed}') | ||
if failed != 0: | ||
raise Exception(f'有{failed}个失败!') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,34 @@ | ||
# 北京青年大学习 | ||
基于Github Action运行,简洁版本 | ||
|
||
基于GitHub Action运行,简洁版本 | ||
|
||
在运行时获取最新一集,如未学习进行学习,已学习则结束 | ||
|
||
建议配置运行频率一周2次(默认为3天一次),没有成功会出错,默认配置下Github会向邮箱推送,所以没有推送功能 | ||
建议配置运行频率一周2次(默认为3天一次),没有成功会出错,默认配置下GitHub会向邮箱推送,所以没有推送功能 | ||
|
||
更新:优化了验证码识别和验证码失败的反馈 | ||
更新:多账号支持 | ||
|
||
|
||
# How to use | ||
1. Fork (+ Star) | ||
2. 填写以下SECRET (名称均为大写): | ||
|
||
(账号密码为登录青春北京的信息,可以在[这里](https://m.bjyouth.net/site/login)测试登录信息) | ||
|
||
| Name | Description | | ||
| -------- | -------- | | ||
| USERNAME | 账号(必须) | | ||
| PASSWORD | 密码(必须) | | ||
| ORGID | 组织ID(可选,默认为172442,北京海淀区团委) | | ||
1. Fork (+ Star) | ||
2. 填写以下SECRET (名称均为大写) | ||
|
||
[如何添加SECRET](https://docs.github.com/cn/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository) | ||
(账号密码为登录青春北京的信息,可以在[这里](https://m.bjyouth.net/site/login)测试登录信息,[如何添加SECRET](https://docs.github.com/cn/actions/security-guides/encrypted-secrets#creating-encrypted-secrets-for-a-repository)) | ||
|
||
3. 在Actions界面**手动启用(默认被禁用)** Workflows,**DaXueXi** 自动跟随本分支更新(以希望在有变化时不用再手动fetch upstream),如有安全顾虑**或需要修改**等可选择没有自动更新的 **DaXueXi (No update)** | ||
4. (可以手动运行一次试验),可以在Run python中看到打印的结果信息 | ||
方法1:单用户 | ||
|
||
# 其他 | ||
| Name | Description | | ||
| -------- | :----------------------------------------: | | ||
| USERNAME | 账号(必须) | | ||
| PASSWORD | 密码(必须) | | ||
| ORGID | 组织ID(可选,默认为172442,北京海淀区团委) | | ||
|
||
方法2:支持多用户 | ||
|
||
感谢[ouyen/qndxx-beijing](https://github.com/ouyen/qndxx-beijing) | ||
| Name | Description | | ||
| ------- | ---------------------------------------------------------- | | ||
| ACCOUNT | 账号(必须): 每一行为 ***账号 密码 组织ID*** 中间由空格隔开 | | ||
|
||
3. 在Actions界面**手动启用(默认被禁用)** Workflows,**DaXueXi** 自动跟随本分支更新(以希望在有变化时不用再手动fetch upstream),如有安全顾虑**或需要修改**等可选择没有自动更新的 **DaXueXi (No update)** | ||
4. (可以手动运行一次试验),可以在Run python中看到打印的结果信息 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import json | ||
import re | ||
import time | ||
import traceback | ||
|
||
import requests | ||
|
||
from utility import encrypt, cap_recognize | ||
|
||
|
||
def study(username, password, org_id, ua): | ||
# return 1:success;0:fail | ||
url = '' | ||
try_time = 0 | ||
while try_time < 4: | ||
try: | ||
bjySession = requests.session() | ||
bjySession.timeout = 5 # set session timeout | ||
bjySession.headers.update({"User-Agent": ua, }) | ||
touch = bjySession.get(url="https://m.bjyouth.net/site/login") | ||
cap_url = "https://m.bjyouth.net" + re.findall( | ||
r'src="(/site/captcha.+)" alt=', touch.text)[0] | ||
cap_text = cap_recognize(bjySession.get(url=cap_url).content) | ||
# print(f'验证码识别: {cap_text}') | ||
login_r = bjySession.post('https://m.bjyouth.net/site/login', | ||
data={ | ||
'_csrf_mobile': bjySession.cookies.get_dict()['_csrf_mobile'], | ||
'Login[password]': encrypt(password), | ||
'Login[username]': encrypt(username), | ||
'Login[verifyCode]': cap_text | ||
}) | ||
print(f'Login:[{login_r.status_code}]{login_r.text}') | ||
if login_r.text == '8': | ||
print('Login:识别的验证码错误') | ||
continue | ||
if 'fail' in login_r.text: | ||
try_time += 9 | ||
raise Exception('Login:账号密码错误') | ||
r = json.loads(bjySession.get("https://m.bjyouth.net/dxx/index").text) | ||
if 'newCourse' not in r: | ||
print(r) | ||
url = r['newCourse']['url'] | ||
title = r['newCourse']['title'] | ||
course_id = r['newCourse']['id'] | ||
break | ||
except: | ||
time.sleep(3) | ||
try_time += 1 | ||
print(traceback.format_exc()) | ||
|
||
if not url: | ||
print('登陆失败,退出') | ||
return 0 | ||
|
||
r2 = bjySession.get('https://m.bjyouth.net/dxx/my-integral?type=2&page=1&limit=15') | ||
have_learned = json.loads(r2.text) | ||
if f"学习课程:《{title}》" in list(map(lambda x: x['text'], have_learned['data'])): | ||
print(f'{title} 在运行前已完成,退出') | ||
return 1 | ||
|
||
pattern = re.compile(r'https://h5.cyol.com/special/daxuexi/(\w+)/m.html\?t=1&z=201') | ||
result = pattern.search(url) | ||
if not result: | ||
print(f'Url pattern not matched: {url}') | ||
return 0 | ||
|
||
end_img_url = f'https://h5.cyol.com/special/daxuexi/{result.group(1)}/images/end.jpg' | ||
study_url = f"https://m.bjyouth.net/dxx/check?id={course_id}&org_id={org_id}" | ||
|
||
r = bjySession.get(study_url) | ||
if r.text: | ||
print(f'Unexpected response: {r.text}') | ||
return 0 | ||
|
||
r = bjySession.get('https://m.bjyouth.net/dxx/my-integral?type=2&page=1&limit=15') | ||
have_learned = json.loads(r.text) | ||
if f"学习课程:《{title}》" in list(map(lambda x: x['text'], have_learned['data'])): | ||
print(f'{title} 成功完成学习') | ||
return 1 | ||
else: | ||
print(f'完成{title}, 但未在检查中确认') | ||
return 0 |