# mt_spider/monitor.py import threading, time, logging from collections import deque class SpiderMonitor(threading.Thread): def __init__(self, spider_instance): super().__init__(daemon=True) self.spider = spider_instance self.running = True self.pausing = threading.Event() self.last_verification_time = 0 self.verification_count = 0 self.MAX_VERIFICATION_RETRY = 3 self.recent_clicks = deque(maxlen=10) self.logger = logging.getLogger("SpiderMonitor") self.popup_rules = { "simple": [ ('//*[@text="确定"]', "点击确定"), ('//*[@text="允许"]', "点击允许"), ('//*[@text="关闭"]', "点击关闭"), ('//*[@resource-id="com.sankuai.meituan:id/close"]', "关闭按钮"), ], "verification": [ '//*[contains(@text, "验证")]', '//*[contains(@text, "滑块")]', '//*[contains(@text, "点击")]', '//*[contains(@text, "请输入图片中的内容")]', '//*[contains(@text, "用最短线连接")]', '//*[contains(@text, "请拖动下方滑块完成拼图")]', '//*[contains(@resource-id, "captcha")]' ] } def run(self): while self.running: try: handled = self.check_and_handle_popup() time.sleep(2 if handled else 1) except Exception as e: self.logger.exception("监控线程异常: %s", e) time.sleep(3) def _is_recent_click(self, xpath): key = f"{xpath}_{int(time.time())}" return key in self.recent_clicks or (self.recent_clicks.append(key), False)[0] def check_and_handle_popup(self): d = self.spider.d for xpath, desc in self.popup_rules["simple"]: if d.xpath(xpath).exists and not self._is_recent_click(xpath): self.logger.info("检测到弹窗: %s", desc) d.xpath(xpath).click() return True for xpath in self.popup_rules["verification"]: if d.xpath(xpath).exists: now = time.time() if now - self.last_verification_time < 30: return False self.last_verification_time = now self.verification_count += 1 self.logger.warning("验证码弹窗触发,等待人工处理...") if self.verification_count > self.MAX_VERIFICATION_RETRY: self.logger.error("验证码重试超限,终止任务") self.spider.stop_all() return True self.pausing.set() d.toast.show("需要人工处理验证码", 120) while d.xpath(xpath).exists: time.sleep(5) self.logger.info("验证码已处理") d.toast.show("验证完成", 2) self.pausing.clear() return True if d.xpath('//*[contains(@text, "广告")]').exists: w, h = d.info['displayWidth'], d.info['displayHeight'] d.click(w - 50, 50) self.logger.info("关闭广告弹窗") return True return False def stop(self): self.running = False