haha
This commit is contained in:
@@ -15,7 +15,13 @@ from pathlib import Path
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from PIL import Image, ImageDraw
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
from tyyp_app.config import GET_YAN_ZHEN_MA_URL, ORDER_PACKET_URL, PROJECT_ROOT
|
from tyyp_app.config import (
|
||||||
|
GET_YAN_ZHEN_MA_URL,
|
||||||
|
ORDER_PACKET_URL,
|
||||||
|
PROJECT_ROOT,
|
||||||
|
UI_SLEEP_FACTOR,
|
||||||
|
UI_SLEEP_MIN_SECONDS,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# ---------- 拼图验证码计算 ----------
|
# ---------- 拼图验证码计算 ----------
|
||||||
@@ -160,7 +166,13 @@ def find_first(page, selectors: list[str], timeout: float = 5):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def wait_for_data_src(img_ele, timeout: float = 6, interval: float = 0.12) -> str:
|
def _sleep_ui(seconds: float, floor: float = UI_SLEEP_MIN_SECONDS) -> None:
|
||||||
|
if seconds <= 0:
|
||||||
|
return
|
||||||
|
time.sleep(max(float(floor), float(seconds) * float(UI_SLEEP_FACTOR)))
|
||||||
|
|
||||||
|
|
||||||
|
def wait_for_data_src(img_ele, timeout: float = 6, interval: float = 0.08) -> str:
|
||||||
"""轮询等待 img 元素的 src 变为有效 data:image URL。"""
|
"""轮询等待 img 元素的 src 变为有效 data:image URL。"""
|
||||||
deadline = time.time() + timeout
|
deadline = time.time() + timeout
|
||||||
while time.time() < deadline:
|
while time.time() < deadline:
|
||||||
@@ -169,7 +181,7 @@ def wait_for_data_src(img_ele, timeout: float = 6, interval: float = 0.12) -> st
|
|||||||
_prefix, _, b64 = src.partition(",")
|
_prefix, _, b64 = src.partition(",")
|
||||||
if b64.strip():
|
if b64.strip():
|
||||||
return src
|
return src
|
||||||
time.sleep(interval)
|
_sleep_ui(interval, floor=0.01)
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"等待 data:image src 超时({timeout}s),当前 src 前80字符: {(img_ele.attr('src') or '')[:80]}"
|
f"等待 data:image src 超时({timeout}s),当前 src 前80字符: {(img_ele.attr('src') or '')[:80]}"
|
||||||
)
|
)
|
||||||
@@ -664,13 +676,13 @@ def submit_phone(
|
|||||||
url: str = "http://yscnb.com/tyyp/",
|
url: str = "http://yscnb.com/tyyp/",
|
||||||
alpha_threshold: int = 12,
|
alpha_threshold: int = 12,
|
||||||
distance_adjust: int = 0,
|
distance_adjust: int = 0,
|
||||||
wait_page: float = 0.3,
|
wait_page: float = 0.15,
|
||||||
) -> Any:
|
) -> Any:
|
||||||
"""
|
"""
|
||||||
填写手机号、点击获取验证码、执行滑块,返回 getYanZhenMa/v2 接口响应体。
|
填写手机号、点击获取验证码、执行滑块,返回 getYanZhenMa/v2 接口响应体。
|
||||||
"""
|
"""
|
||||||
page.get(url)
|
page.get(url)
|
||||||
time.sleep(wait_page)
|
_sleep_ui(wait_page, floor=0.03)
|
||||||
|
|
||||||
# 1. 勾选协议
|
# 1. 勾选协议
|
||||||
agree_checkbox = find_first(
|
agree_checkbox = find_first(
|
||||||
@@ -685,7 +697,7 @@ def submit_phone(
|
|||||||
)
|
)
|
||||||
if agree_checkbox:
|
if agree_checkbox:
|
||||||
click_safe(agree_checkbox)
|
click_safe(agree_checkbox)
|
||||||
time.sleep(0.4)
|
_sleep_ui(0.4, floor=0.04)
|
||||||
|
|
||||||
# 2. 立即订购
|
# 2. 立即订购
|
||||||
order_btn = None
|
order_btn = None
|
||||||
@@ -710,16 +722,16 @@ def submit_phone(
|
|||||||
)
|
)
|
||||||
if order_btn:
|
if order_btn:
|
||||||
break
|
break
|
||||||
time.sleep(0.25)
|
_sleep_ui(0.25, floor=0.03)
|
||||||
|
|
||||||
if order_btn:
|
if order_btn:
|
||||||
try:
|
try:
|
||||||
order_btn.run_js("this.scrollIntoView({block:'center'})")
|
order_btn.run_js("this.scrollIntoView({block:'center'})")
|
||||||
time.sleep(0.05)
|
_sleep_ui(0.05, floor=0.008)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
click_safe(order_btn)
|
click_safe(order_btn)
|
||||||
time.sleep(0.4)
|
_sleep_ui(0.4, floor=0.04)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
page.run_js("""
|
page.run_js("""
|
||||||
@@ -736,7 +748,7 @@ def submit_phone(
|
|||||||
""")
|
""")
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
time.sleep(0.4)
|
_sleep_ui(0.4, floor=0.04)
|
||||||
|
|
||||||
# 3. 输入手机号
|
# 3. 输入手机号
|
||||||
phone_input = find_first(
|
phone_input = find_first(
|
||||||
@@ -886,7 +898,7 @@ def submit_phone(
|
|||||||
last_move_distances = move_distances
|
last_move_distances = move_distances
|
||||||
|
|
||||||
drag_slider(page, slider, move_distance)
|
drag_slider(page, slider, move_distance)
|
||||||
time.sleep(0.2)
|
_sleep_ui(0.2, floor=0.03)
|
||||||
|
|
||||||
remaining = max(0.1, deadline - time.time())
|
remaining = max(0.1, deadline - time.time())
|
||||||
packet, toast_text = _wait_packet_or_feedback(page, timeout=min(4.0, remaining))
|
packet, toast_text = _wait_packet_or_feedback(page, timeout=min(4.0, remaining))
|
||||||
@@ -975,7 +987,7 @@ def submit_code(page, code: str) -> dict:
|
|||||||
raise RuntimeError("未找到验证码输入框")
|
raise RuntimeError("未找到验证码输入框")
|
||||||
|
|
||||||
code_input.input(code, clear=True)
|
code_input.input(code, clear=True)
|
||||||
time.sleep(0.2)
|
_sleep_ui(0.2, floor=0.03)
|
||||||
|
|
||||||
confirm_btn = find_first(
|
confirm_btn = find_first(
|
||||||
page,
|
page,
|
||||||
@@ -992,7 +1004,7 @@ def submit_code(page, code: str) -> dict:
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
confirm_btn.run_js("this.scrollIntoView({block:'center'})")
|
confirm_btn.run_js("this.scrollIntoView({block:'center'})")
|
||||||
time.sleep(0.05)
|
_sleep_ui(0.05, floor=0.008)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -1002,11 +1014,11 @@ def submit_code(page, code: str) -> dict:
|
|||||||
|
|
||||||
def input_code(page, code):
|
def input_code(page, code):
|
||||||
page.ele('x://input[@placeholder="请输入验证码"]').input(code, clear=True)
|
page.ele('x://input[@placeholder="请输入验证码"]').input(code, clear=True)
|
||||||
time.sleep(0.5)
|
_sleep_ui(0.5, floor=0.06)
|
||||||
|
|
||||||
page.listen.start(ORDER_PACKET_URL)
|
page.listen.start(ORDER_PACKET_URL)
|
||||||
page.ele('x://*[@id="app"]/div/img').click(by_js=True)
|
page.ele('x://*[@id="app"]/div/img').click(by_js=True)
|
||||||
time.sleep(0.5)
|
_sleep_ui(0.5, floor=0.06)
|
||||||
page.ele('x://*[@id="app"]/div/div[7]/div/div[3]/button[2]').click(by_js=True)
|
page.ele('x://*[@id="app"]/div/div[7]/div/div[3]/button[2]').click(by_js=True)
|
||||||
res = _normalize_listen_packet(page.listen.wait(timeout=15, fit_count=False))
|
res = _normalize_listen_packet(page.listen.wait(timeout=15, fit_count=False))
|
||||||
if res is None:
|
if res is None:
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ PROXY_SOURCE_URL = "http://47.109.106.79:7002/ProxIpServiceTxt"
|
|||||||
SESSION_IDLE_SECONDS = 180
|
SESSION_IDLE_SECONDS = 180
|
||||||
FLOW_CLEANUP_INTERVAL_SECONDS = 15
|
FLOW_CLEANUP_INTERVAL_SECONDS = 15
|
||||||
|
|
||||||
|
# 自动化交互节奏(用于缩短按钮前后固定等待)
|
||||||
|
UI_SLEEP_FACTOR = 0.4
|
||||||
|
UI_SLEEP_MIN_SECONDS = 0.015
|
||||||
|
|
||||||
MOBILE_UA_POOL = [
|
MOBILE_UA_POOL = [
|
||||||
"Mozilla/5.0 (Linux; Android 14; Pixel 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36",
|
"Mozilla/5.0 (Linux; Android 14; Pixel 8 Pro) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36",
|
||||||
"Mozilla/5.0 (Linux; Android 13; M2012K11AC) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Mobile Safari/537.36",
|
"Mozilla/5.0 (Linux; Android 13; M2012K11AC) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Mobile Safari/537.36",
|
||||||
|
|||||||
Reference in New Issue
Block a user