├── __init__.py ├── custom ├── __init__.py └── xuexi_chrome.py ├── getData ├── __init__.py ├── version.py ├── get_video.py ├── get_article.py └── dataTimeOperation.py ├── operation ├── __init__.py ├── check_version.py ├── scan_article.py ├── watch_video.py ├── get_chromedriver.py └── exam.py ├── userOperation ├── __init__.py ├── logout.py ├── login.py └── check.py ├── .gitignore ├── xxqg.ico ├── 效果图1.png ├── 效果图2.png ├── 效果图3.png ├── 效果图4.png ├── xuexi.jpg ├── chromedriver.exe ├── requirements.txt ├── data ├── lastTime.json └── settings.json ├── LICENSE ├── xuexi.spec ├── README.md └── xuexi.py /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /custom/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /getData/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /operation/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /userOperation/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /build/ 3 | /dist/ 4 | /data/exam_temp.json 5 | -------------------------------------------------------------------------------- /xxqg.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Devin-Kung/xxqg/HEAD/xxqg.ico -------------------------------------------------------------------------------- /效果图1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Devin-Kung/xxqg/HEAD/效果图1.png -------------------------------------------------------------------------------- /效果图2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Devin-Kung/xxqg/HEAD/效果图2.png -------------------------------------------------------------------------------- /效果图3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Devin-Kung/xxqg/HEAD/效果图3.png -------------------------------------------------------------------------------- /效果图4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Devin-Kung/xxqg/HEAD/效果图4.png -------------------------------------------------------------------------------- /xuexi.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Devin-Kung/xxqg/HEAD/xuexi.jpg -------------------------------------------------------------------------------- /chromedriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Devin-Kung/xxqg/HEAD/chromedriver.exe -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Devin-Kung/xxqg/HEAD/requirements.txt -------------------------------------------------------------------------------- /getData/version.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | # 当前程序版本号 3 | VERSION = '1.0.9.2' 4 | -------------------------------------------------------------------------------- /data/lastTime.json: -------------------------------------------------------------------------------- 1 | { 2 | "articles": "2022-07-24", 3 | "videos": "2022-07-24" 4 | } -------------------------------------------------------------------------------- /data/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "浏览文章": "true", 3 | "观看视频": "true", 4 | "自动答题": "true", 5 | "每日答题": "true", 6 | "每周答题": "true", 7 | "专项答题": "true", 8 | "答题时间设置": { 9 | "是否启用(关闭则每天都答题)": "false", 10 | "答题类型(数字代表星期几)": { 11 | "每日答题": "1,2,3,4,5,6,7", 12 | "每周答题": "1,2,3,4,5,6,7", 13 | "专项答题": "1,2,3,4,5,6,7" 14 | } 15 | }, 16 | "自动更新ChromeDriver": "true" 17 | } -------------------------------------------------------------------------------- /userOperation/logout.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | from random import uniform 3 | from time import sleep 4 | from selenium.webdriver.common.by import By 5 | from custom.xuexi_chrome import XuexiChrome 6 | 7 | 8 | def logout(browser: XuexiChrome): 9 | browser.xuexi_get('https://www.xuexi.cn/') 10 | sleep(round(uniform(1, 2), 2)) 11 | logout_btn = browser.find_element(by=By.CLASS_NAME, value='logged-link') 12 | logout_btn.click() 13 | -------------------------------------------------------------------------------- /userOperation/login.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | from time import sleep 3 | from selenium.webdriver.common.by import By 4 | from custom.xuexi_chrome import XuexiChrome 5 | 6 | 7 | def login(browser: XuexiChrome): 8 | """ 9 | 扫码登录流程,将登录的最终结果返回给主程序 10 | :param browser: browser 11 | :return: bool,表示是否登录成功 12 | """ 13 | browser.xuexi_get('https://pc.xuexi.cn/points/my-points.html') 14 | sleep(2.5) 15 | print('--> 请在5分钟内扫码完成登录') 16 | browser.implicitly_wait(10) 17 | qglogin = browser.find_element(by=By.ID, value='qglogin') 18 | browser.execute_script('arguments[0].scrollIntoView();', qglogin) 19 | 20 | for i in range(60): 21 | if browser.current_url == 'https://pc.xuexi.cn/points/my-points.html': 22 | print('--> 登录成功') 23 | return True 24 | sleep(5) 25 | return False 26 | -------------------------------------------------------------------------------- /getData/get_video.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | from getData import dataTimeOperation 3 | from requests import get 4 | from json import loads, dumps 5 | 6 | 7 | def get_video(): 8 | if not dataTimeOperation.is_get_data('videos'): 9 | return 10 | headers = { 11 | "Accept": "application/json", 12 | "Connection": "keep-alive", 13 | "DNT": "1", 14 | "Host": "www.xuexi.cn", 15 | "Referer": "https://www.xuexi.cn/a191dbc3067d516c3e2e17e2e08953d6/b87d700beee2c44826a9202c75d18c85.html", 16 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" 17 | } 18 | 19 | articles = get(url='https://www.xuexi.cn/lgdata/4d82ahlubmol.json', headers=headers) 20 | with open('./data/videos.json', 'w', encoding='utf-8') as f: 21 | f.write(dumps(loads(articles.content), ensure_ascii=False, indent=4)) 22 | dataTimeOperation.set_time('videos') 23 | print('--> 视频数据更新成功') 24 | 25 | 26 | if __name__ == '__main__': 27 | get_video() 28 | -------------------------------------------------------------------------------- /getData/get_article.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | from getData import dataTimeOperation 3 | from requests import get 4 | from json import loads, dumps 5 | 6 | 7 | def get_article(): 8 | if not dataTimeOperation.is_get_data('articles'): 9 | return 10 | headers = { 11 | "Accept": "application/json", 12 | "Connection": "keep-alive", 13 | "DNT": "1", 14 | "Host": "www.xuexi.cn", 15 | "Referer": "https://www.xuexi.cn/4f5aa999a479568bf620109395d8fe56/69fe65d658afc891dd105e1ce9e5879d.html", 16 | "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" 17 | } 18 | 19 | articles = get(url='https://www.xuexi.cn/lgdata/u1ght1omn2.json', headers=headers) 20 | with open('./data/articles.json', 'w', encoding='utf-8') as f: 21 | f.write(dumps(loads(articles.content), ensure_ascii=False, indent=4)) 22 | dataTimeOperation.set_time('articles') 23 | print('--> 文章数据更新成功') 24 | 25 | 26 | if __name__ == '__main__': 27 | get_article() 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 PRaichu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /xuexi.spec: -------------------------------------------------------------------------------- 1 | # -*- mode: python ; coding: utf-8 -*- 2 | 3 | 4 | block_cipher = None 5 | 6 | 7 | a = Analysis(['xuexi.py'], 8 | pathex=['E:\\CodeWork\\Python\\xxqg'], 9 | binaries=[], 10 | datas=[], 11 | hiddenimports=[], 12 | hookspath=[], 13 | hooksconfig={}, 14 | runtime_hooks=[], 15 | excludes=[], 16 | win_no_prefer_redirects=False, 17 | win_private_assemblies=False, 18 | cipher=block_cipher, 19 | noarchive=False) 20 | pyz = PYZ(a.pure, a.zipped_data, 21 | cipher=block_cipher) 22 | 23 | exe = EXE(pyz, 24 | a.scripts, 25 | a.binaries, 26 | a.zipfiles, 27 | a.datas, 28 | [], 29 | name='xuexi', 30 | debug=False, 31 | bootloader_ignore_signals=False, 32 | strip=False, 33 | upx=True, 34 | upx_exclude=[], 35 | runtime_tmpdir=None, 36 | console=True, 37 | disable_windowed_traceback=False, 38 | target_arch=None, 39 | codesign_identity=None, 40 | entitlements_file=None , icon='xxqg.ico') 41 | -------------------------------------------------------------------------------- /custom/xuexi_chrome.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | from selenium import webdriver 3 | from random import uniform 4 | from time import sleep 5 | from selenium.webdriver.chrome.webdriver import DEFAULT_KEEP_ALIVE 6 | 7 | 8 | class XuexiChrome(webdriver.Chrome): 9 | """ 10 | 自定义webdriver 11 | """ 12 | def __init__(self, executable_path="chromedriver", port=0, options=None, service_args=None, 13 | desired_capabilities=None, service_log_path=None, chrome_options=None, 14 | service=None, keep_alive=DEFAULT_KEEP_ALIVE): 15 | super().__init__(executable_path, port, options, service_args, desired_capabilities, service_log_path, 16 | chrome_options, service, keep_alive) 17 | 18 | def xuexi_get(self, url): 19 | """ 20 | 自定义webdriver的get请求; 21 | 发起请求前先移除Chrome的window.navigator.webdriver参数,并随机等待,减少被检测的风险 22 | :param url: 23 | :return: 24 | """ 25 | self.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", { 26 | 'source': ''' 27 | Object.defineProperty(navigator, 'webdriver', { 28 | get: () => undefined 29 | }) 30 | window.alert = function() { 31 | return; 32 | } 33 | ''' 34 | }) 35 | self.get(url) 36 | self.implicitly_wait(10) 37 | sleep(round(uniform(1.5, 2.5), 2)) 38 | -------------------------------------------------------------------------------- /operation/check_version.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | from traceback import format_exc 3 | from requests import get 4 | from json import loads 5 | from getData.version import VERSION 6 | 7 | 8 | def get_latest_version(): 9 | url = 'https://api.github.com/repos/PRaichu/xxqg/releases/latest' 10 | headers = { 11 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36' 12 | } 13 | try: 14 | response_data = get(url=url, headers=headers).content 15 | latest_version = loads(response_data)['tag_name'] 16 | return latest_version 17 | except ValueError: 18 | print(str(format_exc())) 19 | print('--> \033[31m请求版本号失败,请检查是否开启了VPN或代理软件,如果开启了请关闭后再试\033[0m') 20 | print('--> \033[31m此处报错为版本号请求失败,不会影响程序运行,无需关闭程序\033[0m') 21 | return None 22 | except: 23 | print(str(format_exc())) 24 | print('--> \033[31m请求版本号失败,请检查你的网络环境\033[0m') 25 | print('--> \033[31m此处报错为版本号请求失败,不会影响程序运行,无需关闭程序\033[0m') 26 | return None 27 | 28 | 29 | def check(): 30 | latest_version = get_latest_version() 31 | if latest_version is not None and VERSION != latest_version: 32 | print('--> 程序当前版本号:{},最新版本号:\033[32m{}\033[0m,该版本可能已过时,建议下载最新版本以获得更好的体验!'.format(VERSION, latest_version)) 33 | print('--> 下载地址:https://github.com/PRaichu/xxqg/releases/latest') 34 | print('--> 当然,你也可以选择不更新,这不会影响当前程序的使用!\n') 35 | 36 | 37 | if __name__ == '__main__': 38 | check() 39 | -------------------------------------------------------------------------------- /operation/scan_article.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | from json import loads, dumps 3 | from time import sleep 4 | from random import randint, uniform 5 | from rich.progress import Progress 6 | from custom.xuexi_chrome import XuexiChrome 7 | 8 | 9 | def scan_article(browser: XuexiChrome): 10 | article_path = 'data/articles.json' 11 | with open(article_path, 'r', encoding='utf-8') as f: 12 | articles = f.read() 13 | # print(articles) 14 | articles = loads(articles) 15 | while True: 16 | rand_index = randint(0, len(articles) - 1) 17 | if articles[rand_index]['type'] != 'tuwen': 18 | del articles[rand_index] 19 | continue 20 | else: 21 | break 22 | url = articles[rand_index]['url'] 23 | browser.xuexi_get('https://www.xuexi.cn/d184e7597cc0da16f5d9f182907f1200/9a3668c13f6e303932b5e0e100fc248b.html') 24 | browser.xuexi_get(url) 25 | 26 | # 看文章随机70-75秒 27 | total_time = randint(70, 75) 28 | print('--> 正在浏览:《' + articles[rand_index]['title'] + '》') 29 | with Progress() as progress: 30 | task = progress.add_task("--> [cyan]浏览进度:", total=total_time) 31 | while not progress.finished: 32 | browser.execute_script( 33 | 'window.scrollBy(' + str(randint(2, 9)) + ',' + str(randint(15, 31)) + ')') 34 | sleep_time = round(uniform(1, 5), 2) 35 | progress.update(task, advance=sleep_time) 36 | sleep(sleep_time) 37 | 38 | print() 39 | del articles[rand_index] 40 | with open(article_path, 'w', encoding='utf-8') as f: 41 | f.write(dumps(articles, ensure_ascii=False, indent=4)) 42 | 43 | -------------------------------------------------------------------------------- /getData/dataTimeOperation.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | from time import localtime, strptime, strftime, time 3 | from datetime import datetime 4 | from json import loads, dumps 5 | from pathlib import Path 6 | 7 | 8 | def get_diff(date_str): 9 | """ 10 | 获取两个日期之差 11 | :param date_str: 日期字符串 12 | :return: 差值 13 | """ 14 | now_time = localtime(time()) 15 | compare_time = strptime(date_str, "%Y-%m-%d") 16 | date1 = datetime(compare_time[0], compare_time[1], compare_time[2]) 17 | date2 = datetime(now_time[0], now_time[1], now_time[2]) 18 | diff_days = (date2 - date1).days 19 | return diff_days 20 | 21 | 22 | def is_get_data(file_type): 23 | data_path = './data/lastTime.json' 24 | if not Path(data_path).is_file(): 25 | with open(data_path, 'w', encoding='utf-8') as f: 26 | data_dict = { 27 | 'articles': '2020-01-01', 28 | 'videos': '2020-01-01' 29 | } 30 | f.write(dumps(data_dict, ensure_ascii=False, indent=4)) 31 | return True 32 | else: 33 | with open(data_path, 'r', encoding='utf-8') as f: 34 | last_time = loads(f.read()) 35 | diff_days = get_diff(last_time[file_type]) 36 | return diff_days > 30 37 | 38 | 39 | def set_time(file_type): 40 | data_path = './data/lastTime.json' 41 | with open(data_path, 'r', encoding='utf-8') as f: 42 | data_dict = loads(f.read()) 43 | data_dict[file_type] = strftime("%Y-%m-%d", localtime()) 44 | with open(data_path, 'w', encoding='utf-8') as f: 45 | f.write(dumps(data_dict, ensure_ascii=False, indent=4)) 46 | 47 | 48 | if __name__ == '__main__': 49 | print(get_diff('2020-12-1')) 50 | is_get_data('articles') 51 | -------------------------------------------------------------------------------- /operation/watch_video.py: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | from json import loads, dumps 3 | from time import sleep 4 | from random import randint, uniform 5 | from rich.progress import Progress 6 | from selenium.webdriver.common.by import By 7 | from custom.xuexi_chrome import XuexiChrome 8 | 9 | 10 | def watch_video(browser: XuexiChrome): 11 | video_path = 'data/videos.json' 12 | with open(video_path, 'r', encoding='utf-8') as f: 13 | videos = f.read() 14 | # print(videos) 15 | videos = loads(videos) 16 | while True: 17 | rand_index = randint(0, len(videos) - 1) 18 | if videos[rand_index]['type'] != 'shipin': 19 | del videos[rand_index] 20 | continue 21 | else: 22 | break 23 | 24 | url = videos[rand_index]['url'] 25 | browser.xuexi_get('https://www.xuexi.cn/0809b8b6ab8a81a4f55ce9cbefa16eff/ae60b027cb83715fd0eeb7bb2527e88b.html') 26 | browser.xuexi_get('https://www.xuexi.cn/4426aa87b0b64ac671c96379a3a8bd26/db086044562a57b441c24f2af1c8e101.html#t1jk1cdl7l-5') 27 | browser.xuexi_get(url) 28 | video = browser.find_element(by=By.TAG_NAME, value='video') 29 | start = browser.find_element(by=By.CLASS_NAME, value='outter') 30 | sleep(round(uniform(1, 3), 2)) 31 | browser.execute_script('arguments[0].scrollIntoView();', video) 32 | try: 33 | start.click() 34 | except BaseException: 35 | pass 36 | 37 | # 看视频随机70-75秒 38 | total_time = randint(70, 75) 39 | print('--> 正在观看:《' + videos[rand_index]['title'] + '》') 40 | with Progress() as progress: 41 | task = progress.add_task("--> [red]观看进度:", total=total_time) 42 | while not progress.finished: 43 | sleep_time = round(uniform(1, 3), 2) 44 | progress.update(task, advance=sleep_time) 45 | sleep(sleep_time) 46 | 47 | print() 48 | 49 | del videos[rand_index] 50 | with open(video_path, 'w', encoding='utf-8') as f: 51 | f.write(dumps(videos, ensure_ascii=False, indent=4)) 52 | 53 | 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | # 项目结构树
84 |
85 | ```text
86 | +--custom # 自定义webdriver模块
87 | | +--xuexi_chrome.py
88 | | +--__init__.py
89 | +--data # 程序运行所需数据文件及配置文件
90 | | +--articles.json
91 | | +--lastTime.json
92 | | +--settings.json
93 | | +--videos.json
94 | +--getData # 数据获取模块
95 | | +--dataTimeOperation.py
96 | | +--get_article.py
97 | | +--get_video.py
98 | | +--version.py
99 | | +--__init__.py
100 | +--operation # 程序核心模块
101 | | +--check_version.py
102 | | +--exam.py
103 | | +--get_chromedriver.py
104 | | +--scan_article.py
105 | | +--watch_video.py
106 | | +--__init__.py
107 | +--userOperation # 用户相关模块
108 | | +--check.py
109 | | +--login.py
110 | | +--logout.py
111 | | +--__init__.py
112 | +--xuexi.py # 主程序入口
113 | +--__init__.py
114 | ```
115 |
116 | ## License
117 |
118 | [MIT](https://github.com/PRaichu/xxqg/blob/master/LICENSE)
119 |
120 | Copyright (c) 2020-present PRaichu
--------------------------------------------------------------------------------
/operation/get_chromedriver.py:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | import re
3 | from requests import get
4 | from re import compile
5 | from subprocess import Popen, PIPE, call
6 | from traceback import format_exc
7 | from zipfile import ZipFile
8 | import winreg
9 | from json import loads
10 |
11 |
12 | def do(program_path):
13 | """
14 | 检测并更新ChromeDriver
15 | :param program_path: ChromeDriver路径(文件夹路径)
16 | :return: 执行结果 True:执行成功,False:执行失败
17 | """
18 | settings_path = 'data/settings.json'
19 | with open(settings_path, 'r', encoding='utf-8') as f:
20 | settings = f.read()
21 | settings = loads(settings)
22 | if settings['自动更新ChromeDriver'] != "true":
23 | return True
24 | try:
25 | url = 'https://registry.npmmirror.com/-/binary/chromedriver/'
26 | chrome_version = get_chrome_version() # 当前Chrome版本号(前三位)
27 | version = get_version(program_path) # 当前ChromeDriver版本号(前三位)
28 | if chrome_version != version:
29 | print('--> 当前ChromeDriver版本号和Chrome浏览器版本号不一致,准备进行更新')
30 | latest_version = get_download_version(chrome_version)
31 | download_url = url + latest_version + '/chromedriver_win32.zip' # 拼接下载链接
32 | download_chromedriver(download_url)
33 | unzip_file(program_path)
34 | print('--> ChromeDriver更新成功\n')
35 | return True
36 | except:
37 | print(str(format_exc()))
38 | print('--> 程序异常,请确保你的chrome浏览器是最新版本,然后重启脚本')
39 | call('pause', shell=True)
40 | return False
41 |
42 |
43 | def get_download_version(current_version):
44 | """
45 | 根据本地Chrome版本号获取可下载的ChromeDriver版本号
46 | :param current_version: 当前本地Chrome版本号前三位
47 | :return: 完整版本号
48 | """
49 | google_api_url = 'https://registry.npmmirror.com/-/binary/chromedriver/'
50 | rep = loads(get(google_api_url).content.decode('utf-8'))
51 | version_list = []
52 |
53 | for item in rep:
54 | letter_re = re.compile(r'[A-Za-z]', re.S)
55 | letter_res = re.findall(letter_re, item['name'])
56 | if len(letter_res):
57 | continue
58 | version_list.append(item)
59 |
60 | download_version = version_list[len(version_list) - 1]
61 | for item in version_list:
62 | if compile(r'^[1-9]\d*\.\d*.\d*').findall(item['name'])[0] == current_version:
63 | download_version = item['name'][:-1]
64 | return download_version
65 |
66 |
67 | def download_chromedriver(download_url):
68 | """
69 | 下载chromedriver
70 | :param download_url: 下载链接
71 | """
72 | file = get(download_url)
73 | with open("chromedriver.zip", 'wb') as zip_file: # 保存文件到脚本所在目录
74 | zip_file.write(file.content)
75 | print('--> ChromeDriver下载成功')
76 |
77 |
78 | def get_version(path):
79 | """
80 | 获取当前ChromeDriver版本号前三位
81 | :param path: chromedriver文件夹路径
82 | :return: 版本号前三位
83 | """
84 | import os
85 | version_info = Popen([os.path.join(path, 'chromedriver.exe'), '--version'], shell=True,
86 | stdout=PIPE).stdout.read().decode()
87 | return compile(r'^[1-9]\d*\.\d*.\d*').findall(version_info.split(' ')[1])[0]
88 |
89 |
90 | def unzip_file(path):
91 | """
92 | 解压chromedriver.zip到指定目录
93 | :param path: 解压目录
94 | """
95 | f = ZipFile('chromedriver.zip', 'r')
96 | for file in f.namelist():
97 | f.extract(file, path)
98 | f.close()
99 | print('--> 解压成功')
100 | import os
101 | os.remove('chromedriver.zip')
102 | print('--> 压缩包已删除')
103 |
104 |
105 | def get_chrome_version():
106 | """
107 | 获取当前Chrome浏览器版本号
108 | :return: 版本号前三位
109 | """
110 | version_re = compile(r'^[1-9]\d*\.\d*.\d*')
111 | try:
112 | # 从注册表中获得版本号
113 | key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r'Software\Google\Chrome\BLBeacon')
114 | version, _ = winreg.QueryValueEx(key, 'version')
115 | return version_re.findall(version)[0] # 返回前3位版本号
116 | except WindowsError as e:
117 | print('Chrome版本检查失败:{}'.format(e))
118 |
--------------------------------------------------------------------------------
/userOperation/check.py:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | from json import loads
3 | from enum import Enum
4 | from rich import print
5 | from rich.table import Table
6 | from datetime import datetime
7 | from selenium.webdriver.common.by import By
8 | from custom.xuexi_chrome import XuexiChrome
9 |
10 |
11 | class CheckResType(Enum):
12 | NULL = 0
13 | ARTICLE = 1
14 | VIDEO = 2
15 | ARTICLE_AND_VIDEO = 3
16 | DAILY_EXAM = 4
17 | WEEKLY_EXAM = 5
18 | SPECIAL_EXAM = 6
19 |
20 |
21 | def check_task(browser: XuexiChrome):
22 | """
23 | 检查任务项并返回给主程序
24 | :param browser: browser
25 | :return: CheckResType:任务类型
26 | """
27 | # table = PrettyTable(["每日登录", "选读文章", "视频数量", "视频时长", "每日答题", "每周答题", "专项答题", "今日累计积分", "成长总积分"])
28 | table = Table(show_header=True, header_style="bold black")
29 | table.add_column("每日登录", justify='center')
30 | table.add_column("选读文章", justify='center')
31 | table.add_column("视频数量", justify='center')
32 | table.add_column("视频时长", justify='center')
33 | table.add_column("每日答题", justify='center')
34 | table.add_column("专项答题", justify='center')
35 | table.add_column("每周答题", justify='center')
36 | table.add_column("今日累计积分", justify='center')
37 | table.add_column("成长总积分", justify='center')
38 | table_row = []
39 | settings_path = 'data/settings.json'
40 | with open(settings_path, 'r', encoding='utf-8') as f:
41 | settings = f.read()
42 | settings = loads(settings)
43 |
44 | exam_temp_path = './data/exam_temp.json'
45 | with open(exam_temp_path, 'r', encoding='utf-8') as f:
46 | exam_temp = f.read()
47 | exam_temp = loads(exam_temp)
48 |
49 | res = CheckResType.NULL
50 | browser.xuexi_get('https://www.xuexi.cn/index.html')
51 | browser.xuexi_get('https://pc.xuexi.cn/points/my-points.html')
52 |
53 | # 获取各任务项底部按钮
54 | task_buttons = browser.find_elements(by=By.CLASS_NAME, value='big')
55 |
56 | # 获取各任务项积分
57 | scores = browser.find_elements(by=By.CLASS_NAME, value='my-points-card-text')
58 | for score in scores:
59 | table_row.append(score.text.strip())
60 |
61 | # 今日积分
62 | today_points = browser.find_elements(by=By.CLASS_NAME, value='my-points-points')[1]
63 | table_row.append(today_points.text.strip())
64 | # 总积分
65 | all_points = browser.find_elements(by=By.CLASS_NAME, value='my-points-points')[0]
66 | table_row.append(all_points.text.strip())
67 |
68 | # 打印表格
69 | table.add_row(table_row[0],
70 | table_row[1],
71 | table_row[2],
72 | table_row[3],
73 | table_row[4],
74 | table_row[5],
75 | table_row[6],
76 | table_row[7] + '分',
77 | table_row[8] + '分')
78 | print(table)
79 |
80 | if settings['浏览文章'] == "true" and scores[1].text != '12分/12分':
81 | res = CheckResType.ARTICLE
82 | if settings['观看视频'] == "true" and (scores[2].text != '6分/6分' or scores[3].text != '6分/6分'):
83 | if res == CheckResType.ARTICLE:
84 | res = CheckResType.ARTICLE_AND_VIDEO
85 | else:
86 | res = CheckResType.VIDEO
87 |
88 | # 检查设置文件
89 | if settings['自动答题'] != 'true':
90 | return res
91 |
92 | day_of_week = str(datetime.now().isoweekday())
93 | if settings['每日答题'] == 'true' and res == CheckResType.NULL and task_buttons[4].text != '已完成':
94 | if settings['答题时间设置']['是否启用(关闭则每天都答题)'] != 'true' or (settings['答题时间设置']['是否启用(关闭则每天都答题)'] == 'true' and day_of_week in settings['答题时间设置']['答题类型(数字代表星期几)']['每日答题']):
95 | res = CheckResType.DAILY_EXAM
96 | if exam_temp['SPECIAL_EXAM'] == 'true' and settings['专项答题'] == 'true' and res == CheckResType.NULL and task_buttons[5].text != '已完成':
97 | if settings['答题时间设置']['是否启用(关闭则每天都答题)'] != 'true' or (settings['答题时间设置']['是否启用(关闭则每天都答题)'] == 'true' and day_of_week in settings['答题时间设置']['答题类型(数字代表星期几)']['专项答题']):
98 | res = CheckResType.SPECIAL_EXAM
99 | if exam_temp['WEEKLY_EXAM'] == 'true' and settings['每周答题'] == 'true' and res == CheckResType.NULL and task_buttons[6].text != '已完成':
100 | if settings['答题时间设置']['是否启用(关闭则每天都答题)'] != 'true' or (settings['答题时间设置']['是否启用(关闭则每天都答题)'] == 'true' and day_of_week in settings['答题时间设置']['答题类型(数字代表星期几)']['每周答题']):
101 | res = CheckResType.WEEKLY_EXAM
102 |
103 | return res
104 |
--------------------------------------------------------------------------------
/xuexi.py:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | from json import dumps
3 | from ssl import SSLEOFError
4 | from subprocess import call
5 | from traceback import format_exc
6 | from requests.exceptions import SSLError
7 | from urllib3.exceptions import MaxRetryError
8 | from selenium import webdriver
9 | from random import randint
10 | from custom.xuexi_chrome import XuexiChrome
11 | from getData import get_article, get_video
12 | from getData.version import VERSION
13 | from userOperation import login, check
14 | from operation import scan_article, watch_video, exam, get_chromedriver, check_version
15 |
16 |
17 | def article_or_video():
18 | """
19 | 伪随机(在随机浏览文章或视频的情况下,保证文章或视频不会连续2次以上重复出现),浏览文章或视频
20 | :return: 1(文章)或2(视频)
21 | """
22 | rand = randint(1, 2)
23 | if len(randArr) >= 2 and randArr[len(randArr) - 1] + randArr[len(randArr) - 2] == 2:
24 | rand = 2
25 | elif len(randArr) >= 2 and randArr[len(randArr) - 1] + randArr[len(randArr) - 2] == 4:
26 | rand = 1
27 | randArr.append(rand)
28 | return rand
29 |
30 |
31 | def user_login():
32 | """
33 | 登录,循环执行,直到登录成功
34 | :return:
35 | """
36 | while not login.login(browser):
37 | print('--> 登录超时,正在尝试重新登录')
38 | continue
39 |
40 |
41 | def run():
42 | """
43 | 刷视频,刷题目主要部分
44 | 通过check_task()函数决定应该执行什么任务,并调用相应任务函数
45 | :return: null
46 | """
47 | while True:
48 | check_res = check.check_task(browser)
49 | if check_res == check.CheckResType.NULL:
50 | break
51 | elif check_res == check.CheckResType.ARTICLE:
52 | scan_article.scan_article(browser)
53 | elif check_res == check.CheckResType.VIDEO:
54 | watch_video.watch_video(browser)
55 | elif check_res == check.CheckResType.ARTICLE_AND_VIDEO:
56 | if article_or_video() == 1:
57 | scan_article.scan_article(browser)
58 | else:
59 | watch_video.watch_video(browser)
60 | else:
61 | exam.to_exam(browser, check_res)
62 |
63 |
64 | def finally_run():
65 | """
66 | 程序最后执行的函数,包括打印信息、关闭浏览器等
67 | """
68 | browser.quit()
69 | print(r'''
70 | __/\\\\\\\\\\\\\____/\\\________/\\\__________/\\\\\\\\\\\\__/\\\\\\\\\\\\_____/\\\\\\\\\\\\\\\_
71 | _\/\\\/////////\\\_\///\\\____/\\\/_________/\\\//////////__\/\\\////////\\\__\/\\\///////////__
72 | _\/\\\_______\/\\\___\///\\\/\\\/__________/\\\_____________\/\\\______\//\\\_\/\\\_____________
73 | _\/\\\\\\\\\\\\\\______\///\\\/___________\/\\\____/\\\\\\\_\/\\\_______\/\\\_\/\\\\\\\\\\\_____
74 | _\/\\\/////////\\\_______\/\\\____________\/\\\___\/////\\\_\/\\\_______\/\\\_\/\\\///////______
75 | _\/\\\_______\/\\\_______\/\\\____________\/\\\_______\/\\\_\/\\\_______\/\\\_\/\\\_____________
76 | _\/\\\_______\/\\\_______\/\\\____________\/\\\_______\/\\\_\/\\\_______/\\\__\/\\\_____________
77 | _\/\\\\\\\\\\\\\/________\/\\\____________\//\\\\\\\\\\\\/__\/\\\\\\\\\\\\/___\/\\\_____________
78 | _\/////////////__________\///______________\////////////____\////////////_____\///______________''')
79 |
80 | call('pause', shell=True)
81 |
82 |
83 | if __name__ == "__main__":
84 | try:
85 | from sys import exit
86 | import ctypes
87 | from os import getcwd, remove, path
88 |
89 | ctypes.windll.kernel32.SetConsoleTitleW('xuexi-{}'.format(VERSION))
90 |
91 | try:
92 | check_version.check()
93 | except (SSLEOFError, MaxRetryError, SSLError):
94 | print(str(format_exc()))
95 | print('--> \033[31m网络连接失败,请检查是否开启了VPN或代理软件,如果开启了请关闭后再试\033[0m')
96 | print('--> \033[31m当前版本:{}\033[0m'.format(VERSION))
97 | call('pause', shell=True)
98 | exit(1)
99 |
100 | if not get_chromedriver.do(getcwd()):
101 | exit(1)
102 |
103 | chrome_options = webdriver.ChromeOptions()
104 |
105 | chrome_options.add_experimental_option('useAutomationExtension', False) # 防止检测
106 | chrome_options.add_argument("--mute-audio") # 静音
107 | chrome_options.add_experimental_option('excludeSwitches', ['enable-automation', 'enable-logging']) # 防止检测、禁止打印日志
108 | chrome_options.add_argument('--disable-blink-features=AutomationControlled')
109 | chrome_options.add_argument('--ignore-certificate-errors') # 忽略证书错误
110 | chrome_options.add_argument('--ignore-ssl-errors') # 忽略ssl错误
111 | chrome_options.add_argument('–log-level=3')
112 |
113 | browser = XuexiChrome(path.join(getcwd(), 'chromedriver.exe'), options=chrome_options)
114 | browser.maximize_window()
115 |
116 | exam_temp_Path = './data/exam_temp.json'
117 | except:
118 | print(str(format_exc()))
119 | print('--> \033[31m程序异常,请尝试重启脚本\033[0m')
120 | print('--> \033[31m当前版本:{}\033[0m'.format(VERSION))
121 | call('pause', shell=True)
122 | else:
123 | try:
124 | with open(exam_temp_Path, 'w', encoding='utf-8') as f:
125 | dataDict = {
126 | 'DAILY_EXAM': 'true',
127 | 'WEEKLY_EXAM': 'true',
128 | 'SPECIAL_EXAM': 'true'
129 | }
130 | f.write(dumps(dataDict, ensure_ascii=False, indent=4))
131 |
132 | get_article.get_article()
133 | get_video.get_video()
134 | user_login()
135 | randArr = [] # 存放并用于判断随机值,防止出现连续看文章或者看视频的情况
136 | run()
137 | print('--> 任务全部完成,程序已结束')
138 | except (SSLEOFError, MaxRetryError, SSLError):
139 | print(str(format_exc()))
140 | print('--> \033[31m网络连接失败,请检查是否开启了VPN或代理软件,如果开启了请关闭后再试\033[0m')
141 | print('--> \033[31m当前版本:{}\033[0m'.format(VERSION))
142 | except:
143 | print(str(format_exc()))
144 | print('--> \033[31m程序异常,请尝试重启脚本\033[0m')
145 | print('--> \033[31m当前版本:{}\033[0m'.format(VERSION))
146 | finally:
147 | remove(exam_temp_Path)
148 | finally_run()
149 |
--------------------------------------------------------------------------------
/operation/exam.py:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | from json import loads, dumps
3 | from traceback import format_exc
4 | from selenium.common.exceptions import WebDriverException, NoSuchElementException, UnexpectedAlertPresentException
5 | from time import sleep
6 | from random import uniform
7 | from difflib import SequenceMatcher
8 | from re import findall
9 | from selenium.webdriver.common.by import By
10 | from selenium.webdriver.remote.webelement import WebElement
11 | from custom.xuexi_chrome import XuexiChrome
12 | from userOperation import check
13 |
14 |
15 | def click(browser: XuexiChrome, element: WebElement):
16 | browser.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {
17 | 'source': '''
18 | Object.defineProperty(navigator, 'webdriver', {
19 | get: () => undefined
20 | })
21 | window.alert = function() {
22 | return;
23 | }
24 | '''
25 | })
26 | element.click()
27 |
28 |
29 | def check_exam(browser: XuexiChrome, exam_type):
30 | """
31 | 检查可做的题目,如果本页没有则翻页查找
32 | :param browser: browser
33 | :param exam_type: 题目类型(周、专)
34 | :return: null
35 | """
36 | sleep(round(uniform(1, 2), 2))
37 | while True:
38 | flag = True # 用来记录是否答题,答题则置为False
39 | all_exams = browser.find_elements(by=By.CLASS_NAME, value='ant-btn-primary')
40 | for exam in all_exams:
41 | if exam.text == '开始答题' or exam.text == '继续答题':
42 | browser.execute_script('arguments[0].scrollIntoView();', exam)
43 | sleep(round(uniform(1, 2), 2))
44 | click(browser, exam)
45 | sleep(round(uniform(2, 4), 2))
46 | run_exam(browser)
47 | flag = False
48 | break
49 | if flag: # flag为True则执行翻页
50 | next_page = browser.find_element(by=By.CLASS_NAME, value='ant-pagination-next')
51 | browser.execute_script('arguments[0].scrollIntoView();', next_page)
52 | sleep(round(uniform(1, 2), 2))
53 | if next_page.get_attribute('aria-disabled') == 'true': # 检查翻页按钮是否可点击
54 | exam_type = None
55 | if exam_type == check.CheckResType.WEEKLY_EXAM:
56 | exam_type = 'WEEKLY_EXAM'
57 | print('--> 每周答题:已无可做题目')
58 | elif exam_type == check.CheckResType.SPECIAL_EXAM:
59 | exam_type = 'SPECIAL_EXAM'
60 | print('--> 专项答题:已无可做题目')
61 | # 如果该类型的题目已全部做完,则记录防止再次刷
62 | exam_temp_path = './data/exam_temp.json'
63 | with open(exam_temp_path, 'r', encoding='utf-8') as f:
64 | data_dict = loads(f.read())
65 | data_dict[exam_type] = 'false'
66 | with open(exam_temp_path, 'w', encoding='utf-8') as f:
67 | f.write(dumps(data_dict, ensure_ascii=False, indent=4))
68 | return
69 | click(browser, next_page)
70 | sleep(round(uniform(3, 5), 2))
71 | else:
72 | break
73 |
74 |
75 | def to_exam(browser: XuexiChrome, exam_type: check.CheckResType):
76 | """
77 | 根据参数题目类型进入对应的题目
78 | :param browser: browser
79 | :param exam_type: 题目类型(日、周、专)
80 | :return:
81 | """
82 | browser.xuexi_get('https://www.xuexi.cn/')
83 | browser.xuexi_get('https://pc.xuexi.cn/points/my-points.html')
84 | sleep(round(uniform(1, 2), 2))
85 |
86 | # 获取答题按钮族
87 | exam = browser.find_elements(by=By.CLASS_NAME, value='big')
88 | if exam_type == check.CheckResType.DAILY_EXAM:
89 | daily = exam[4]
90 | browser.execute_script('arguments[0].scrollIntoView();', daily)
91 | sleep(round(uniform(1, 2), 2))
92 | click(browser, daily)
93 | sleep(round(uniform(2, 4), 2))
94 | run_exam(browser)
95 | elif exam_type == check.CheckResType.SPECIAL_EXAM:
96 | special = exam[5]
97 | browser.execute_script('arguments[0].scrollIntoView();', special)
98 | sleep(round(uniform(1, 2), 2))
99 | click(browser, special)
100 | check_exam(browser, exam_type)
101 | elif exam_type == check.CheckResType.WEEKLY_EXAM:
102 | weekly = exam[6]
103 | browser.execute_script('arguments[0].scrollIntoView();', weekly)
104 | sleep(round(uniform(1, 2), 2))
105 | click(browser, weekly)
106 | check_exam(browser, exam_type)
107 |
108 |
109 | def select_all(options):
110 | print('--> 最大概率选项:', end='')
111 | for i in range(len(options)):
112 | print(' ' + options[i].text[0], end='')
113 | print()
114 | for i in range(len(options)):
115 | sleep(round(uniform(0.2, 0.8), 2))
116 | options[i].click()
117 |
118 |
119 | def run_exam(browser: XuexiChrome):
120 | while True:
121 | content = browser.find_element(by=By.CLASS_NAME, value='ant-breadcrumb')
122 | browser.execute_script('arguments[0].scrollIntoView();', content)
123 | sleep(round(uniform(2, 3), 2))
124 | # 题目类型
125 | question_type = browser.find_element(by=By.CLASS_NAME, value='q-header').text
126 | # print(questionType)
127 | # 当前题目的坐标
128 | question_index = int(browser.find_element(by=By.CLASS_NAME, value='big').text)
129 | # 题目总数
130 | question_count = int(findall('/(.*)', browser.find_element(by=By.CLASS_NAME, value='pager').text)[0])
131 | # 确定按钮
132 | ok_btn = browser.find_element(by=By.CLASS_NAME, value='ant-btn-primary')
133 | try:
134 | browser.find_element(by=By.CLASS_NAME, value='answer')
135 | if ok_btn.text == '下一题':
136 | ok_btn.click()
137 | sleep(round(uniform(0.2, 0.8), 2))
138 | continue
139 | except NoSuchElementException:
140 | pass
141 | # 提示按钮
142 | tip_btn = browser.find_element(by=By.CLASS_NAME, value='tips')
143 | print('--> 当前题目进度:' + str(question_index) + '/' + str(question_count))
144 | tip_btn.click()
145 | sleep(round(uniform(0.2, 0.8), 2))
146 | try:
147 | # 获取所有提示内容
148 | tips_content = browser.find_element(by=By.CLASS_NAME, value='line-feed').find_elements(by=By.TAG_NAME, value='font')
149 | sleep(round(uniform(0.2, 0.8), 2))
150 | tip_btn.click()
151 | tips = []
152 | tips.clear()
153 | for tip in tips_content:
154 | tips.append(tip.text)
155 |
156 | if '单选题' in question_type:
157 | # 选择题,获取所有选项
158 | options = browser.find_elements(by=By.CLASS_NAME, value='choosable')
159 | if len(tips) == 0:
160 | sleep(round(uniform(0.2, 0.8), 2))
161 | options[0].click()
162 | else:
163 | ans_dict = {} # 存放每个选项与提示的相似度
164 | for i in range(len(options)):
165 | ans_dict[i] = SequenceMatcher(None, tips[0], options[i].text[3:]).ratio()
166 | ans_dict = sorted(ans_dict.items(), key=lambda x: x[1], reverse=True)
167 | # print(ansDict)
168 | print('--> 最大概率选项: ' + options[ans_dict[0][0]].text[0])
169 | options[ans_dict[0][0]].click()
170 |
171 | sleep(round(uniform(0.2, 0.8), 2))
172 | ok_btn.click()
173 |
174 | elif '多选题' in question_type:
175 | # 选择题,获取所有选项
176 | options = browser.find_elements(by=By.CLASS_NAME, value='choosable')
177 | q_word = browser.find_element(by=By.CLASS_NAME, value='q-body').text
178 | bracket_count = len(findall('()', q_word))
179 | if len(options) == bracket_count:
180 | select_all(options)
181 | else:
182 | if len(tips) == 0:
183 | sleep(round(uniform(0.2, 0.8), 2))
184 | options[0].click()
185 | sleep(round(uniform(0.2, 0.8), 2))
186 | options[1].click()
187 | else:
188 | # 如果选项数量多于提示数量,则匹配出最可能的选项
189 | if len(options) > len(tips):
190 | ans = [] # 存放匹配出的最终结果
191 | for i in range(len(tips)):
192 | ans_dict = {} # 存放每个选项与提示的相似度
193 | for j in range(len(options)):
194 | ans_dict[j] = SequenceMatcher(None, tips[i], options[j].text[3:]).ratio()
195 | # print(ansDict)
196 | ans_dict = sorted(ans_dict.items(), key=lambda x: x[1], reverse=True)
197 | ans.append(ans_dict[0][0])
198 | ans = list(set(ans))
199 | # print(ans)
200 | print('--> 最大概率选项:', end='')
201 | for i in range(len(ans)):
202 | print(' ' + options[ans[i]].text[0], end='')
203 | print()
204 | for i in range(len(ans)):
205 | sleep(round(uniform(0.2, 0.8), 2))
206 | options[ans[i]].click()
207 | # 如果选项数量和提示数量相同或少于提示数量,则全选
208 | else:
209 | select_all(options)
210 |
211 | sleep(round(uniform(0.2, 0.8), 2))
212 | ok_btn.click()
213 |
214 | elif '填空题' in question_type:
215 | # 填空题,获取所有输入框
216 | blanks = browser.find_elements(by=By.CLASS_NAME, value='blank')
217 | tips_i = 0
218 | for i in range(len(blanks)):
219 | sleep(round(uniform(0.2, 0.8), 2))
220 | if len(tips) > tips_i and tips[tips_i].strip() == '':
221 | tips_i += 1
222 | try:
223 | blank_ans = tips[tips_i]
224 | except:
225 | blank_ans = '未找到提示'
226 | print('--> 第{0}空答案可能是: {1}'.format(i + 1, blank_ans))
227 | blanks[i].send_keys(blank_ans)
228 | tips_i += 1
229 |
230 | sleep(round(uniform(0.2, 0.8), 2))
231 | ok_btn.click()
232 | except UnexpectedAlertPresentException:
233 | alert = browser.switch_to.alert
234 | alert.accept()
235 | other_place = browser.find_element(by=By.ID, value='app')
236 | other_place.click()
237 | sleep(round(uniform(0.2, 0.8), 2))
238 | except WebDriverException:
239 | print(str(format_exc()))
240 | print('--> 答题异常,正在重试')
241 | other_place = browser.find_element(by=By.ID, value='app')
242 | other_place.click()
243 | sleep(round(uniform(0.2, 0.8), 2))
244 |
245 | if question_index == question_count:
246 | sleep(round(uniform(0.2, 0.8), 2))
247 | try:
248 | submit = browser.find_element(by=By.CLASS_NAME, value='submit-btn')
249 | submit.click()
250 | browser.implicitly_wait(10)
251 | sleep(round(uniform(2.6, 4.6), 2))
252 | except NoSuchElementException:
253 | submit = browser.find_element(by=By.CLASS_NAME, value='ant-btn-primary')
254 | submit.click()
255 | browser.implicitly_wait(10)
256 | sleep(round(uniform(2.6, 4.6), 2))
257 | except UnexpectedAlertPresentException:
258 | alert = browser.switch_to.alert
259 | alert.accept()
260 | print('--> 答题结束')
261 | break
262 |
--------------------------------------------------------------------------------