haha
This commit is contained in:
@@ -467,11 +467,9 @@ class BossRecruitHandler(BaseTaskHandler):
|
|||||||
|
|
||||||
def _greet_one_geek(self, page, container, item: dict) -> bool:
|
def _greet_one_geek(self, page, container, item: dict) -> bool:
|
||||||
"""
|
"""
|
||||||
对单个牛人打招呼。
|
对单个牛人打招呼 —— 与 1.py _greet_one_geek 完全一致的逻辑。
|
||||||
关键:点击姓名后,BOSS 会动态加载一个新 iframe(简历详情面板),
|
使用 page.get_frame(1) 获取详情面板,所有元素查找语法与 1.py 相同。
|
||||||
"打招呼"按钮在这个面板 frame 中。
|
仅增加 try/finally 防止异常时 UI 卡死。
|
||||||
不能搜索所有 frame(因为 recommendFrame 中也有打招呼按钮),
|
|
||||||
必须精确定位到详情面板 frame。
|
|
||||||
"""
|
"""
|
||||||
geek_name = str((item.get("geekCard") or {}).get("geekName", "")).strip()
|
geek_name = str((item.get("geekCard") or {}).get("geekName", "")).strip()
|
||||||
if not geek_name:
|
if not geek_name:
|
||||||
@@ -480,67 +478,46 @@ class BossRecruitHandler(BaseTaskHandler):
|
|||||||
panel_opened = False
|
panel_opened = False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 查找姓名元素
|
# 与 1.py 一致:查找姓名 → scrollIntoView → 点击
|
||||||
name_ele = container.ele(f'x://span[contains(text(),"{geek_name}")]', timeout=5)
|
name_ele = container.ele(f'x://span[contains(text(),"{geek_name}")]', timeout=5)
|
||||||
if not name_ele:
|
if not name_ele:
|
||||||
name_ele = container.ele(f'x://span[text()="{geek_name}"]', timeout=2)
|
name_ele = container.ele(f'x://span[text()="{geek_name}"]', timeout=2)
|
||||||
if not name_ele:
|
if not name_ele:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# scrollIntoView + 点击
|
|
||||||
name_ele.run_js("this.scrollIntoView()")
|
name_ele.run_js("this.scrollIntoView()")
|
||||||
name_ele.click()
|
name_ele.click()
|
||||||
time.sleep(3)
|
time.sleep(3)
|
||||||
panel_opened = True
|
panel_opened = True
|
||||||
|
|
||||||
# 获取简历详情面板 frame(非 recommendFrame 的那个 iframe)
|
# 与 1.py 一致:a = page.get_frame(1)
|
||||||
panel = self._get_detail_panel_frame(page)
|
a = page.get_frame(1)
|
||||||
if not panel:
|
|
||||||
return False
|
|
||||||
time.sleep(random.uniform(0.5, 1.2))
|
time.sleep(random.uniform(0.5, 1.2))
|
||||||
|
|
||||||
# 打招呼
|
# 与 1.py 一致:打招呼
|
||||||
greet_btn = panel.ele('x://*[contains(text(),"打招呼")]', timeout=3)
|
a.ele(f'x://*[contains(text(),"打招呼")]', timeout=2).click(by_js=True)
|
||||||
if not greet_btn:
|
|
||||||
return False
|
|
||||||
greet_btn.click(by_js=True)
|
|
||||||
time.sleep(random.uniform(0.5, 1.2))
|
time.sleep(random.uniform(0.5, 1.2))
|
||||||
|
|
||||||
# 收藏(可选)
|
# 与 1.py 一致:收藏
|
||||||
try:
|
a.ele(f'x://*[contains(text(),"收藏")]', timeout=2).click(by_js=True)
|
||||||
collect_btn = panel.ele('x://*[contains(text(),"收藏")]', timeout=2)
|
time.sleep(random.uniform(0.5, 1.2))
|
||||||
if collect_btn:
|
|
||||||
collect_btn.click(by_js=True)
|
|
||||||
time.sleep(random.uniform(0.5, 1.2))
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# 点击 btn-outline 按钮(可选)
|
# 与 1.py 一致:btn-outline × 3
|
||||||
for _ in range(3):
|
for i in range(3):
|
||||||
try:
|
a.ele(f'x://*[@class="btn-v2 btn-outline-v2"]', timeout=2).click(by_js=True)
|
||||||
extra_btn = panel.ele('x://*[@class="btn-v2 btn-outline-v2"]', timeout=1)
|
time.sleep(random.uniform(0.5, 1.2))
|
||||||
if extra_btn:
|
|
||||||
extra_btn.click(by_js=True)
|
|
||||||
time.sleep(random.uniform(0.5, 1.2))
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
except Exception:
|
|
||||||
break
|
|
||||||
|
|
||||||
# 快速回复
|
# 与 1.py 一致:快速回复 + 发送
|
||||||
try:
|
page.ele(f'x://*[@data-placeholder="快速回复"]', timeout=2).input(FAST_REPLY_TEXT)
|
||||||
input_box = page.ele('x://*[@data-placeholder="快速回复"]', timeout=2)
|
page.ele(f'x://*[contains(text(),"发送")]', timeout=2).click()
|
||||||
if input_box:
|
time.sleep(random.uniform(0.5, 1.2))
|
||||||
input_box.input(FAST_REPLY_TEXT)
|
|
||||||
send_btn = page.ele('x://*[contains(text(),"发送")]', timeout=2)
|
# 与 1.py 一致:关闭面板
|
||||||
if send_btn:
|
page.ele('x://*[@class="iboss iboss-close"]').click()
|
||||||
send_btn.click()
|
time.sleep(random.uniform(0.5, 1.2))
|
||||||
time.sleep(random.uniform(0.5, 1.2))
|
a.ele('x://*[@class="boss-popup__close"]').click()
|
||||||
except Exception:
|
time.sleep(random.uniform(0.5, 1.2))
|
||||||
pass
|
|
||||||
|
|
||||||
# 关闭面板
|
|
||||||
self._close_all_panels(page)
|
|
||||||
panel_opened = False
|
panel_opened = False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -551,55 +528,6 @@ class BossRecruitHandler(BaseTaskHandler):
|
|||||||
self._close_all_panels(page)
|
self._close_all_panels(page)
|
||||||
time.sleep(0.5)
|
time.sleep(0.5)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _get_detail_panel_frame(page):
|
|
||||||
"""
|
|
||||||
获取简历详情面板 frame。
|
|
||||||
|
|
||||||
页面结构:
|
|
||||||
- frame 0: recommendFrame(推荐牛人列表,name="recommendFrame")
|
|
||||||
- frame 1: 简历详情面板(点击牛人后动态加载的 iframe,无固定 name)
|
|
||||||
|
|
||||||
由于多次交互后 frame 索引可能变化,不能用固定索引。
|
|
||||||
策略:遍历所有 frame,排除 name="recommendFrame" 的,返回另一个。
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
frames = page.get_frames()
|
|
||||||
except Exception:
|
|
||||||
return None
|
|
||||||
|
|
||||||
if not frames:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# 只有一个 frame 时,它就是 recommendFrame,没有详情面板
|
|
||||||
if len(frames) <= 1:
|
|
||||||
# 仍然尝试 get_frame(1)(可能 DrissionPage 有隐式 frame)
|
|
||||||
try:
|
|
||||||
return page.get_frame(1)
|
|
||||||
except Exception:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# 多个 frame 时,找到不是 recommendFrame 的那个
|
|
||||||
for i in range(len(frames) - 1, -1, -1): # 倒序,最新加载的通常在后面
|
|
||||||
try:
|
|
||||||
frame = page.get_frame(i)
|
|
||||||
# 检查 frame 的 name 属性
|
|
||||||
frame_ele = getattr(frame, 'frame_ele', None)
|
|
||||||
if frame_ele:
|
|
||||||
name = frame_ele.attr('name') or ''
|
|
||||||
if name == 'recommendFrame':
|
|
||||||
continue
|
|
||||||
# 不是 recommendFrame 的 frame 就是详情面板
|
|
||||||
return frame
|
|
||||||
except Exception:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 兜底:如果上面的方法都失败,尝试直接 get_frame(1)
|
|
||||||
try:
|
|
||||||
return page.get_frame(1)
|
|
||||||
except Exception:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# ────────────────────── 联系记录入库 ──────────────────────
|
# ────────────────────── 联系记录入库 ──────────────────────
|
||||||
|
|
||||||
def _save_new_greet_contacts(self, *, records: List[dict], worker_id: str, account_name: str) -> int:
|
def _save_new_greet_contacts(self, *, records: List[dict], worker_id: str, account_name: str) -> int:
|
||||||
|
|||||||
Reference in New Issue
Block a user