From 2d23b78ac8c185de020adf88fbbf6549b2c54458 Mon Sep 17 00:00:00 2001 From: Mufanc <47652878+Mufanc@users.noreply.github.com> Date: Thu, 7 Oct 2021 02:53:30 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=A1=B9=E7=9B=AE=EF=BC=8C?= =?UTF-8?q?=E7=BB=93=E6=9E=84=E5=9F=BA=E6=9C=AC=E5=AE=8C=E5=96=84=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20|=20=E5=91=BD=E4=BB=A4=E8=A1=8C=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E5=92=8C=E9=80=89=E9=A1=B9=E7=9A=84=E6=94=AF=E6=8C=81?= =?UTF-8?q?=20=E6=96=B0=E5=A2=9E=20|=20=E6=94=AF=E6=8C=81=E5=88=97?= =?UTF-8?q?=E5=87=BA=E6=89=80=E5=AD=A6=E8=AF=BE=E7=A8=8B=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=20|=20=E7=8E=B0=E5=9C=A8=E5=8F=AF=E4=BB=A5=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=88=A4=E6=96=AD=E7=88=AC=E8=99=AB=E5=92=8C=E5=AE=A2?= =?UTF-8?q?=E6=88=B7=E7=AB=AF=E8=B4=A6=E6=88=B7=E6=98=AF=E5=90=A6=E7=9B=B8?= =?UTF-8?q?=E5=90=8C=20=E4=BC=98=E5=8C=96=20|=20=E9=9A=8F=E6=9C=BA?= =?UTF-8?q?=E5=88=86=E6=95=B0=E5=92=8C=E6=97=B6=E9=97=B4=E7=9A=84=E9=85=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 38 +++++++++-- automaton/__init__.py | 2 - automaton/devtools.py | 70 ++++++++------------ automaton/spider/spider.py | 63 ++++++++++++++++-- automaton/utils.py | 130 +++++++++++++++++++++++++++++++------ configs.py | 5 +- configs.yml | 26 +++----- images/current_course.png | Bin 0 -> 53723 bytes main.py | 35 +++++++--- 9 files changed, 270 insertions(+), 99 deletions(-) create mode 100644 images/current_course.png diff --git a/README.md b/README.md index faec98b..4e9a4ad 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -## iSmart 课程自动姬 v1.0.0 +## iSmart 课程自动姬 v1.0.2 >
「不止于自动化,追求极致效率」

