Summary: This script automates daily sign-ins on the 101jiajiao.com website. It logs in, navigates to the user/member center, and attempts to find and click check-in buttons. It handles potential issues like captchas (requires manual intervention). The guide includes server purchase links (Alibaba Cloud, Tencent Cloud, Huawei Cloud) and a 2024 Qinglong Panel deployment tutorial.
阿里云:
服务器购买地址
https://t.aliyun.com/U/kcPAeY若失效,可用地址
https://www.aliyun.com/daily-act/ecs/activity_selection?source=5176.29345612&userCode=49hts92d腾讯云:
https://curl.qcloud.com/wJpWmSfU若失效,可用地址
https://cloud.tencent.com/act/cps/redirect?redirect=2446&cps_key=ad201ee2ef3b771157f72ee5464b1fea&from=console华为云
https://activity.huaweicloud.com/cps.html?fromacct=64b5cf7cc11b4840bb4ed2ea0b2f4468&utm_source=V1g3MDY4NTY=&utm_medium=cps&utm_campaign=2019052.部署教程
3.代码如下
# -*- coding: utf-8 -*-import osimport reimport sysimport timefrom dataclasses import dataclassfrom typing import Optional, List, Tuplefrom playwright.sync_api import sync_playwright, Page, TimeoutError as PWTimeoutErrorclass Config:base_url: str = "https://www.101jiajiao.com/"login_url: str = "https://www.101jiajiao.com/login.htm"username_env: str = "JIAJIAO_USERNAME"password_env: str = "JIAJIAO_PASSWORD"# 浏览器行为headless: bool = Trueslow_mo_ms: int = 0nav_timeout_ms: int = 35_000action_timeout_ms: int = 15_000# 站点可能的"登录后页面/会员中心"候选(不同账号类型可能不同)member_candidates: Tuple[str, ...] = ("https://www.101jiajiao.com/","https://www.101jiajiao.com/user/","https://www.101jiajiao.com/member/","https://www.101jiajiao.com/my/","https://www.101jiajiao.com/center/","https://www.101jiajiao.com/ucenter/",)# "签到"可能出现的关键词(按钮/链接/菜单)checkin_keywords: Tuple[str, ...] = ("签到", "打卡", "任务", "积分", "每日", "福利")class Jiajiao101Checkin:def __init__(self, cfg: Config):self.cfg = cfgself.username = os.getenv(cfg.username_env, "").strip()self.password = os.getenv(cfg.password_env, "").strip()if not self.username or not self.password:raise RuntimeError(f"缺少账号密码环境变量:{cfg.username_env}/{cfg.password_env},请先设置后再运行。")# ------------------------- 主流程 -------------------------def run(self) -> None:with sync_playwright() as p:browser = p.chromium.launch(headless=self.cfg.headless, slow_mo=self.cfg.slow_mo_ms)context = browser.new_context(locale="zh-CN",user_agent=("Mozilla/5.0 (Windows NT 10.0; Win64; x64) ""AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36"),)page = context.new_page()page.set_default_navigation_timeout(self.cfg.nav_timeout_ms)page.set_default_timeout(self.cfg.action_timeout_ms)try:self.open_login_page(page)self.do_login(page)# 登录后:尝试进入"会员中心/个人中心"self.goto_member_center(page)# 尝试执行签到ok, msg = self.try_checkin(page)# 输出最终结果print("=" * 80)print(f"结果:{'✅ 成功' if ok else '⚠️ 未完成'}")print(f"说明:{msg}")print("=" * 80)finally:context.close()browser.close()# ------------------------- 页面动作 -------------------------def open_login_page(self, page: Page) -> None:page.goto(self.cfg.login_url, wait_until="domcontentloaded")self._sleep(0.8)def do_login(self, page: Page) -> None:"""101家教网登录页是传统表单样式,但页面结构可能因城市分站或版本变化而不同;因此采用"多策略定位输入框 + 回车/点击提交按钮"的方式。"""# 可能出现:input[type=text] / input[name=username] / id=... 等不固定user_locators = ["input[name='username']","input[name='user']","input[name='loginname']","input[type='text']","input[placeholder*='用户名']","input[placeholder*='手机号']","input[placeholder*='邮箱']",]pass_locators = ["input[name='password']","input[type='password']","input[placeholder*='密码']",]user_el = self._first_visible(page, user_locators)pass_el = self._first_visible(page, pass_locators)if not user_el or not pass_el:# 截图/保留现场方便你排查page.screenshot(path="101jiajiao_login_debug.png", full_page=True)raise RuntimeError("未能在登录页定位到用户名/密码输入框(已保存截图 101jiajiao_login_debug.png)")user_el.fill(self.username)pass_el.fill(self.password)# 提交:优先找"登录/登陆"按钮,否则回车submit_locators = ["button:has-text('登录')","button:has-text('登陆')","input[type='submit']","a:has-text('登录')","a:has-text('登陆')",]submit_el = self._first_visible(page, submit_locators)if submit_el:submit_el.click()else:pass_el.press("Enter")# 等待跳转/刷新(如果站点不跳转,也至少等待网络空闲)try:page.wait_for_load_state("networkidle", timeout=20_000)except PWTimeoutError:pass# 如果出现验证码/二次验证,提示人工处理if self._maybe_captcha_or_2fa(page):print("⚠️ 检测到可能存在验证码/二次验证,请在弹出的浏览器中手动完成后再继续…")# 如果你把 headless=False,就能手动点# 这里给 60 秒人工处理窗口(可按需改)self._countdown(60)# 简单判断是否登录成功:页面出现"退出/个人中心/会员中心"等字样html = page.content()if not re.search(r"(退出|个人中心|会员中心|我的|我的简历)", html):# 不一定失败(可能跳到分站/城市页),再给一次缓冲self._sleep(1.5)def goto_member_center(self, page: Page) -> None:"""登录成功后,尽可能进入"会员中心/我的"页面"""# 先尝试点页面上的"会员登录/个人中心/我的"possible_nav = ["a:has-text('个人中心')","a:has-text('会员中心')","a:has-text('我的')","a:has-text('简历')",]nav_el = self._first_visible(page, possible_nav, strict=False)if nav_el:try:nav_el.click()page.wait_for_load_state("domcontentloaded", timeout=10_000)returnexcept Exception:pass# 再尝试候选URL逐个访问for url in self.cfg.member_candidates:try:page.goto(url, wait_until="domcontentloaded")self._sleep(0.6)# 只要页面能打开且不是明显回到登录页,就认为可用if "login" not in page.url and "login.htm" not in page.url:returnexcept Exception:continuedef try_checkin(self, page: Page) -> Tuple[bool, str]:"""执行"签到":- 先找明显的"签到/打卡"按钮- 再找"任务/积分/福利"等入口进入后再找"签到"- 找到就点击,并判断"已签到/签到成功"等结果"""# 1) 直接在当前页找"签到/打卡"if self._click_by_text(page, ["签到", "打卡"]):return self._verify_checkin_result(page)# 2) 进入任务/积分/福利后再找if self._click_by_text(page, ["任务", "积分", "福利", "每日"]):self._sleep(1.2)if self._click_by_text(page, ["签到", "打卡"]):return self._verify_checkin_result(page)# 3) 全页面扫描关键词按钮(更激进但通用)if self._scan_and_click_keywords(page, list(self.cfg.checkin_keywords)):return self._verify_checkin_result(page)return False, "未在登录后的页面中发现明确的"签到/打卡/任务入口"。可能该站点无每日签到,或入口仅在APP/特定页面内。"# ------------------------- 辅助方法 -------------------------def _first_visible(self, page: Page, selectors: List[str], strict: bool = True):for sel in selectors:try:loc = page.locator(sel)if loc.count() > 0:first = loc.firstif first.is_visible():return firstexcept Exception:continueif strict:return Nonereturn Nonedef _click_by_text(self, page: Page, texts: List[str]) -> bool:for t in texts:try:btn = page.get_by_text(t, exact=False).firstif btn and btn.is_visible():btn.click()try:page.wait_for_load_state("domcontentloaded", timeout=8_000)except PWTimeoutError:passreturn Trueexcept Exception:continuereturn Falsedef _scan_and_click_keywords(self, page: Page, keywords: List[str]) -> bool:"""扫描页面上包含关键词的 a/button/div[role=button] 等可点击元素,找到就点。"""candidates = ["a","button","[role='button']","div","span",]for kw in keywords:for tag in candidates:try:loc = page.locator(tag, has_text=kw)if loc.count() > 0:el = loc.firstif el.is_visible():el.click()self._sleep(0.8)return Trueexcept Exception:continuereturn Falsedef _verify_checkin_result(self, page: Page) -> Tuple[bool, str]:"""通过页面文本粗判是否签到成功/已签到。"""self._sleep(1.0)content = page.content()success_patterns = [r"(签到成功|打卡成功|已签到|今日已签到|签到完成)",r"(获得|领取).{0,10}(积分|金币|经验|奖励|红包)",]for ptn in success_patterns:if re.search(ptn, content):return True, "检测到页面反馈:疑似已完成签到/已签到。"# 没匹配到也不一定失败(可能接口无提示),给出中性提示page.screenshot(path="101jiajiao_checkin_result.png", full_page=True)return True, "已执行"签到/打卡"点击动作,但未在页面文本中匹配到明确成功提示(已保存截图 101jiajiao_checkin_result.png)。"def _maybe_captcha_or_2fa(self, page: Page) -> bool:"""粗略判断是否出现验证码/二次验证提示(不做破解,保留人工处理)。"""html = page.content()return bool(re.search(r"(验证码|滑块|短信验证码|安全验证|Geetest|Tencent Captcha)", html, re.I))@staticmethoddef _sleep(sec: float) -> None:time.sleep(sec)@staticmethoddef _countdown(seconds: int) -> None:for i in range(seconds, 0, -1):if i % 5 == 0 or i <= 5:print(f"…等待你处理验证:剩余 {i}s")time.sleep(1)if __name__ == "__main__":cfg = Config(headless=False, # 第一次建议 False,方便遇到验证码/跳转时你手工处理;稳定后可改 Trueslow_mo_ms=50, # 放慢一点更稳定,想更快可改 0)bot = Jiajiao101Checkin(cfg)bot.run()
自动打开 101家教网登录页并登录账号
登录后尽可能进入会员中心/我的页面
自动在页面中寻找"签到/打卡/任务/积分/福利"等入口并点击
如果遇到验证码/二次验证:提示你手动处理(不做破解,更安全也更通用)
最终输出签到执行结果,并在关键阶段保存截图便于排查
主要方法
run:脚本总入口,负责启动浏览器、串联登录→进入个人中心→执行签到→输出结果并关闭资源。
open_login_page:打开 101 家教网登录页面并等待基础加载完成。
do_login:定位用户名/密码输入框并提交登录;检测验证码/二次验证并留出手工处理时间;做基础"疑似登录成功"判断。
goto_member_center:尝试点击页面"个人中心/会员中心/我的"等入口;若找不到则轮询多个候选个人中心 URL。
try_checkin:执行签到主逻辑:先找"签到/打卡",再进入"任务/积分/福利"等页面再找签到,最后全页面扫描关键词并点击。
_verify_checkin_result:点击签到后,通过页面文本匹配"签到成功/已签到/获得积分"等关键字判断结果;匹配不到会截图并返回中性成功提示。
_first_visible:从多个 CSS 选择器中找到第一个可见元素(用于适配页面结构变化)。
_click_by_text:按文本模糊匹配点击元素(如"签到/任务/积分"),并等待页面加载。
_scan_and_click_keywords:全页面扫描包含关键词的可点击元素(a/button/div等),找到就点击(更通用但更"激进")。
_maybe_captcha_or_2fa:粗判页面是否出现验证码/短信验证等提示(不破解,仅提示人工处理)。
注意:
本文部分变量已做脱敏处理,仅用于测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。技术层面需要提供帮助,可以通过打赏的方式进行探讨。
没有评论:
发表评论