def get_cookie_from_network(self, chat_id=None): print("正在打开二维码登陆界面,请稍后") self.web_log('正在打开二维码登陆界面,请稍后') self.driver.get("https://pc.xuexi.cn/points/login.html") try: remover = WebDriverWait(self.driver, 30, 0.2).until( lambda driver: driver.find_element_by_class_name("redflagbox")) except exceptions.TimeoutException: print("网络缓慢,请重试") else: self.driver.execute_script('arguments[0].remove()', remover) try: remover = WebDriverWait( self.driver, 30, 0.2).until(lambda driver: driver.find_element_by_class_name( "layout-header")) except exceptions.TimeoutException: print("当前网络缓慢...") else: self.driver.execute_script('arguments[0].remove()', remover) try: remover = WebDriverWait( self.driver, 30, 0.2).until(lambda driver: driver.find_element_by_class_name( "layout-footer")) except exceptions.TimeoutException: print("当前网络缓慢...") else: self.driver.execute_script('arguments[0].remove()', remover) #修改了适配新版本的二维码的滚动位置 self.driver.execute_script( 'window.scrollTo(document.body.scrollWidth/2 - 200 , 400)') qrurl = '' qcbase64 = '' # 取出iframe中二维码,并发往钉钉 if gl.nohead == True or cfg_get("addition.SendLoginQRcode", 0) == 1: print("二维码将发往机器人...\n" + "=" * 60) qrurl, qcbase64 = self.sendmsg(chat_id) # 扫码登录后删除二维码和登录链接 准备 web_qr_url = web_db.session.query(WebQrUrl).filter_by( url=qcbase64).first() web_msg = web_db.session.query(WebMessage).filter_by( text=qrurl).first() # print(' ----------------------------------------------------------------') # print(web_qr_url) # print(' ----------------------------------------------------------------') # print(web_msg) # print(web_db.session.query(WebMessage).all()) # try: # # 取出iframe中二维码,并发往方糖,拿到的base64没办法直接发钉钉,所以发方糖 # if gl.nohead==True or cfg["addition"]["SendLoginQRcode"] == 1 : # print("二维码将发往方糖机器人...\n" + "=" * 60) # self.toFangTang() # except Exception as e: # print("未检测到SendLoginQRcode配置,请手动扫描二维码登陆..."+e) try: # 获取二维码图片 # 这一块等待测试完毕再加入代码 # self.driver.switch_to.frame("ddlogin-iframe") # source = self.driver.page_source # picc = re.search( # "(data:image/png;base64,)(.*)(\"></div><div data-v-be4de7b6)", source).group(2) # pic = base64.b64decode(picc) # 微信发送图片到手机,以便扫码(此配置项暂未应用至代码。结合 default_template.conf 修改) # wx = WeChat() # media_id = wx.get_media_url(pic) # wx.send_image(media_id) # WebDriverWait(self.driver, 270).until(EC.title_is(u"我的学习")) WebDriverWait(self.driver, 270).until(title_of_login()) cookies = self.get_cookies() user.save_cookies(cookies) # 扫码登录后删除二维码和登录链接 # print('扫码登录后删除二维码和登录链接 {} - {}'.format(web_msg, web_qr_url)) self.web_log('扫码登录后删除二维码和登录链接') web_qr_url and web_db.session.delete(web_qr_url) web_msg and web_db.session.delete(web_msg) web_db.session.commit() return cookies except Exception as e: print("扫描二维码超时... 错误信息:" + str(e)) self.web_log("扫描二维码超时... 错误信息:" + str(e)) if (gl.islooplogin == True): print("循环模式开启,即将重新获取二维码") self.web_log("循环模式开启,即将重新获取二维码") time.sleep(3) return self.get_cookie_from_network() self.quit() if str(e).find("check_hostname") > -1 and str(e).find( "server_hostname") > -1: print("针对“check_hostname requires server_hostname”问题:") print("您的网络连接存在问题,请检查您与xuexi.cn的网络连接并关闭“某些”软件") self.web_log("针对“check_hostname requires server_hostname”问题:") self.web_log("您的网络连接存在问题,请检查您与xuexi.cn的网络连接并关闭“某些”软件") auto.prompt("按回车键退出程序. ") exit()
def __init__(self, noimg=True, nohead=True): self.web = WebHandler() nohead = gl.nohead mydriver_log = '' try: # ==================== 设置options ==================== self.options = Options() if noimg: self.options.add_argument('blink-settings=imagesEnabled=true' ) # 不加载图片, 提升速度,但无法显示二维码 if nohead: self.options.add_argument('--headless') self.options.set_capability('unhandledPromptBehavior', 'accept') self.options.add_argument("--window-size=1920,1050") else: self.options.add_argument('--window-size=750,450') # self.options.add_argument('--window-size=400,500') # self.options.add_argument('--window-size=900,800') # self.options.add_argument("--window-size=1920,1050") self.options.add_argument('--disable-dev-shm-usage') self.options.add_argument( '--disable-software-rasterizer') # 解决GL报错问题 self.options.add_argument('--disable-extensions') self.options.add_argument('--disable-gpu') self.options.add_argument('--no-sandbox') self.options.add_argument('--mute-audio') # 关闭声音 self.options.add_argument('--window-position=700,0') self.options.add_argument('--log-level=3') self.options.add_argument('--user-agent={}'.format( user_agent.getheaders())) self.options.add_experimental_option( 'excludeSwitches', ['enable-automation']) # 绕过js检测 # 在chrome79版本之后,上面的实验选项已经不能屏蔽webdriver特征了 # 屏蔽webdriver特征 self.options.add_argument("--disable-blink-features") self.options.add_argument( "--disable-blink-features=AutomationControlled") self.webdriver = webdriver # ==================== 寻找 chrome ==================== if os.path.exists("./chrome/chrome.exe"): # win self.options.binary_location = "./chrome/chrome.exe" mydriver_log = '可找到 "./chrome/chrome.exe"' elif os.path.exists("/opt/google/chrome/chrome"): # linux self.options.binary_location = "/opt/google/chrome/chrome" mydriver_log = '可找到 "/opt/google/chrome/chrome"' # ==================== 寻找 chromedriver ==================== chromedriver_paths = [ "./chrome/chromedriver.exe", # win "./chromedriver", # linux "/usr/bin/chromedriver", # linux用户安装 # raspberry linux (需要包安装chromedriver) "/usr/lib64/chromium-browser/chromedriver", # raspberry linux (需要包安装chromedriver) "/usr/lib/chromium-browser/chromedriver", "/usr/local/bin/chromedriver", # linux 包安装chromedriver ] have_find = False for one_path in chromedriver_paths: if os.path.exists(one_path): self.driver = self.webdriver.Chrome( executable_path=one_path, chrome_options=self.options) mydriver_log = mydriver_log + '\r\n可找到 "' + one_path + '"' have_find = True break if not have_find: self.driver = self.webdriver.Chrome( chrome_options=self.options) mydriver_log = mydriver_log + '\r\n未找到chromedriver,使用默认方法。' except: print("=" * 60) print(" Chrome 浏览器初始化失败。信息:") print(mydriver_log) print('您可以检查下:') print( "1. 是否存在./chrome/chromedriver.exe 或 PATH 中是否存在 chromedriver.exe" ) print( "2. 浏览器地址栏输入 chrome://version 看到的chrome版本 和 运行 chromedriver.exe 显示的版本整数部分是否相同" ) print( "针对上述问题,请在 http://npm.taobao.org/mirrors/chromedriver 下载对应版本程序并放在合适的位置" ) print("3. 如不是以上问题,请提issue,附上报错信息和您的环境信息") print("=" * 60) auto.prompt("按回车键继续......") raise
def answer_question(quiz_type, cookies, scores, score_all, quiz_xpath, category_xpath, uid=None, driver_default=None): quiz_zh_CN = {"daily": "每日", "weekly": "每周", "zhuanxiang": "专项"} if (quiz_type not in ["daily", "weekly", "zhuanxiang"]): print("quiz_type 错误。收到的quiz_type:" + quiz_type) exit(0) if uid is None: uid = user.get_userId(cookies) if scores[quiz_type] < score_all: # 还没有满分,需要答题 if driver_default is None: driver_ans = Mydriver(nohead=False) ##### driver_ans = Mydriver(nohead=True) else: driver_ans = driver_default driver_daily = driver_ans driver_weekly = driver_ans driver_zhuanxiang = driver_ans driver_ans.driver.maximize_window() print('请保持窗口最大化\n' * 3) driver_ans.get_url("https://www.xuexi.cn/notFound.html") driver_ans.set_cookies(cookies) pass_count = 0 #最大值,用于nohead模式退出 max_count = 0 if scores[quiz_type] < score_all: letters = list("ABCDEFGHIJKLMN") driver_ans.get_url('https://pc.xuexi.cn/points/my-points.html') while driver_ans.title_is(u"我的积分"): # 页面title为积分则一直循环 time.sleep(1) # 等待页面刷新提示 refresh_buttons = driver_ans.driver.find_elements_by_css_selector( ".ant-modal-wrap .ant-btn:not(.ant-btn-primary)") if len(refresh_buttons) > 0: # refresh_buttons[0].click() driver_ans.click_xpath(quiz_xpath) # 点击各个题目的去答题按钮 time.sleep(1) if quiz_type != "daily": # 如果是每日答题就不用找available了 # 此处修改是因为页面可能刷新后导致的查找元素button 丢失从而引发异常重新此处用可以重新查找来解决 try: to_click = find_available_quiz(quiz_type, driver_ans, uid) except Exception as e: to_click = find_available_quiz(quiz_type, driver_ans, uid) if to_click is not None: to_click.click() time.sleep(0.5) else: print(color.blue("无题可答。即将跳过。")) if driver_default is None: try: driver_ans.quit() except Exception as e: print('driver_ans 在 answer_question 退出时出了一点小问题...') else: pass #其他函数传入函数的driver,不自动退出 while scores[quiz_type] < score_all: try: category = driver_ans.xpath_getText( category_xpath) #获取题目类型 get_attribute("name") except Exception as e: print('查找题目类型...查找元素失败!') break print(category) if quiz_type == "daily": ans_results = driver_ans.driver.find_elements_by_css_selector( ".practice-result .infos .info") if (len(ans_results) != 0): #已经找到答题结果页面 print(ans_results[0].get_attribute("innerHTML")) print(ans_results[0].text) print(ans_results[2].get_attribute("innerHTML")) print(ans_results[2].text) time.sleep(1) # exit(2) break log_daily("\n====================") log_daily(log_timestamp()) log_daily("【" + category + "】") log_daily("【题干】") q_body = driver_ans.driver.find_element_by_css_selector( ".q-body") q_html = q_body.get_attribute('innerHTML') q_text = q_body.text print(q_text) log_daily(q_html) tips, tip_full_text = driver_ans._view_tips() if quiz_type == "daily": log_daily("【提示信息】") log_daily(str(tips) + "\n" + tip_full_text) if not tips: print("本题没有提示") max_count += 1 pass_count += 1 if max_count >= 100 and globalvar.nohead == True: print("略过次数已经超过100次,且出于Nohead模式,退出答题") break if pass_count >= 5: ##### print( "暂时略过已达到 5 次,【 建议您将此题目的题干、提示、选项信息提交到github问题收集issue:https://github.com/TechXueXi/TechXueXi/issues/29 】" ) auto.prompt("等待用户手动答题...完成后请在此按回车...") pass_count = 0 if quiz_type == "daily": ##### log_daily("!!!!!本题没有找到提示,暂时略过!!!!!") auto.prompt("等待用户手动答题...完成后请在此按回车...") time.sleep(1) if "填空题" in category: print('没有找到提示,暂时略过') ##### print('使用默认答案 好 ') #如无填空答案,使用默认答案 好 字 by Sean ##### tips = ['好'] continue ##### elif "多选题" in category: print('没有找到提示,暂时略过') ##### print('使用默认答案 全选') #by Sean continue ##### elif "单选题" in category: print('没有找到提示,暂时略过') # 如无单选答案,使用默认答案 ##### print('使用默认答案 B') #by Sean continue ##### # return driver_daily._search(driver_daily.content, driver_daily.options, driver_daily.excludes) else: print("题目类型非法") if quiz_type == "daily": log_daily("!!!!!无提示,题目类型非法!!!!!") break else: if "填空题" in category: answer = tips if quiz_type != "zhuanxiang": driver_ans.fill_in_blank(answer) else: driver_ans.zhuanxiang_fill_in_blank(answer) elif "多选题" in category: if quiz_type == "daily": options = driver_daily.radio_get_options() ##### len_option = len(options) log_daily("【多选题选项】") log_daily(str(options)) radio_in_tips, radio_out_tips = "", "" for letter, option in zip(letters, options): for tip in tips: if tip in option: # print(f'{option} in tips') if letter not in radio_in_tips: radio_in_tips += letter radio_out_tips = [ letter for letter, option in zip(letters, options) if (letter not in radio_in_tips) ] print('包含提示的选项 ', radio_in_tips, ',不包含提示的选项 ', radio_out_tips) log_daily('包含提示的选项 ' + str(radio_in_tips) + ',不包含提示的选项 ' + str(radio_out_tips)) if len( radio_in_tips ) > 1: # and radio_in_tips not in driver_daily.excludes: print('根据提示', radio_in_tips) driver_daily.radio_check(radio_in_tips) elif len( radio_out_tips ) > 1: # and radio_out_tips not in excludes print('根据提示', radio_out_tips) driver_daily.radio_check(radio_out_tips) # return driver_daily._search(content, options, excludes) else: print('无法根据提示判断,请自行答题……') log_daily("!!!!!无法根据提示判断,请自行答题……!!!!!") ##### print('将使用默认全选答题') #by Sean ##### len_option = len(options) ##### radio_in_tips = letters[:len_option] ##### driver_daily.radio_check(radio_in_tips) auto.prompt("等待用户手动答题...完成后请在此按回车...") elif quiz_type == "weekly": options = driver_weekly.radio_get_options() radio_in_tips, radio_out_tips = "", "" for letter, option in zip(letters, options): for tip in tips: if tip in option: # print(f'{option} in tips') if letter not in radio_in_tips: radio_in_tips += letter radio_out_tips = [ letter for letter, option in zip(letters, options) if (letter not in radio_in_tips) ] print('含 ', radio_in_tips, '不含', radio_out_tips) if len( radio_in_tips ) > 1: # and radio_in_tips not in driver_weekly.excludes: print('根据提示', radio_in_tips) driver_weekly.radio_check(radio_in_tips) elif len( radio_out_tips ) > 1: # and radio_out_tips not in excludes print('根据提示', radio_out_tips) driver_weekly.radio_check(radio_out_tips) # return driver_weekly._search(content, options, excludes) else: print('无法根据提示判断,请自行准备搜索……') ##### print('将使用默认全选答题') #by Sean ##### len_option = len(options) ##### radio_in_tips = letters[:len_option] ##### driver_weekly.radio_check(radio_in_tips) auto.prompt("等待用户手动答题...完成后请在此按回车...") elif quiz_type == "zhuanxiang": options = driver_zhuanxiang.radio_get_options() radio_in_tips, radio_out_tips = "", "" for letter, option in zip(letters, options): for tip in tips: if tip in option: # print(f'{option} in tips') if letter not in radio_in_tips: radio_in_tips += letter radio_out_tips = [ letter for letter, option in zip(letters, options) if (letter not in radio_in_tips) ] print('含 ', radio_in_tips, '不含', radio_out_tips) if len( radio_in_tips ) > 1: # and radio_in_tips not in driver_zhuanxiang.excludes: print('根据提示', radio_in_tips) driver_zhuanxiang.radio_check(radio_in_tips) elif len( radio_out_tips ) > 1: # and radio_out_tips not in excludes print('根据提示', radio_out_tips) driver_zhuanxiang.radio_check(radio_out_tips) # return driver_zhuanxiang._search(content, options, excludes) else: print('无法根据提示判断,请自行准备搜索……') ##### print('将使用默认全选答题') #by Sean ##### len_option = len(options) ##### radio_in_tips = letters[:len_option] ##### driver_zhuanxiang.radio_check(radio_in_tips) auto.prompt("等待用户手动答题...完成后请在此按回车...") elif "单选题" in category: if quiz_type == "daily": options = driver_daily.radio_get_options() log_daily("【单选题选项】") log_daily(str(options)) if '因此本题选' in tips: #提示类型1 check = [x for x in letters if x in tips] log_daily("根据提示类型1,选择答案:" + str(check)) driver_daily.radio_check(check) else: radio_in_tips, radio_out_tips = "", "" ''' option_elements = driver_daily.wait.until(driver_daily.EC.presence_of_all_elements_located( (driver_daily.By.XPATH, '//*[@id="app"]/div/div[2]/div/div[4]/div[1]'))) # option_elements = self.find_elements(rules['challenge_options']) options = [x.get_attribute("name") for x in option_elements]''' for letter, option in zip(letters, options): for tip in tips: if tip in option: # print(f'{option} in tips') if letter not in radio_in_tips: radio_in_tips += letter else: # print(f'{option} out tips') if letter not in radio_out_tips: radio_out_tips += letter print('包含提示的选项 ', radio_in_tips, ',不包含提示的选项 ', radio_out_tips) log_daily('包含提示的选项 ' + str(radio_in_tips) + ',不包含提示的选项 ' + str(radio_out_tips)) if 1 == len( radio_in_tips ): # and radio_in_tips not in driver_daily.excludes: print('根据提示', radio_in_tips) driver_daily.radio_check(radio_in_tips) elif 1 == len( radio_out_tips ): # and radio_out_tips not in excludes print('根据提示', radio_out_tips) driver_daily.radio_check(radio_out_tips) # return driver_daily._search(content, options, excludes) else: print('无法根据提示判断,请自行答题……') log_daily("!!!!!无法根据提示判断,请自行答题……!!!!!") ##### print('将使用默认选 B') #by Sean ##### radio_in_tips = "B" ##### driver_daily.radio_check(radio_in_tips) auto.prompt("等待用户手动答题...完成后请在此按回车...") elif quiz_type == "weekly": options = driver_weekly.radio_get_options() if '因此本题选' in tips: check = [x for x in letters if x in tips] driver_weekly.radio_check(check) else: radio_in_tips, radio_out_tips = "", "" ''' option_elements = driver_weekly.wait.until(driver_weekly.EC.presence_of_all_elements_located( (driver_weekly.By.XPATH, '//*[@id="app"]/div/div[2]/div/div[4]/div[1]'))) # option_elements = self.find_elements(rules['challenge_options']) options = [x.get_attribute("name") for x in option_elements]''' for letter, option in zip(letters, options): for tip in tips: if tip in option: # print(f'{option} in tips') if letter not in radio_in_tips: radio_in_tips += letter else: # print(f'{option} out tips') if letter not in radio_out_tips: radio_out_tips += letter print('含 ', radio_in_tips, '不含', radio_out_tips) if 1 == len( radio_in_tips ): # and radio_in_tips not in driver_weekly.excludes: print('根据提示', radio_in_tips) driver_weekly.radio_check(radio_in_tips) elif 1 == len( radio_out_tips ): # and radio_out_tips not in excludes print('根据提示', radio_out_tips) driver_weekly.radio_check(radio_out_tips) # return driver_weekly._search(content, options, excludes) else: print('无法根据提示判断,请自行准备搜索……') ##### print('将使用默认选 B') #by Sean ##### radio_in_tips = "B" ##### driver_weekly.radio_check(radio_in_tips) auto.prompt("等待用户手动答题...完成后请在此按回车...") elif quiz_type == "zhuanxiang": options = driver_zhuanxiang.radio_get_options() if '因此本题选' in tips: check = [x for x in letters if x in tips] driver_zhuanxiang.radio_check(check) else: radio_in_tips, radio_out_tips = "", "" ''' option_elements = driver_zhuanxiang.wait.until(driver_zhuanxiang.EC.presence_of_all_elements_located( (driver_zhuanxiang.By.XPATH, '//*[@id="app"]/div/div[2]/div/div[4]/div[1]'))) # option_elements = self.find_elements(rules['challenge_options']) options = [x.get_attribute("name") for x in option_elements]''' for letter, option in zip(letters, options): for tip in tips: if tip in option: # print(f'{option} in tips') if letter not in radio_in_tips: radio_in_tips += letter else: # print(f'{option} out tips') if letter not in radio_out_tips: radio_out_tips += letter print('含 ', radio_in_tips, '不含', radio_out_tips) if 1 == len( radio_in_tips ): # and radio_in_tips not in driver_zhuanxiang.excludes: print('根据提示', radio_in_tips) driver_zhuanxiang.radio_check( radio_in_tips) elif 1 == len( radio_out_tips ): # and radio_out_tips not in excludes print('根据提示', radio_out_tips) driver_zhuanxiang.radio_check( radio_out_tips) # return driver_zhuanxiang._search(content, options, excludes) else: print('无法根据提示判断,请自行准备搜索……') ##### print('将使用默认选 B') #by Sean ##### radio_in_tips = "B" ##### driver_zhuanxiang.radio_check(radio_in_tips) auto.prompt("等待用户手动答题...完成后请在此按回车...") else: print("题目类型非法") if quiz_type == "daily": log_daily("!!!!!有提示,但题目类型非法!!!!!") break time.sleep(1) total, scores = show_score(cookies) if scores[quiz_type] >= score_all: print("检测到" + quiz_zh_CN[quiz_type] + "答题分数已满,退出学 xi ") else: print("!!!!!没拿到满分,请收集日志反馈错误题目!!!!!") auto.prompt("完成后(或懒得弄)请在此按回车...") #log_daily("!!!!!没拿到满分!!!!!") if driver_default == None: try: driver_ans.quit() except Exception as e: print('driver_ans 在 answer_question 退出时出了一点小问题...') else: pass #其他函数传入函数的driver,不自动退出 else: print(quiz_zh_CN[quiz_type] + "答题已满分.")