def swipe_left(self): # 向右滑动屏幕 self.driver.swipe(self.size['width'] * random.uniform(0.89, 0.98), self.size['height'] * random.uniform(0.75, 0.89), self.size['width'] * random.uniform(0.01, 0.11), self.size['height'] * random.uniform(0.75, 0.89), random.uniform(800, 1200)) logger.debug('向左滑动屏幕')
def swipe_down(self): # 向下滑动屏幕 self.driver.swipe(self.size['width'] * random.uniform(0.55, 0.65), self.size['height'] * random.uniform(0.25, 0.35), self.size['width'] * random.uniform(0.55, 0.65), self.size['height'] * random.uniform(0.65, 0.75), random.uniform(800, 1200)) logger.debug('向下滑动屏幕')
def _submit(self, delay=None): if not delay: delay = random.randint(self.daily_delay_bot, self.daily_delay_top) logger.info(f'随机延时 {delay} 秒...') time.sleep(delay) self.app.safe_click(rules["daily_submit"]) time.sleep(random.randint(1, 3))
def _read(self, num, ssc_count): logger.info(f'预计阅读新闻 {num} 则') while num > 0: # or ssc_count: try: articles = self.app.driver.find_elements_by_xpath( rules['article_list']) except: logger.debug(f'真是遗憾,一屏都没有可点击的新闻') articles = [] for article in articles: title = article.get_attribute("name") if title in self.titles: continue try: pic_num = article.parent.find_element_by_id( "cn.xuexi.android:id/st_feeds_card_mask_pic_num") logger.debug(f'这绝对是摄影集,直接下一篇') continue except: logger.debug(f'这篇文章应该不是摄影集了吧') article.click() num -= 1 logger.info(f'<{num}> 当前篇目 {title}') article_delay = random.randint( self.read_delay, self.read_delay + min(10, self.read_count)) logger.info(f'阅读时间估计 {article_delay} 秒...') while article_delay > 0: if article_delay < 20: delay = article_delay else: delay = random.randint(min(10, article_delay), min(20, article_delay)) logger.debug(f'延时 {delay} 秒...') time.sleep(delay) article_delay -= delay self.app.swipe_up() else: logger.debug(f'完成阅读 {title}') if ssc_count > 0: try: comment_area = self.app.driver.find_element_by_xpath( rules['article_comments']) self._star_share_comments(title) ssc_count -= 1 except: logger.debug('这是一篇关闭评论的文章,收藏分享留言过程出现错误') self.titles.append(title) self.app.safe_back('article -> list') if 0 >= num: break else: self.app.swipe_up()
def _watch(self, video_count=None): g1, t1 = self.app.score["视听学习"] g2, t2 = self.app.score["视听学习时长"] if (g1 == t1) and (g2 == t2): logger.debug(f'视听学习时长积分已达成,无需重复收听') return logger.info("开始浏览百灵视频...") self.app.safe_click(rules['bailing_enter']) self.app.safe_click(rules['bailing_enter']) # 再点一次刷新短视频列表 self.app.safe_click(rules['video_first']) logger.info(f'预计观看视频 {video_count} 则') while video_count: video_count -= 1 video_delay = random.randint( self.view_delay, self.view_delay + min(10, self.video_count)) logger.info(f'正在观看视频 <{video_count}#> {video_delay} 秒进入下一则...') time.sleep(video_delay) self.app.swipe_up() else: logger.info(f'视听学习完毕,正在返回...') self.app.safe_back('video -> bailing') logger.debug(f'正在返回首页...') self.app.safe_click(rules['home_entry'])
def _weekly(self): self.app.safe_click(rules["weekly_entry"]) titles = self.app.wait.until( EC.presence_of_all_elements_located( (By.XPATH, rules["weekly_titles"]))) states = self.app.wait.until( EC.presence_of_all_elements_located( (By.XPATH, rules["weekly_states"]))) # first, last = None, None for title, state in zip(titles, states): # if not first and title.location_in_view["y"]>0: # first = title if self.app.size["height"] - title.location_in_view["y"] < 10: logger.debug(f'屏幕内没有未作答试卷') break logger.debug( f'{title.get_attribute("name")} {state.get_attribute("name")}') if "未作答" == state.get_attribute("name"): logger.info(f'{title.get_attribute("name")}, 开始!') state.click() time.sleep(random.randint(5, 9)) self.daily._dispatch(5) # 这里直接采用每日答题 break self.app.safe_back('weekly report -> weekly list') self.app.safe_back('weekly list -> quiz')
def _search(self, content, options, exclude=''): # 职责 网上搜索 logger.debug(f'搜索 {content} <exclude = {exclude}>') logger.info(f"选项 {options}") content = re.sub(r'[\((]出题单位.*', "", content) if options[-1].startswith("以上") and chr(len(options)+64) not in exclude: logger.info(f'根据经验: {chr(len(options)+64)} 很可能是正确答案') return chr(len(options)+64) # url = quote('https://www.baidu.com/s?wd=' + content, safe=string.printable) url = quote("https://www.sogou.com/web?query=" + content, safe=string.printable) response = requests.get(url, headers=self.headers).text counts = [] for i, option in zip(['A', 'B', 'C', 'D', 'E', 'F'], options): count = response.count(option) counts.append((count, i)) logger.info(f'{i}. {option}: {count} 次') counts = sorted(counts, key=lambda x:x[0], reverse=True) counts = [x for x in counts if x[1] not in exclude] c, i = counts[0] if 0 == c: # 替换了百度引擎为搜狗引擎,结果全为零的机会应该会大幅降低 _, i = random.choice(counts) logger.info(f'搜索结果全0,随机一个 {i}') logger.info(f'根据网络搜索结果: {i} 很可能是正确答案') return i
def _star_share_comments(self, title): logger.debug(f'哟哟,切克闹,收藏转发来一套') if random.random() < 0.33: self._comments_once(title) if random.random() < 0.5: self._star_once() self._share_once() else: self._share_once() self._star_once() else: if random.random() < 0.5: self._star_once() self._share_once() else: self._share_once() self._star_once() self._comments_once(title)
def __init__(self, app): self.app = app try: self.challenge_count = cfg.getint('prefers', 'challenge_count') except: self.challenge_count = random.randint( cfg.getint('prefers', 'challenge_count_min'), cfg.getint('prefers', 'challenge_count_max')) self.challenge_delay_bot = cfg.getint('prefers', 'challenge_delay_min') self.challenge_delay_top = cfg.getint('prefers', 'challenge_delay_max') logger.debug(f'挑战答题: {self.challenge_count}')
def __init__(self, app): self.app = app self.has_bgm = cfg.get("prefers", "radio_switch") if "disable" == self.has_bgm: self.view_time = 1080 else: self.view_time = 360 self.radio_chanel = cfg.get("prefers", "radio_chanel") try: self.video_count = cfg.getint("prefers", "video_count") self.view_delay = 15 except: g, t = self.app.score["视听学习"] if t == g: self.video_count = 0 self.view_delay = random.randint(15, 30) else: self.video_count = random.randint( cfg.getint('prefers', 'video_count_min'), cfg.getint('prefers', 'video_count_max')) self.view_delay = self.view_time // self.video_count + 1 logger.debug(f'视听学习: {self.video_count}')
def _challenge(self): logger.info(f'挑战答题 目标 {self.challenge_count} 题, Go!') while True: result = self._challenge_cycle(self.challenge_count) if 0 >= result: logger.info(f'已成功挑战 {self.challenge_count} 题,正在返回') break else: delay_time = random.randint(1, 3) logger.info( f'本次挑战 {self.challenge_count - result} 题,{delay_time} 秒后再来一组' ) time.sleep(delay_time) continue
def __init__(self, app): self.app = app self.read_time = 361 self.volumn_title = cfg.get("prefers", "article_volumn_title") self.star_share_comments_count = cfg.getint( "prefers", "star_share_comments_count") self.titles = list() try: self.read_count = cfg.getint("prefers", "article_count") self.read_delay = 30 except: self.read_count = random.randint( cfg.getint('prefers', 'article_count_min'), cfg.getint('prefers', 'article_count_max')) self.read_delay = self.read_time // self.read_count + 1 logger.debug(f'阅读文章: {self.read_count}')
def start(): try: if random.random() > 0.5: logger.debug(f'视听学习优先') app.watch() app.music() shuffle([app.read, app.daily, app.challenge, app.weekly]) else: logger.debug(f'视听学习置后') app.music() shuffle([app.read, app.daily, app.challenge, app.weekly]) app.watch() app.logout_or_not() except: print("发生异常") return 1 else: return 0 # sys.exit(0)
def _daily(self, num): self.app.safe_click(rules["daily_entry"]) while num: num -= 1 logger.info(f'每日答题 第 {num}# 组') self._dispatch(self.count_of_each_group) if not self.daily_force: score = self.app.wait.until( EC.presence_of_element_located( (By.XPATH, rules["daily_score"]))).get_attribute("name") # score = self.find_element(rules["daily_score"]).get_attribute("name") try: score = int(score) except: raise TypeError('integer required') self.g += score if self.g == self.t: logger.info(f"今日答题已完成,返回") break if num == 0: logger.debug(f'今日循环结束 <{self.g} / {self.t}>') break delay = random.randint(self.delay_group_bot, self.delay_group_top) logger.info(f'每日答题未完成 <{self.g} / {self.t}> {delay} 秒后再来一组') time.sleep(delay) self.app.safe_click(rules['daily_again']) continue else: logger.debug("应该不会执行本行代码") self.app.safe_back('daily -> quiz') try: back_confirm = self.app.driver.find_element_by_xpath( rules["daily_back_confirm"]) back_confirm.click() except: logger.debug(f"无需点击确认退出")
def _kaleidoscope(self): ''' 本地频道积分 +1 ''' if self.app.back_or_not("本地频道"): return volumns = self.app.wait.until( EC.presence_of_all_elements_located( (By.XPATH, rules['article_volumn']))) volumns[3].click() time.sleep(10) # self.safe_click(rules['article_kaleidoscope']) target = None try: target = self.app.driver.find_element_by_xpath( rules['article_kaleidoscope']) except NoSuchElementException as e: logger.error(f'没有找到城市万花筒入口') if target: target.click() time.sleep(3) delay = random.randint(5, 15) logger.info(f"在本地学习平台驻足 {delay} 秒") time.sleep(delay) self.app.safe_back('学习平台 -> 文章列表')
def _blank(self): contents = self.app.wait.until( EC.presence_of_all_elements_located( (By.XPATH, rules["daily_blank_content"]))) # contents = self.find_elements(rules["daily_blank_content"]) # content = " ".join([x.get_attribute("name") for x in contents]) logger.debug(f'len of blank contents is {len(contents)}') if 1 < len(contents): # 针对作妖的UI布局某一版 content, spaces = "", [] for item in contents: content_text = item.get_attribute("name") if "" != content_text: content += content_text else: length_of_spaces = len( item.find_elements(By.CLASS_NAME, "android.view.View")) - 1 spaces.append(length_of_spaces) content += " " * (length_of_spaces) else: # 针对作妖的UI布局某一版 contents = self.app.wait.until( EC.presence_of_all_elements_located( (By.XPATH, rules["daily_blank_container"]))) content, spaces, _spaces = "", [], 0 for item in contents: content_text = item.get_attribute("name") if "" != content_text: content += content_text if _spaces: spaces.append(_spaces) _spaces = 0 else: content += " " _spaces += 1 else: # for...else... # 如果填空处在最后,需要加一个判断 if _spaces: spaces.append(_spaces) logger.debug( f'[填空题] {content} [{" ".join([str(x) for x in spaces])}]') logger.debug(f'空格数 {spaces}') blank_edits = self.app.wait.until( EC.presence_of_all_elements_located( (By.XPATH, rules["daily_blank_edits"]))) # blank_edits = self.find_elements(rules["daily_blank_edits"]) length_of_edits = len(blank_edits) logger.info(f'填空题 {content}') answer = self._verify("填空题", content, []) # if not answer: words = (''.join( random.sample(string.ascii_letters + string.digits, 8)) for i in range(length_of_edits)) else: words = answer.split(" ") logger.debug(f'提交答案 {words}') for k, v in zip(blank_edits, words): k.send_keys(v) time.sleep(1) self._submit() try: wrong_or_not = self.app.driver.find_element_by_xpath( rules["daily_wrong_or_not"]) right_answer = self.app.driver.find_element_by_xpath( rules["daily_answer"]).get_attribute("name") answer = re.sub(r'正确答案: ', '', right_answer) logger.info(f"答案 {answer}") notes = self.app.driver.find_element_by_xpath( rules["daily_notes"]).get_attribute("name") logger.debug(f"解析 {notes}") self._submit(2) if 1 == length_of_edits: localmodel.update_bank('挑战题', content, [""], answer, '', notes) else: logger.error("多位置的填空题待验证正确性") localmodel.update_bank( '填空题', content, [""], self._blank_answer_divide(answer, spaces), '', notes) except: logger.debug("填空题回答正确")
def shuffle(funcs): random.shuffle(funcs) for func in funcs: func() time.sleep(5)
def _challenge_cycle(self, num): self.app.safe_click(rules['challenge_entry']) offset = 0 # 自动答错的偏移开关 while num > -1: print('') print('') content = self.app.wait.until( EC.presence_of_element_located( (By.XPATH, rules['challenge_content']))).get_attribute("name") # content = self.find_element(rules["challenge_content"]).get_attribute("name") option_elements = self.app.wait.until( EC.presence_of_all_elements_located( (By.XPATH, rules['challenge_options']))) # option_elements = self.find_elements(rules['challenge_options']) options = [x.get_attribute("name") for x in option_elements] length_of_options = len(options) logger.info(f'<{num}> {content}') answer = self.challenge_verify(category='挑战题', content=content, options=options) delay_time = random.randint(self.challenge_delay_bot, self.challenge_delay_top) if 0 == num: offset = random.randint(1, length_of_options - 1) # randint居然包含上限值,坑爹!!! logger.info(f'已完成指定题量,设置提交选项偏移 -{offset}') logger.info( f'随机延时 {delay_time} 秒提交答案: {chr((ord(answer)-65-offset+length_of_options)%length_of_options+65)}' ) else: logger.info(f'随机延时 {delay_time} 秒提交答案: {answer}') time.sleep(delay_time) # 利用python切片的特性,即使索引值为-offset,可以正确取值 option_elements[ord(answer) - 65 - offset].click() try: time.sleep(5) wrong = None wrong = self.app.driver.find_element_by_xpath( rules["challenge_over"]) except: logger.info(f'恭喜本题回答正确') if wrong is None: num -= 1 localmodel.update_bank('挑战题', content, options, answer, '', '') else: logger.info(f'很遗憾本题回答错误') if num > 0: localmodel.update_bank('挑战题', content, options, '', answer, '') logger.debug("点击结束本局") wrong.click() # 直接结束本局 time.sleep(5) break else: logger.debug("通过选项偏移,应该不会打印这句话,除非碰巧答案有误") logger.debug("那么也好,延时30秒后结束挑战") time.sleep(30) self.app.safe_back('challenge -> share_page') # 发现部分模拟器返回无效 # 更新后挑战答题需要增加一次返回 time.sleep(5) self.app.safe_back('share_page -> quiz') # 发现部分模拟器返回无效 return num