|
|
@@ -66,6 +66,7 @@ class TlsPlugin(IVSPlg):
|
|
|
if not os.path.exists(self.root_workspace):
|
|
|
os.makedirs(self.root_workspace)
|
|
|
|
|
|
+ self.last_refresh_time = time.time()
|
|
|
self.tunnel = None
|
|
|
self.session_create_time: float = 0
|
|
|
|
|
|
@@ -86,17 +87,40 @@ class TlsPlugin(IVSPlg):
|
|
|
self.free_config = config.free_config or {}
|
|
|
|
|
|
def keep_alive(self):
|
|
|
- try:
|
|
|
- self.page.refresh()
|
|
|
- self.page.wait.load_start(timeout=2)
|
|
|
- self.page.wait.doc_loaded()
|
|
|
- time.sleep(random.uniform(1, 3))
|
|
|
- self._check_page_is_session_expired_or_invalid('Book your appointment', html = self.page.html)
|
|
|
- self.simulate_random_human_clicks()
|
|
|
- except SessionExpiredOrInvalidError as e:
|
|
|
- self.is_healthy = False
|
|
|
- except Exception as e:
|
|
|
- self._log(f"Unexpected error in keep_alive: {e}")
|
|
|
+ """
|
|
|
+ 统一保活机制:
|
|
|
+ - 距离上次刷新超过 10 分钟:执行完整页面刷新并检查 Session。
|
|
|
+ - 否则:随机发送 Fetch 小请求保活。
|
|
|
+ """
|
|
|
+ if time.time() - self.last_refresh_time >= 60*10:
|
|
|
+ try:
|
|
|
+ self._log("Cut all connections...")
|
|
|
+ self.tunnel.cut_all_connections()
|
|
|
+ self._log("refresh page...")
|
|
|
+ self.page.refresh()
|
|
|
+ self.page.wait.load_start(timeout=2)
|
|
|
+ self.page.wait.doc_loaded()
|
|
|
+ time.sleep(random.uniform(1, 3))
|
|
|
+ self._check_page_is_session_expired_or_invalid('Book your appointment', html=self.page.html)
|
|
|
+ self.last_refresh_time = time.time()
|
|
|
+ self._log("refresh page finished")
|
|
|
+ except Exception as e:
|
|
|
+ self._log(f"refresh page error: {str(e)}")
|
|
|
+ self.is_healthy = False
|
|
|
+ else:
|
|
|
+ choice = random.choice(['home', 'travel_groups'])
|
|
|
+ headers = {}
|
|
|
+ if choice == 'home':
|
|
|
+ url = "https://visas-fr.tlscontact.com/"
|
|
|
+ elif choice == 'travel_groups':
|
|
|
+ url = "https://visas-fr.tlscontact.com/en-us/travel-groups"
|
|
|
+ headers = {"cache-control": "max-age=0"}
|
|
|
+ try:
|
|
|
+ self._log(f"send keep alive fetch request ({choice})")
|
|
|
+ self._perform_request("GET", url, headers=headers)
|
|
|
+ except Exception as e:
|
|
|
+ self._log(f"send keep alive fetch error: {str(e)}")
|
|
|
+ self.is_healthy = False
|
|
|
|
|
|
def simulate_random_human_clicks(self, min_x=300, max_x=800, min_y=400, max_y=600, min_clicks=1, max_clicks=2):
|
|
|
"""
|
|
|
@@ -286,14 +310,17 @@ class TlsPlugin(IVSPlg):
|
|
|
self._log(f"Navigating: {tls_url}")
|
|
|
self.page.get(tls_url)
|
|
|
time.sleep(5)
|
|
|
-
|
|
|
+ if 'Attention Required! | Cloudflare' in self.page.title and 'Sorry, you have been blocked' in self.page.html:
|
|
|
+ self._log(f'Block by cloudflare, try refresh...')
|
|
|
+ self.page.refresh()
|
|
|
+ self.page.wait.load_start(timeout=2)
|
|
|
+ self.page.wait.doc_loaded()
|
|
|
cf_bypasser = CloudflareBypasser(self.page, log=self.config.debug)
|
|
|
if not cf_bypasser.bypass(max_retry=6):
|
|
|
raise BizLogicError("Cloudflare bypass timeout")
|
|
|
time.sleep(3)
|
|
|
cf_bypasser.handle_waiting_room()
|
|
|
|
|
|
- # --- 初始化人类行为模拟工具 ---
|
|
|
self._log("Init humanize tools...")
|
|
|
self.mouse = HumanMouse(self.page, debug=self.config.debug)
|
|
|
self.keyboard = HumanKeyboard(self.page)
|
|
|
@@ -308,7 +335,9 @@ class TlsPlugin(IVSPlg):
|
|
|
has_submitted_login = False
|
|
|
|
|
|
for step in range(max_steps):
|
|
|
- self.page.wait.load_start()
|
|
|
+ self.page.wait.doc_loaded()
|
|
|
+ time.sleep(0.5)
|
|
|
+
|
|
|
current_url = self.page.url
|
|
|
self._log(f"--- [Router Step {step+1}] Current URL: {current_url} ---")
|
|
|
|
|
|
@@ -344,8 +373,10 @@ class TlsPlugin(IVSPlg):
|
|
|
self._log("State: Login Portal. Clicking login link...")
|
|
|
login_link = self.page.ele("tag:a@@href:login")
|
|
|
self.mouse.human_click_ele(login_link)
|
|
|
- time.sleep(3)
|
|
|
+
|
|
|
+ self.page.wait.load_start(timeout=3)
|
|
|
continue
|
|
|
+
|
|
|
if self.page.ele("tag:svg@@data-testid=user-button", timeout=1):
|
|
|
self._log("State: Already login, logout now...")
|
|
|
user_btn = self.page.ele("tag:svg@@data-testid=user-button")
|
|
|
@@ -353,9 +384,10 @@ class TlsPlugin(IVSPlg):
|
|
|
time.sleep(1.5)
|
|
|
logout_btn = self.page.ele("#logout")
|
|
|
self.mouse.human_click_ele(logout_btn)
|
|
|
- time.sleep(1.5)
|
|
|
+
|
|
|
+ self.page.wait.load_start(timeout=3)
|
|
|
self.page.get(tls_url)
|
|
|
- time.sleep(3)
|
|
|
+ self.page.wait.load_start(timeout=3)
|
|
|
continue
|
|
|
|
|
|
# 状态 4:真正的登录表单页
|
|
|
@@ -415,7 +447,8 @@ class TlsPlugin(IVSPlg):
|
|
|
login_btn = self.page.ele('tag:button@@text():Login')
|
|
|
self.mouse.human_click_ele(login_btn)
|
|
|
has_submitted_login = True
|
|
|
- time.sleep(3)
|
|
|
+
|
|
|
+ self.page.wait.load_start(timeout=5)
|
|
|
continue
|
|
|
|
|
|
# 状态 5:Travel Groups 页面
|
|
|
@@ -439,7 +472,7 @@ class TlsPlugin(IVSPlg):
|
|
|
if select_btn:
|
|
|
time.sleep(random.uniform(0.5, 1.2))
|
|
|
self.mouse.human_click_ele(select_btn)
|
|
|
- time.sleep(3)
|
|
|
+ self.page.wait.load_start(timeout=3)
|
|
|
continue
|
|
|
else:
|
|
|
self._log("[WARN] Select button found but not visible.")
|
|
|
@@ -450,7 +483,8 @@ class TlsPlugin(IVSPlg):
|
|
|
if self.page.ele('#book-appointment-btn', timeout=1):
|
|
|
self._log("State: Intermediate Dashboard. Clicking Book Appointment button...")
|
|
|
self.mouse.human_click_ele(self.page.ele('#book-appointment-btn'))
|
|
|
- time.sleep(3)
|
|
|
+
|
|
|
+ self.page.wait.load_start(timeout=3)
|
|
|
continue
|
|
|
|
|
|
# 状态 7:登录失败校验 或 未知加载状态
|