Summary: Provides server purchase links (Alibaba, Tencent, Huawei Clouds), a deployment tutorial link, and Python script code for automating daily check-ins on ms.ccoo.cn. The script features auto-login, sign-in button detection, and cookie persistence.
阿里云:
服务器购买地址
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 pathlib import Pathfrom typing import Optional, Listfrom playwright.sync_api import sync_playwright, TimeoutError as PWTimeoutErrorBASE_URL = os.getenv("CCOO_BASE_URL", "http://www.ms.ccoo.cn/").rstrip("/") + "/"STATE_FILE = Path("storage_state.json")USER = os.getenv("CCOO_USER", "").strip()PASS = os.getenv("CCOO_PASS", "").strip()# 你可以把这里改成更明确的入口(如果你知道网站签到入口)CANDIDATE_PATHS = ["", # 首页"user/", "member/", "my/", "mine/", "ucenter/", "account/","signin/", "sign/", "checkin/", "task/", "mission/", "qiandao/",]# 常见"签到/打卡/领取"按钮文案关键字BUTTON_TEXT_KEYWORDS = ["签到", "打卡", "今日签到", "立即签到", "一键签到","领取", "领积分", "领红包", "任务", "去签到",]def log(msg: str):print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] {msg}", flush=True)def open_candidate_pages(page) -> None:"""依次打开签到入口的页面,提高命中率"""for p in CANDIDATE_PATHS:url = BASE_URL + ptry:log(f"打开页面: {url}")page.goto(url, wait_until="domcontentloaded", timeout=25000)page.wait_for_timeout(800)except PWTimeoutError:log(f"打开超时,跳过: {url}")continuedef is_logged_in(page) -> bool:"""基于页面特征判断是否已登录(通用 heuristics)命中任意一种即认为登录态存在:- 页面出现"退出/注销/个人中心/我的"等- 页面包含明显的用户头像/昵称区域(常见 class)"""html = page.content()if any(k in html for k in ["退出", "注销", "个人中心", "我的资料", "我的订单", "我的主页"]):return True# 常见用户区域class/id特征(可按实际站点补充)for sel in ["text=退出", "text=注销", "text=个人中心", "text=我的","[class*='avatar']", "[class*='user']", "[id*='user']", "[id*='avatar']",]:try:if page.locator(sel).first.is_visible(timeout=800):return Trueexcept Exception:passreturn Falsedef try_login(page) -> bool:"""通用登录流程:1) 打开首页2) 尝试点击"登录/账号登录/密码登录"3) 尝试在页面上找到账号/密码输入框并填写4) 点击"登录/提交""""if not USER or not PASS:log("❌ 未设置环境变量 CCOO_USER / CCOO_PASS,无法自动登录")return Falsepage.goto(BASE_URL, wait_until="domcontentloaded", timeout=25000)page.wait_for_timeout(1000)# 先尝试点"登录"入口login_entry_selectors = ["text=登录", "text=立即登录", "text=账号登录", "text=密码登录","a:has-text('登录')", "button:has-text('登录')",]for sel in login_entry_selectors:try:loc = page.locator(sel).firstif loc.is_visible(timeout=800):loc.click(timeout=1500)page.wait_for_timeout(800)breakexcept Exception:pass# 寻找账号/密码输入框(常见 placeholder / name / type)user_selectors = ["input[placeholder*='手机']","input[placeholder*='账号']","input[placeholder*='用户名']","input[placeholder*='邮箱']","input[type='text']","input[name*='user']","input[name*='mobile']","input[name*='email']","input[id*='user']","input[id*='mobile']",]pass_selectors = ["input[type='password']","input[placeholder*='密码']","input[name*='pass']","input[id*='pass']",]user_box = Nonepwd_box = Nonefor sel in user_selectors:try:loc = page.locator(sel).firstif loc.is_visible(timeout=800):user_box = locbreakexcept Exception:passfor sel in pass_selectors:try:loc = page.locator(sel).firstif loc.is_visible(timeout=800):pwd_box = locbreakexcept Exception:passif not user_box or not pwd_box:log("❌ 未能自动定位账号/密码输入框(需要你根据实际页面补 1-2 个选择器)")return Falseuser_box.fill(USER, timeout=3000)pwd_box.fill(PASS, timeout=3000)# 点击登录按钮submit_selectors = ["button:has-text('登录')","button:has-text('提交')","button:has-text('确定')","input[type='submit']","text=登录",]clicked = Falsefor sel in submit_selectors:try:loc = page.locator(sel).firstif loc.is_visible(timeout=800):loc.click(timeout=2000)clicked = Truebreakexcept Exception:passif not clicked:log("❌ 未找到可点击的登录按钮(需要你补充登录按钮选择器)")return False# 等待跳转/登录态生效page.wait_for_timeout(2500)# 有些站点登录后会跳回首页或个人中心,这里再打开一遍首页确认page.goto(BASE_URL, wait_until="domcontentloaded", timeout=25000)page.wait_for_timeout(1000)ok = is_logged_in(page)log("✅ 登录成功" if ok else "❌ 登录可能失败(未检测到登录态)")return okdef find_sign_buttons(page) -> List:"""多策略找"签到/打卡/领取"按钮:- 按文本关键词找 button/a/div/span- 按常见 class/id(qiandao/sign/checkin/task)"""candidates = []# 1) 文本关键字for kw in BUTTON_TEXT_KEYWORDS:for sel in [f"button:has-text('{kw}')",f"a:has-text('{kw}')",f"div:has-text('{kw}')",f"span:has-text('{kw}')",]:try:locs = page.locator(sel)count = min(locs.count(), 5)for i in range(count):one = locs.nth(i)if one.is_visible(timeout=300):candidates.append(one)except Exception:pass# 2) 常见标识for sel in ["[class*='qiandao']","[class*='sign']","[class*='checkin']","[id*='qiandao']","[id*='sign']","[id*='checkin']","a[href*='qiandao']","a[href*='sign']","a[href*='checkin']","a[href*='task']",]:try:locs = page.locator(sel)count = min(locs.count(), 5)for i in range(count):one = locs.nth(i)if one.is_visible(timeout=300):candidates.append(one)except Exception:pass# 去重(按 element handle)uniq = []seen = set()for c in candidates:try:h = c.element_handle()if not h:continuekey = h._impl_obj._guid if hasattr(h, "_impl_obj") else str(h)if key not in seen:seen.add(key)uniq.append(c)except Exception:passreturn uniqdef do_sign(page) -> bool:"""执行签到:打开候选页面 → 找按钮 → 逐个尝试点击"""open_candidate_pages(page)btns = find_sign_buttons(page)if not btns:log("❌ 未找到任何疑似签到/打卡按钮(建议你指定一个明确的签到入口路径或选择器)")return Falselog(f"发现 {len(btns)} 个疑似按钮,开始尝试点击…")for idx, b in enumerate(btns, 1):try:text = (b.inner_text(timeout=800) or "").strip().replace("\n", " ")except Exception:text = ""try:log(f"尝试点击第 {idx} 个按钮: {text[:30]}")b.click(timeout=2000)page.wait_for_timeout(1500)# 点击后一般会出现"已签到/成功/领取成功"等提示html = page.content()if any(k in html for k in ["已签到", "签到成功", "打卡成功", "领取成功", "成功"]):log("✅ 检测到成功提示,签到可能已完成")return True# 也可能直接跳转到结果页if re.search(r"(sign|qiandao|checkin|task|mission)", page.url, re.I):log(f"ℹ️ 页面已跳转到: {page.url}")# 继续用提示判断html2 = page.content()if any(k in html2 for k in ["已签到", "签到成功", "打卡成功", "领取成功", "成功"]):log("✅ 检测到成功提示,签到可能已完成")return Trueexcept Exception as e:log(f"点击失败,继续下一个: {e}")log("❌ 已尝试所有候选按钮,仍未判断为签到成功")return Falsedef main():log("开始执行 ms.ccoo.cn 自动签到(通用探测版)")with sync_playwright() as p:browser = p.chromium.launch(headless=True)context = browser.new_context(storage_state=str(STATE_FILE) if STATE_FILE.exists() else None)page = context.new_page()# 1) 先检查登录态page.goto(BASE_URL, wait_until="domcontentloaded", timeout=25000)page.wait_for_timeout(1000)if not is_logged_in(page):log("未检测到登录态,开始自动登录…")if not try_login(page):log("❌ 登录失败,终止")browser.close()sys.exit(1)else:log("✅ 检测到已登录态(将直接签到)")# 2) 执行签到ok = do_sign(page)# 3) 保存登录态,便于下次免登context.storage_state(path=str(STATE_FILE))log(f"✅ 已保存登录态到 {STATE_FILE.resolve()}")browser.close()if ok:log("🎉 脚本执行结束:签到流程已完成(或检测到成功提示)")sys.exit(0)else:log("⚠️ 脚本执行结束:未能确认签到成功(需要补充入口或选择器)")sys.exit(2)if __name__ == "__main__":main()
该脚本为家乡通自动签到脚本,主要作用包括:
自动复用 Cookie:优先读取
storage_state.json,能免登录直接跑签到。自动登录:未登录时,尝试点击"登录",自动填入账号密码并提交。
自动探测签到入口:遍历一批常见"个人中心/任务/签到"路径。
自动找"签到/打卡/领取"按钮:通过"文本关键字 + 常见class/id/href"多策略定位并点击。
保存登录态:执行结束后保存最新 Cookie,下次更稳定。
主要方法
log→ 统一输出带时间戳的日志,便于排障。open_candidate_pages→ 依次打开常见个人中心/任务/签到路径,提高命中率。is_logged_in→ 用页面关键字/元素特征判断是否处于登录状态。try_login→ 自动完成"找登录入口 → 填账号密码 → 提交 → 验证登录态"的流程。find_sign_buttons→ 多策略搜集疑似"签到/打卡/领取"按钮(文本匹配 + 标识匹配)。do_sign→ 执行签到核心流程:打开候选页 → 找按钮 → 逐个点击 → 判断成功提示。main→ 脚本入口:加载/复用登录态 → 必要时登录 → 执行签到 → 保存登录态并退出。
注意:
本文部分变量已做脱敏处理,仅用于测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。技术层面需要提供帮助,可以通过打赏的方式进行探讨。
没有评论:
发表评论