diff --git a/README.md b/README.md index 5869ab8..44024bc 100644 --- a/README.md +++ b/README.md @@ -67,10 +67,10 @@ pip install -r requirements.txt - 打开[Server酱](https://benjiah.gitee.io/redirect/serversauce)。 - 申请一个`sendkey`,并记录下来。 -### 4.2.填写[`config/config.ini`](config/config_example.ini) +### 4.2.填写[`config/config.json`](config/config_example.json) -- 重命名`config_example.ini`文件为`config.ini`。 -- 参照[`config.ini`文件](config/config_example.ini)内说明填写其余内容。 +- 重命名`config_example.json`文件为`config.json`。 +- 参照[`config.json`文件](config/config_example.json)内说明填写其余内容。 ### 4.3.填写[`config/account.csv`](config/account_example.csv)(可选) @@ -125,15 +125,12 @@ chmod 777 scripts/run.sh │ ├─config │ account.csv <---多账户管理文件 -│ config.ini <---配置文件 +│ config.json <---配置文件 +│ email_tmpl.html <---Email模板文件 │ ├─log │ log.log <---日志文件 │ -├─res -│ email_tmpl.html <---Email模板文件 -│ error.json <---错误码及错误信息文件 -│ └─scripts run.bat <---Windows下运行文件 run.sh <---GNU/Linux下运行文件 diff --git a/common/account.py b/common/account.py index 7d23ec4..d7ccc03 100644 --- a/common/account.py +++ b/common/account.py @@ -2,6 +2,7 @@ import csv from common.logger import logger +from common.config import global_config as gc class Account: @@ -18,7 +19,7 @@ def __init__(self, csv_file="../config/account.csv"): @logger.catch def _read_csv(self): - self._csv_file = csv.reader(open(self._path, encoding='UTF-8-sig')) + self._csv_file = csv.reader(open(self._path, encoding='utf-8-sig')) for row in self._csv_file: if row == [] or "#" in row[0]: logger.debug(f"Del:{row}") @@ -60,4 +61,4 @@ def row(self): return len(self._raw) -global_account = Account("../config/account.csv") +global_account = Account(gc.config['config']['path']['account_file']) diff --git a/common/config.py b/common/config.py index c7f6ae1..12b2969 100644 --- a/common/config.py +++ b/common/config.py @@ -1,34 +1,28 @@ import os -import configparser +import json from common.logger import logger class Config: - def __init__(self, config_file=r"../config/config.ini"): + def __init__(self, config_file=r"../config/config.json"): os.chdir(os.path.dirname(__file__)) self._path = os.path.abspath(config_file) if not os.path.exists(self._path): logger.error(f"No such file:{self._path}") raise FileNotFoundError(f"No such file:{self._path}") - self._config = configparser.ConfigParser() - self._config.read(self._path, encoding='utf-8-sig') - self._configRaw = configparser.RawConfigParser() - self._configRaw.read(self._path, encoding='utf-8-sig') + self.config = {} + self._json_read() + + @logger.catch + def _json_read(self): + with open(self._path, 'r', encoding='utf-8') as f: + self.config = json.load(f) logger.debug(f"Loaded [{self._path}]") @logger.catch def refresh(self): - self._config.read(self._path, encoding='utf-8-sig') - self._configRaw.read(self._path, encoding='utf-8-sig') + self._json_read() logger.debug(f"Refreshed [{self._path}]") - @logger.catch - def get(self, section, name): - return self._config.get(section, name) - - @logger.catch - def getRaw(self, section, name): - return self._configRaw.get(section, name) - -global_config = Config(r"../config/config.ini") +global_config = Config(r"../config/config.json") diff --git a/common/logger.py b/common/logger.py index 4a124d8..cf9f4ac 100644 --- a/common/logger.py +++ b/common/logger.py @@ -7,7 +7,7 @@ class Logger: def __init__(self, log_file: str): os.chdir(os.path.dirname(__file__)) - self._config_path = os.path.abspath(r"../config/config.ini") + self._config_path = os.path.abspath(r"../config/config.json") self._log_fmt = "{time:YYYY-MM-DD HH:mm:ss.SSS} [{level:<5}] {file}.{line}: {message}" self._debug_fmt = "{time:YYYY-MM-DD HH:mm:ss.SSS} [{level:<5}] {name}:{function}:{line}: {message}" self._logger_conf(log_file) @@ -28,13 +28,13 @@ def _logger_conf(self, log_file): def _get_level(self): level_raw = "" try: - with open(self._config_path, "r", encoding="UTF-8") as f: + with open(self._config_path, "r", encoding="utf-8") as f: lines = f.readlines() for i in lines: if "level" in i and ";" != i[0]: level_raw = i except: - level_raw = "level = INFO" + level_raw = '"level": "DEBUG",' if "DEBUG" in level_raw: self._level = "DEBUG" else: diff --git a/common/push.py b/common/push.py index 80c0e72..630a00d 100644 --- a/common/push.py +++ b/common/push.py @@ -7,14 +7,14 @@ from urllib import parse from datetime import datetime from email.mime.text import MIMEText -from common.config import global_config +from common.config import global_config as gc from common.logger import logger class Email: @logger.catch def __init__(self, mail_user, mail_host, mail_pwd): - if global_config.getRaw('config', 'email_enable') == "off": + if gc.config['setting']['push']['email']['enable'] == "off": logger.debug("Email is disabled") return logger.debug("Email is enabled") @@ -25,17 +25,18 @@ def __init__(self, mail_user, mail_host, mail_pwd): self._is_login = False self.smtp = 0 self._mail_payload = "" + self._email_tmpl_path = gc.config['config']['path']['email_tmpl'] @logger.catch def _load_tmpl(self): os.chdir(os.path.dirname(__file__)) - with open(r"../res/email_tmpl.html", "r", encoding="UTF-8") as f: + with open(self._email_tmpl_path, "r", encoding="utf-8") as f: self._mail_payload = f.read() logger.debug(f'Loaded [{os.path.abspath(r"../res/email_tmpl.html")}]') @logger.catch def login(self): - if global_config.getRaw('config', 'email_enable') == "off": + if gc.config['setting']['push']['email']['enable'] == "off": return self._load_tmpl() try: @@ -75,18 +76,19 @@ def send(self, uid, title, msg, receiver: list): class Push: @logger.catch def __init__(self): - self._global_wechat = global_config.getRaw('config', 'wechat_enable') - self._global_email = global_config.getRaw('config', 'email_enable') - self._bot_email_user = global_config.getRaw('bot_email', 'email_user') - self._bot_email_host = global_config.getRaw('bot_email', 'email_host') - self._bot_email_pwd = global_config.getRaw('bot_email', 'email_pwd') + self._global_wechat = gc.config['setting']['push']['wechat']['enable'] + self._global_email = gc.config['setting']['push']['email']['enable'] + self._bot_email_user = gc.config['bot_email']['email_user'] + self._bot_email_host = gc.config['bot_email']['email_host'] + self._bot_email_pwd = gc.config['bot_email']['email_pwd'] self.bot_email = Email(self._bot_email_user, self._bot_email_host, self._bot_email_pwd) - self._errno_msg_path = r"../res/error.json" - self._errno_msg = self._load_errno() + self._errno_msg_path = gc.config['config']['path']['errno_msg'] + # self._errno_msg = self._load_errno() + self._errno_msg = gc.config['config']['errmsg'] @logger.catch def _load_errno(self): - with open(self._errno_msg_path, "r", encoding="UTF-8") as f: + with open(self._errno_msg_path, "r", encoding="utf-8") as f: self._raw = f.read() logger.debug(f'Loaded [{os.path.abspath(self._errno_msg_path)}]') return json.loads(self._raw) @@ -95,7 +97,7 @@ def _load_errno(self): @logger.catch def sct_wechat(uid, title, message, sendkey): now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") - url = f'https://sctapi.ftqq.com/{sendkey}.send' + url = f"{gc.config['config']['url']['sct']}/{sendkey}.send" ps = "" msg = f'{" " * 10}{title}\n\n{uid}:\n{" " * 4}{message}\n{ps}\n\n{now}' payload = { @@ -162,7 +164,7 @@ def push(self, result, uid, wechat_push, email_push, wechat_type, api, userid, s title = "[ERROR]" message = "ERROR!" if errno != 0: - errmsg = [i["msg"] for i in self._errno_msg["content"] if errno == i["errno"]][0] + errmsg = [i["msg"] for i in self._errno_msg if errno == i["errno"]][0] message = f'{message}[错误信息:"{errmsg}"]' logger.debug(f"Title:{title}#Message:{message}#Error code:{errno}") if self._global_wechat != "off": diff --git a/common/report.py b/common/report.py index a81ebc6..43115b8 100644 --- a/common/report.py +++ b/common/report.py @@ -6,6 +6,7 @@ from bs4 import BeautifulSoup from common import security from common.logger import logger +from common.config import global_config as gc class Report: @@ -18,6 +19,8 @@ def __init__(self): self._navigation_url = 0 self._date = "" self._captcha_code = "" + self._success = gc.config['config']['response']['success'] + self._existed = gc.config['config']['response']['existed'] @logger.catch def update_date(self): @@ -39,7 +42,7 @@ def _get_captcha_code(self): logger.error(f"No available hosts.") self._set_error(6, 1) return - url = f"{self._host}/weblogin.asp" + url = f"{self._host}/{gc.config['config']['url']['login']}" res = self._session.get(url=url, headers=self._headers) logger.debug(f"URL:{url}. Status code:{res.status_code}") res.encoding = "utf-8" @@ -59,7 +62,7 @@ def _login(self, uid, password): if self._error == 1: logger.debug(f"The error flag: {self._error}. Exit the function.") return - url = f"{self._host}/weblogin.asp" + url = f"{self._host}/{gc.config['config']['url']['login']}" payload = { "username": uid, "userpwd": password, @@ -88,7 +91,7 @@ def _get_navigation_url(self, target): if self._error == 1: logger.debug(f"The error flag: {self._error}. Exit the function.") return - url = f"{self._host}/left.asp" + url = f"{self._host}/{gc.config['config']['url']['left']}" res = self._session.get(url=url, headers=self._headers) logger.debug(f"URL:{url}. Status code:{res.status_code}") if res.status_code != 200: @@ -110,7 +113,7 @@ def _report_default_method(self): return "" logger.info("Try to report in the default method.") param = parse.parse_qs(parse.urlparse(str(self._navigation_url)).query) - url = f"{self._host}/projecthealth_addx.asp" + url = f"{self._host}/{gc.config['config']['url']['report_default']}" payload = { "id": param["id"][0], "id2": self._date, @@ -133,7 +136,7 @@ def _report(self, location): logger.info("Try to report in the alternate method.") [province, city, area] = location param = parse.parse_qs(parse.urlparse(str(self._navigation_url)).query) - url = f"{self._host}/projecthealth_add.asp" + url = f"{self._host}/{gc.config['config']['url']['report']}" payload = { "id": param["id"][0], "id2": self._date, @@ -189,27 +192,30 @@ def main(self, uid, password): self._error = 0 self._errno = 0 self._session = requests.Session() - self._host = f"https://xsswzx.cdu.edu.cn/{security.get_random_host()}/com_user" + _host_0 = gc.config['config']['url']['host_head'] + _host_1 = security.get_random_host() + _host_2 = gc.config['config']['url']['host_foot'] + self._host = f"{_host_0}/{_host_1}/{_host_2}" self._headers = { "User-Agent": security.get_random_useragent() } self._get_captcha_code() self._login(uid, password) - self._get_navigation_url("健康日报登记") + self._get_navigation_url(gc.config['config']['url']['navigation']) ret = self._report_default_method() - if "已存在" in ret: + if self._existed in ret: logger.info(f"The report is already existed. ID:{uid}") return 0, self._errno - elif "提交成功" in ret: + elif self._success in ret: logger.info(f"Successful to report. ID:{uid}") return 1, self._errno else: logger.error("Failed to report in the default method.") ret = self._report(self._fetch_location()) - if "已存在" in ret: + if self._existed in ret: logger.info(f"The report is already existed. ID:{uid}") return 0, self._errno - elif "提交成功" in ret: + elif self._success in ret: logger.info(f"Successful to report. ID:{uid}") return 1, self._errno else: diff --git a/common/security.py b/common/security.py index 5c591c7..cdb5658 100644 --- a/common/security.py +++ b/common/security.py @@ -2,29 +2,21 @@ import requests from common.logger import logger +from common.config import global_config as gc from fake_useragent import UserAgent -HOSTS = [ - "ispstu", # 富强 - "ispstu1-1", # 民主 - "ispstu1-2", # 文明 - "ispstu2", # 和谐 - "ispstu2-1", # 自由 - "ispstu2-2", # 平等 - "ispstu3", # 公正 - "ispstu3-1", # 法治 - "ispstu3-2", # 爱国 - "ispstu4", # 敬业 - "ispstu4-1", # 诚信 - "ispstu4-3" # 友善 -] +HOSTS = list(gc.config['config']['all_hosts'].keys()) ua = UserAgent(verify_ssl=False) available_host = [] @logger.catch def check_host_status(host): - url = f"https://xsswzx.cdu.edu.cn/{host}/com_user/weblogin.asp" + url_0 = gc.config['config']['url']['host_head'] + url_1 = host + url_2 = gc.config['config']['url']['host_foot'] + url_3 = gc.config['config']['url']['login'] + url = f"{url_0}/{url_1}/{url_2}/{url_3}" try: res = requests.get(url=url, timeout=10) logger.debug(f"URL:{url}. Status code:{res.status_code}") diff --git a/common/service.py b/common/service.py index 8f3a4f5..9fed61e 100644 --- a/common/service.py +++ b/common/service.py @@ -2,7 +2,7 @@ from time import sleep, time from common import security from common.logger import logger -from common.config import global_config +from common.config import global_config as gc from common.account import global_account from common.report import Report from common.push import global_push @@ -12,10 +12,10 @@ class ReportService: @logger.catch def __init__(self): self._str_now_time = "0.1" - self._wechat_push = global_config.getRaw('config', 'wechat_enable') - self._email_push = global_config.getRaw('config', 'email_enable') - self._wechat_type = global_config.getRaw('config', 'wechat_type') - self._api = global_config.getRaw('config', 'api') + self._wechat_push = gc.config['setting']['push']['wechat']['enable'] + self._wechat_type = gc.config['setting']['push']['wechat']['type'] + self._api = gc.config['setting']['push']['wechat']['api'] + self._email_push = gc.config['setting']['push']['email']['enable'] self._account_cnt = global_account.row self._report = Report() @@ -52,21 +52,21 @@ def _gen(self): @logger.catch def start(self): - if global_config.getRaw('config', 'timer_enable') == "off": + if gc.config['setting']['timer']['enable'] == "off": logger.info("Timer is disabled.") logger.info("Start to report.") self._gen() else: logger.info("Timer is enabled.") while True: - global_config.refresh() - str_set_time = global_config.getRaw('config', 'set_time') + gc.refresh() + str_set_time = str(gc.config['setting']['timer']['set_time']) str_now_time = self._get_now_time() logger.info(f"Now time:{str_now_time}. Set time:{str_set_time}.") while True: - global_config.refresh() - if str_set_time != global_config.getRaw('config', 'set_time'): - str_set_time = global_config.getRaw('config', 'set_time') + gc.refresh() + if str_set_time != str(gc.config['setting']['timer']['set_time']): + str_set_time = str(gc.config['setting']['timer']['set_time']) logger.info(f"New set time:{str_set_time}.") str_now_time = self._get_now_time() if str_now_time != str_set_time: diff --git a/config/config_example.ini b/config/config_example.ini deleted file mode 100644 index a0790a5..0000000 --- a/config/config_example.ini +++ /dev/null @@ -1,40 +0,0 @@ -; ########################### -; 使用时请修改文件名为 config.ini -; 以下填写均不需要引号! -; ########################### -[config] -; 如果想开启定时打卡,则将 timer_enable 设置为 on,默认为 off 不开启 -timer_enable = off - -; 开启定时打卡后必须设定打卡时间,如6点5分则输入06.05 -set_time = 06.05 - -; ########################################### -; 微信推送全局开关 -; 使用了Server酱的推送服务 -; 如果需要微信推送打卡结果,则将 wechat_enable 设置为 on,默认为 off 不开启 -wechat_enable = off - -;提供多种推送通道,目前仅支持sct企业微信和腾讯云自建企业微信(go-scf) -;如果需选择企业微信通道,则将 wechat_type 设置为 1,否则为 2 。默认为 1 sct企业微信通道 -wechat_type = 1 - -; 如果wechat_type = 2 ,必须填入 api (请求路径:https://xxxxxxxxxx) -api = -; ########################################### - -; 邮件推送全局开关 -; 如果需要邮件推送打卡结果,则将 email_enable 设置为 on,默认为 off 不开启 -email_enable = off - -[bot_email] -; 负责推送服务的邮箱 - -# 邮箱地址 xxxxxxxx@xx.com -email_user = - -# 邮箱域名 smtp.xx.com -email_host = - -# 邮箱授权码(并不一定是邮箱密码) xxxxxxxxxxxxxxxx -email_pwd = diff --git a/config/config_example.json b/config/config_example.json new file mode 100644 index 0000000..97399b7 --- /dev/null +++ b/config/config_example.json @@ -0,0 +1,108 @@ +{ + "setting": { + "timer": { + "//enable": "[必填]如果想开启定时打卡,则将 enable 设置为 on,默认为 off 不开启", + "enable": "off", + "//set_time": "[选填]开启定时打卡后必须设定打卡时间,如6点5分则输入06.05(用双引号包裹)", + "set_time": "06.05" + }, + "push": { + "//email": "邮件推送配置", + "email": { + "//enable": "[必填]如果需要邮件推送打卡结果,则将 enable 设置为 on,默认为 off 不开启", + "enable": "off" + }, + "//wechat": "微信推送配置,使用了Server酱的推送服务", + "wechat": { + "//enable": "[必填]微信推送全局开关。如果需要微信推送打卡结果,则将 enable 设置为 on,默认为 off 不开启", + "enable": "off", + "//type": "[选填]提供多种推送通道,目前仅支持sct企业微信和腾讯云自建企业微信(go-scf)。如果需选择企业微信通道,则将 type 设置为 1,否则为 2 。默认为 1 sct企业微信通道", + "type": 1, + "//api": "[选填]如果type = 2 ,必须填入 api (请求路径:https://xxxxxxxxxx)", + "api": "https://xxxxxxxxxx" + } + } + }, + "//bot_email": "[选填]负责推送服务的邮箱", + "bot_email": { + "//email_user": "邮箱地址 xxxxxxxx@xx.com", + "email_user": "", + "//email_host": "邮箱域名 smtp.xx.com", + "email_host": "", + "//email_pwd": "邮箱授权码(并不一定是邮箱密码)", + "email_pwd": "" + }, + "//config": "!!程序配置,请勿修改!!", + "config": { + "url": { + "host_head": "https://xsswzx.cdu.edu.cn", + "host_foot": "com_user", + "login": "weblogin.asp", + "left": "left.asp", + "navigation": "健康日报登记", + "report_default": "projecthealth_addx.asp", + "report": "projecthealth_add.asp", + "sct": "https://sctapi.ftqq.com" + }, + "path": { + "account_file": "../config/account.csv", + "email_tmpl": "../config/email_tmpl.html" + }, + "response": { + "success": "提交成功", + "existed": "已存在" + }, + "all_hosts": { + "ispstu": "富强", + "ispstu1-1": "民主", + "ispstu1-2": "文明", + "ispstu2": "和谐", + "ispstu2-1": "自由", + "ispstu2-2": "平等", + "ispstu3": "公正", + "ispstu3-1": "法治", + "ispstu3-2": "爱国", + "ispstu4": "敬业", + "ispstu4-1": "诚信", + "ispstu4-3": "友善" + }, + "errmsg": [ + { + "errno": 0, + "msg": "OK" + }, + { + "errno": -1, + "msg": "未知错误" + }, + { + "errno": 1, + "msg": "提取验证码失败" + }, + { + "errno": 2, + "msg": "登录ISP系统失败:学号、密码或验证码错误" + }, + { + "errno": 3, + "msg": "解析『疫情信息登记』地址失败" + }, + { + "errno": 4, + "msg": "解析『【一键登记:无变化】』地址失败" + }, + { + "errno": 5, + "msg": "解析最近一次登记记录失败,已为您强制打卡" + }, + { + "errno": 6, + "msg": "网络错误,与ISP系统建立连接失败" + }, + { + "errno": 7, + "msg": "解析最新登记地点失败,请手动打卡" + } + ] + } +} \ No newline at end of file diff --git a/res/email_tmpl.html b/config/email_tmpl.html similarity index 100% rename from res/email_tmpl.html rename to config/email_tmpl.html diff --git a/main.py b/main.py index c0e55ed..abe792e 100644 --- a/main.py +++ b/main.py @@ -12,6 +12,6 @@ |_| """ print(LOGO) -log_version("beta", "1.3.1") +log_version("beta", "1.4.0") report_service = ReportService() report_service.start() diff --git a/res/error.json b/res/error.json deleted file mode 100644 index 66a4c68..0000000 --- a/res/error.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "WARNING" : "DO NOT EDIT THIS FILE!", - "content" : [ - { - "errno" : 0, - "msg" : "OK" - }, - { - "errno" : -1, - "msg" : "未知错误" - }, - { - "errno" : 1, - "msg" : "提取验证码失败" - }, - { - "errno" : 2, - "msg" : "登录ISP系统失败:学号、密码或验证码错误" - }, - { - "errno" : 3, - "msg" : "解析『疫情信息登记』地址失败" - }, - { - "errno" : 4, - "msg" : "解析『【一键登记:无变化】』地址失败" - }, - { - "errno" : 5, - "msg" : "解析最近一次登记记录失败,已为您强制打卡" - }, - { - "errno" : 6, - "msg" : "网络错误,与ISP系统建立连接失败" - }, - { - "errno" : 7, - "msg" : "解析最新登记地点失败,请手动打卡" - } - ] -}