> @@ -39,14 +39,42 @@ ### 使用方法 -  修改 `configs.yml` 中的账号和密码,保证与 iSmart 客户端中登录的账号一致,然后修改 iSmart 的启动快捷方式,增加参数 `--remote-debugging-port=9222`: +  修改 iSmart 的启动快捷方式,增加参数 `--remote-debugging-port=9222`(如下图),**然后启动 iSmart 客户端并保持登录** ![](images/edit-lnk.png) -  此时运行 main.py,启动 iSmart 客户端,进入某本书籍的教材学习页(如下图),脚本会自动提交成绩。 +  修改 `configs.yml` 中的账号和密码,保证与 iSmart 客户端中登录的账号一致,然后根据需要调整下方参数。在终端中执行 `py main.py -h` 可以查看更多帮助信息,这里列举几个常用命令 + +* 列出所有课程和书籍的详细信息 + +```shell +py main.py list -d +``` + +
+ +* 根据书籍 id 执行刷课 + +```shell +py main.py flash -i 51627#7B6911511DB6B33638F6C58531D8FBD3 +``` + +
+ +* 根据当前打开的页面执行刷课 + +```shell +py main.py flash -c +``` + +注意如果打开的是「教材学习」页(如下图),只会刷打开的这一本书籍的任务 ![](images/booklearn.png) -### 写在最后 +而如果是在课程详情页面,则会对该课程下的所有书籍执行刷课: + +![](images/current_course.png) + +### 过滤器语法 -  该项目尚处于起步阶段,项目结构还没有完全确定下来,所以后续可能会经历多次重构。目前很多功能虽然存在于源码中,但还不完善或者未经测试,可能造成意料之外的结果,所以在使用前还请三思 +* 待完善 \ No newline at end of file diff --git a/automaton/__init__.py b/automaton/__init__.py index 64948a8..e69de29 100644 --- a/automaton/__init__.py +++ b/automaton/__init__.py @@ -1,2 +0,0 @@ -from .spider import Spider -from .devtools import Browser diff --git a/automaton/devtools.py b/automaton/devtools.py index b8ae184..86af9c6 100644 --- a/automaton/devtools.py +++ b/automaton/devtools.py @@ -1,40 +1,29 @@ import asyncio -import ctypes import json import re +import urllib.parse as parser import httpx import websockets from loguru import logger from configs import configs -from .utils import ainput - -_default_port = configs['browser']['port'] -_executable = configs['browser']['executable'] -_args = configs['browser']['args'] class Browser(object): @classmethod - def connect(cls): - return cls(_default_port) - - @classmethod - def launch(cls): - ctypes.windll.shell32.ShellExecuteW( - None, 'runas', _executable, - ' '.join([f'--remote-debugging-port={_default_port}', *_args]), - None, 1 - ) - return cls(_default_port) + async def connect(cls): + browser = cls(configs['browser']['port']) + if configs['browser']['verify'] and not await browser._verify(): + return None + return browser def __init__(self, dev_port): self.port = dev_port - async def verify(self): # 校验客户端和配置文件中的用户是否相同 + async def _verify(self): # 校验客户端和配置文件中的用户是否相同 logger.info('正在校验账号...') - page = await self._any_http_page() + page = await self.wait_for_page(r'https?://.*') user_info = json.loads((await page.eval(''' (function () { var xhr = new XMLHttpRequest() @@ -47,47 +36,35 @@ class Browser(object): spider_user = configs['user']['username'] if spider_user != user_info['mobile'] and spider_user != user_info['username']: logger.warning('检测到 iSmart 客户端中登录的账号与配置文件中账号不符!') - choice = await ainput('继续使用可能会出现意料之外的问题,是否继续?[y/N]') + choice = input('继续使用可能会出现意料之外的问题,是否继续?[y/N]') if choice.lower() != 'y': return False else: logger.info('校验通过!') return True - async def wait_for_book(self): # 等待「教材学习」页面 - async with httpx.AsyncClient() as client: - while True: - logger.info('等待「教材学习」页面...') - try: - pages = (await client.get(f'http://127.0.0.1:{self.port}/json')).json() - for page in pages: - if re.match(r'.*me.ismartlearning.cn/center/student/course/bookLearn.html.*', page['url']) and \ - 'webSocketDebuggerUrl' in page: - return Page(page['url'], page['webSocketDebuggerUrl']) - except httpx.ConnectError: - pass - await asyncio.sleep(2) - - async def _any_http_page(self): + async def wait_for_page(self, regexp): # 等待符合条件的页面出现 async with httpx.AsyncClient() as client: while True: logger.info('等待可用页面...') try: pages = (await client.get(f'http://127.0.0.1:{self.port}/json')).json() for page in pages: - if re.match(r'https?://.*', page['url']) and 'webSocketDebuggerUrl' in page: + if re.fullmatch(regexp, page['url']) and 'webSocketDebuggerUrl' in page: return Page(page['url'], page['webSocketDebuggerUrl']) except httpx.ConnectError: pass await asyncio.sleep(2) - async def submit(self, book_id, chapter_id, task_id, score, seconds, percent, user_id): # 提交任务点的得分 - page = await self._any_http_page() - model = 'NetBrowser.submitTask("%s", "%s", "%s", 0, "%d", %d, %d, "%s");' - result = f'%7B%22studentid%22:{user_id},%22testInfo%22:%7B%22answerdata%22:%22%22,%22markdatao%22:%22%22%7D%7D' - return await page.eval( - model % (book_id, chapter_id, task_id, score, seconds, percent, result) - ) + # noinspection PyTypeChecker + async def get_current(self): + async with httpx.AsyncClient() as client: + pages = (await client.get(f'http://127.0.0.1:{self.port}/json')).json() + for page in pages: + params = dict(parser.parse_qsl(parser.urlsplit(page['url']).query)) + if 'bookId' in params: + return params['courseId'], params['bookId'] + return params['courseId'], None class Page(object): @@ -113,3 +90,10 @@ class Page(object): } ) return result['result'] + + async def submit(self, book_id, chapter_id, task_id, score, seconds, percent, user_id): # 提交任务点的得分 + model = 'NetBrowser.submitTask("%s", "%s", "%s", 0, "%d", %d, %d, "%s");' + result = f'%7B%22studentid%22:{user_id},%22testInfo%22:%7B%22answerdata%22:%22%22,%22markdatao%22:%22%22%7D%7D' + return await self.eval( + model % (book_id, chapter_id, task_id, score, seconds, percent, result) + ) diff --git a/automaton/spider/spider.py b/automaton/spider/spider.py index 464511f..49ae6d9 100644 --- a/automaton/spider/spider.py +++ b/automaton/spider/spider.py @@ -5,14 +5,30 @@ import httpx from loguru import logger from .captcha import recognize -from ..utils import Tree + + +class Tree: # 任务树 + def __init__(self, task): + self.task = task + self.child = [] + + def sort(self): + self.child.sort( + key=lambda node: node.task['displayOrder'] + ) + for ch in self.child: + ch.sort() class Spider(httpx.AsyncClient): def __init__(self): super().__init__() + self.is_login = False async def login(self, username, password): + if self.is_login: + return {} + self.cookies.clear() # 重置 cookies logger.info('正在获取验证码...') result = await self.get(f'http://sso.ismartlearning.cn/captcha.html?{random()}') @@ -34,6 +50,7 @@ class Spider(httpx.AsyncClient): logger.debug(info['result']) assert info['result']['code'] == -26 # 断言登录结果 + self.is_login = True return info['result'] async def get_courses(self): # 获取课程列表 @@ -49,7 +66,13 @@ class Spider(httpx.AsyncClient): async def get_books(self, course_id): # 获取某课程的书籍列表 logger.info('正在获取书籍列表...') - await self.get_courses() # 必须有这个请求,否则后面会报错 + await self.post( # 必须有这个请求,否则后面会报错 + 'http://school.ismartlearning.cn/client/course/list-of-student?status=1', + data={ + 'pager.currentPage': 1, + 'pager.pageSize': 32767 + } + ) books = (await self.post( 'http://school.ismartlearning.cn/client/course/textbook/list-of-student', data={ @@ -60,6 +83,7 @@ class Spider(httpx.AsyncClient): async def get_tasks(self, book_id, book_type, course_id): # 获取某书籍的任务树 logger.info('正在获取任务列表...') + await self.post('http://school.ismartlearning.cn/client/course/textbook/chapters') tasks = (await self.post( 'http://school.ismartlearning.cn/client/course/textbook/chapters', data={ @@ -69,9 +93,11 @@ class Spider(httpx.AsyncClient): } )).json()['data'] id_record = {task['id']: Tree(task) for task in tasks} + book_name = (await self.book_info(book_id))['bookName'] root = Tree({ 'book_id': tasks[0]['book_id'], - 'unitStudyPercent': 0 + 'unitStudyPercent': 0, + 'name': book_name }) for task_id in id_record: node = id_record[task_id] @@ -80,9 +106,10 @@ class Spider(httpx.AsyncClient): if (parent_id := node.task['parent_id']) in id_record: id_record[parent_id].child.append(node) else: - logger.warning(f'任务已忽略(父节点不存在):{node_name}') + logger.warning(f'父节点不存在:{node_name}') else: root.child.append(node) + root.sort() return root async def get_paper(self, paper_id): # 获取任务点信息(包括题目和答案) @@ -92,6 +119,7 @@ class Spider(httpx.AsyncClient): 'service': 'http://xot-api.ismartlearning.cn/client/textbook/paperinfo' } )).json()['data']['serverTicket'] + logger.debug(f'Ticket: {ticket}') paper_info = (await self.post( 'http://xot-api.ismartlearning.cn/client/textbook/paperinfo', data={ @@ -114,3 +142,30 @@ class Spider(httpx.AsyncClient): return (await self.post( 'https://school.ismartlearning.cn/client/user/student-info') ).json() + + async def book_info(self, book_id): + logger.info('正在获取书籍信息...') + ticket = (await self.post( + 'http://sso.ismartlearning.cn/v1/serviceTicket', + data={ + 'service': 'http://book-api.ismartlearning.cn/client/v2/book/info' + } + )).json()['data']['serverTicket'] + logger.debug(f'Ticket: {ticket}') + book_info = (await self.post( + 'http://book-api.ismartlearning.cn/client/v2/book/info', + headers={ + 'Origin': 'http://me.ismartlearning.cn', + 'Referer': 'http://me.ismartlearning.cn/', + 'X-Requested-With': 'XMLHttpRequest', + 'Accept-Encoding': 'gzip, deflate' + }, + params={ + 'ticket': ticket + }, + data={ + 'bookId': book_id, + 'bookType': 0 + } + )).json() + return book_info['data'] diff --git a/automaton/utils.py b/automaton/utils.py index f002a54..dab53c6 100644 --- a/automaton/utils.py +++ b/automaton/utils.py @@ -1,33 +1,123 @@ -import asyncio -from concurrent.futures import ThreadPoolExecutor +import json import urllib.parse as parser +from random import uniform, randint + +from bs4 import BeautifulSoup +from loguru import logger from configs import configs from .devtools import Browser from .spider import Spider +PLACEHOLDER = '. ' +_paper_config = configs['paper'] + + +async def list_books(detail): + async with Spider() as spider: + await spider.login(**configs['user']) + courses = await spider.get_courses() + + for cr in courses: + if detail: + hint = f'{cr["courseName"]} ({cr["teacherName"]})' + else: + hint = cr['courseName'] + print(hint) + + books = await spider.get_books(cr["courseId"]) + for book in books: + if detail: + hint = f'> [{cr["courseId"]}#{book["bookId"]}] {book["bookName"]} ({book["percent"]}%)' + else: + hint = f'> {book["bookName"]}' + print(PLACEHOLDER + hint) + + +async def _random(spider, paper_id): # 随机的分数和学习时长 + paper = BeautifulSoup((await spider.get_paper(paper_id))['paperData'], 'lxml-xml') + questions = paper.select('element[knowledge]:has(> question_type)') + if not questions: + return 100, 5 + + total = 0 + score, time = 0, 0 + for q in questions: + q_type = int(q.select_one('question_type').text) + q_score = float(q.select_one('question_score').text) + total += q_score + + ranges = _paper_config['random-score'] + if q_type <= len(ranges) and (r := ranges[q_type-1]) is not None: + if not isinstance(ranges[q_type-1], list): + r = [r, r] + score += q_score * uniform(*r) + else: + q_no = q.select_one('question_no').text + logger.warning(f'T{q_no}:未知的题型!') + if (r := _paper_config['defaults']) == 'pause': + score += float(input('请手动输入该题得分 [0-1]:')) + else: # defaults + score += q_score * uniform(*r) -class Tree: # 任务树 - def __init__(self, task): - self.task = task - self.child = [] + time += randint(*_paper_config['random-time']) + return int(100 * score / total), time -async def ainput(prompt: str = ''): - with ThreadPoolExecutor(1, 'ainput') as executor: - return ( - await asyncio.get_event_loop().run_in_executor(executor, input, prompt) - ).rstrip() + +async def _flash(course_id, book_id, spider): + async def dfs(node, depth=0): + task = node.task + print(PLACEHOLDER * depth + task['name']) + if _paper_config['skip-finished'] and task['unitStudyPercent'] == 100: + print(PLACEHOLDER * depth + '# Skipped') + return + if 'paperId' in task: # 如果有任务则提交 + chapter_id = task['chapterId'] + task_id = task['id'] + score, time = await _random(spider, task['paperId']) + result = await page.submit(book_id, chapter_id, task_id, score, time, 100, user_id) + if result['wasThrown'] or not result['result']['value']: + logger.warning(f'任务 {task["name"]} 可能提交失败,请留意最终结果!') + for ch in node.child: + await dfs(ch, depth + 1) + + browser = await Browser.connect() + page = await browser.wait_for_page(r'https?://pc\.ismartin\.com.*') + + # With Spider + await spider.login(**configs['user']) + user_id = (await spider.user_info())['data']['uid'] + + book_type = (await spider.book_info(book_id))['bookType'] + root = await spider.get_tasks(book_id, book_type, course_id) + await dfs(root) + + +async def flash_by_id(identity): + async with Spider() as spider: + await _flash(*identity.split('#'), spider) + + +async def flash_current(): # 对当前课程或书籍执行刷课 + browser = await Browser.connect() + course_id, book_id = await browser.get_current() + async with Spider() as spider: + if book_id: + await _flash(course_id, book_id, spider) + else: + await spider.login(**configs['user']) + books = await spider.get_books(course_id) + for book in books: + await _flash(course_id, book['bookId'], spider) -async def flash_recent(): # 对当前书籍执行刷课 - if configs['browser']['mode'] == 'launch': - browser = Browser.launch() - else: - browser = Browser.connect() - page = await browser.wait_for_book() - params = dict(parser.parse_qsl(parser.urlsplit(page.url).query)) - # noinspection PyTypeChecker - book_id, course_id = params['bookId'], params['courseId'] +async def flash_all(): async with Spider() as spider: await spider.login(**configs['user']) + courses = await spider.get_courses() + for course in courses: + course_id = course['courseId'] + books = await spider.get_books(course_id) + for book in books: + await _flash(course_id, book['bookId'], spider) diff --git a/configs.py b/configs.py index 6db0278..eb9d085 100644 --- a/configs.py +++ b/configs.py @@ -1,10 +1,13 @@ import yaml - with open('configs.yml', 'r', encoding='utf-8') as _fp: configs = yaml.safe_load(_fp) +def update(conf): + configs.update(conf) + + if __name__ == '__main__': import json print(json.dumps(configs, indent=4)) diff --git a/configs.yml b/configs.yml index 455604b..55280c8 100644 --- a/configs.yml +++ b/configs.yml @@ -1,17 +1,7 @@ -# Todo: 每次 commit 之前务必清除账号密码 - -# 刷课配置 -project: - skip-finished: true # 跳过已完成任务(暂不支持) - -# iSmart 客户端配置 browser: - mode: connect # 连接模式( connect / launch ) - # 下面为 mode = launch 时的配置 - executable: Z:\iSmart\client\iSmart.exe # 客户端可执行文件的路径 - args: # 启动 iSmart 客户端时额外提供的参数 - - --disable-web-security - port: 9222 # devTools 调试端口 + port: 9222 + verify: true + # 用户配置(务必保持账号密码与 iSmart 中已登录的相同) user: @@ -20,8 +10,10 @@ user: # 答题配置 paper: + skip-finished: true # 跳过已完成任务 + # 不同题目类型的随机得分 - ramdom-score: # Todo: 判断列表长度 + random-score: - 1 # 1.单选 - 1 # 2.多选 - 1 # 3.判断 @@ -33,6 +25,8 @@ paper: - [ 0.7, 1 ] # 9.口语跟读 - [ 0.7, 1 ] # 10.短文改错 - 1 # 11.选词填空 - defaults: pause # 未知题型的处理方式 - random-time: [ 90, 240 ] # 每道题的随机用时(秒) + - + defaults: pause # 未知题型的处理方式(暂停或使用默认得分) +# defaults: [ 1, 1 ] + random-time: [ 90, 180 ] # 每道题的随机用时(秒) diff --git a/images/current_course.png b/images/current_course.png new file mode 100644 index 0000000000000000000000000000000000000000..60b72c6268cdc8b8dc04d8c1db3607fcf11be7e8 GIT binary patch literal 53723 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%0A4QSROk>bdIps7)$&@1JX>RO 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
  • pIH#Y`SVbkLJ!u*lPVOLpGV6@f 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 literal 0 HcmV?d00001 diff --git a/main.py b/main.py index 56ed878..a55aca8 100644 --- a/main.py +++ b/main.py @@ -1,23 +1,42 @@ import asyncio +import sys from argparse import ArgumentParser +from loguru import logger + +from automaton import utils + async def main(): parser = ArgumentParser('main.py') - parser.add_argument('-v', dest='LEVEL', default='warning', help='日志过滤等级,默认为 warning') - subparsers = parser.add_subparsers(help='模式选择') + + parser.add_argument('-v', dest='level', action='count', help='日志过滤等级,依次为 warning, info, debug') + subparsers = parser.add_subparsers(dest='method', help='模式选择') method_list = subparsers.add_parser('list', help='列出所有课程和书籍') + method_list.add_argument('-d', '--detail', action='store_true', help='显示详细信息') method_flash = subparsers.add_parser('flash', help='对选定的一个或几个课程执行刷课') target = method_flash.add_mutually_exclusive_group() - target.add_argument('-b', '--book', action='store_true', help='对当前打开的书籍执行刷课') - target.add_argument('-c', '--course', action='store_true', help='对当前打开的课程执行刷课') - target.add_argument('-a', '--all', action='store_true', help='对所有课程和书籍执行刷课') - method_flash.add_argument('-f', '--filter', help='') - method_flash.add_argument('-i', '--invert', help='过滤器反向') + target.add_argument('-i', '--id', help='直接指定书籍 id') + target.add_argument('-c', '--current', action='store_true', help='限定当前课程或书籍') + target.add_argument('-a', '--all', action='store_true', help='选择全部') + method_flash.add_argument('-f', '--filter', help='任务过滤器,设置后只刷匹配的任务(尚未实现)') # Todo: 实现这个 + + args = parser.parse_args() + + logger.remove() + logger.add(sys.stdout, level=['WARNING', 'INFO', 'DEBUG'][args.level or 0]) - parser.parse_args() + if args.method == 'list': + await utils.list_books(detail=args.detail) + elif args.method == 'flash': + if args.id: + await utils.flash_by_id(args.id) + elif args.current: + await utils.flash_current() + elif args.all: + await utils.flash_all() if __name__ == '__main__': loop = asyncio.new_event_loop()