1.购买服务器阿里云:服务器购买地址https://t.aliyun.com/U/55RK8C若失效,可用地址
阿里云:
服务器购买地址
https://t.aliyun.com/U/55RK8C若失效,可用地址
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 sysimport timeimport jsonimport loggingfrom datetime import datetimefrom pathlib import Pathfrom typing import Optional, Listfrom playwright.sync_api import sync_playwright, Page, BrowserContext, TimeoutError as PWTimeoutErrorBASE_URL = "https://jianghu.taobao.com/"USER_DATA_DIR = Path("./user_data") # 持久化登录态目录(会保存 cookies/localStorage)SCREENSHOT_DIR = Path("./screenshots")LOG_DIR = Path("./logs")SCREENSHOT_DIR.mkdir(exist_ok=True)LOG_DIR.mkdir(exist_ok=True)LOG_FILE = LOG_DIR / "jianghu_checkin.log"def setup_logger() -> logging.Logger:logger = logging.getLogger("jianghu_checkin")logger.setLevel(logging.INFO)logger.handlers.clear()fmt = logging.Formatter("%(asctime)s | %(levelname)s | %(message)s")fh = logging.FileHandler(LOG_FILE, encoding="utf-8")fh.setFormatter(fmt)sh = logging.StreamHandler(sys.stdout)sh.setFormatter(fmt)logger.addHandler(fh)logger.addHandler(sh)return loggerlogger = setup_logger()def now_str() -> str:return datetime.now().strftime("%Y%m%d_%H%M%S")def shot(page: Page, name: str) -> str:path = SCREENSHOT_DIR / f"{now_str()}_{name}.png"try:page.screenshot(path=str(path), full_page=True)return str(path)except Exception:return ""def wait_for_user_login(page: Page, max_wait_sec: int = 180) -> bool:"""首次运行:给用户时间手动登录简单判断登录成功与否:页面不再是登录态/出现"我的/头像/退出"等典型元素。"""logger.info("首次运行可能需要手动登录:请在打开的浏览器里完成淘宝登录(扫码/验证等)")deadline = time.time() + max_wait_sec# 你也可以把这里的判断逻辑改成"某个登录后才出现的元素"login_success_keywords = ["退出", "我的", "消息", "个人中心", "设置"]while time.time() < deadline:try:html = page.content()if any(k in html for k in login_success_keywords):logger.info("检测到疑似登录成功的页面特征。")return Trueexcept Exception:passtime.sleep(2)logger.warning("等待手动登录超时:可能尚未登录成功。你可以重新运行脚本或延长等待时间。")return Falsedef open_site(context: BrowserContext) -> Page:page = context.new_page()page.set_default_timeout(30_000)page.goto(BASE_URL, wait_until="domcontentloaded")return pagedef try_click_candidates(page: Page, selectors: List[str]) -> Optional[str]:"""依次尝试点击候选元素,成功返回命中的 selector,否则返回 None"""for sel in selectors:try:el = page.locator(sel).firstif el.count() == 0:continueif not el.is_visible():continueel.click(timeout=5_000)return selexcept PWTimeoutError:continueexcept Exception:continuereturn Nonedef do_checkin(page: Page) -> bool:logger.info("开始执行:自动寻找签到入口并尝试签到…")# 尝试等待页面加载更充分一点(很多站点是 SPA)time.sleep(3)# 入口候选entry_selectors = ["text=签到","text=打卡","text=任务","text=福利","text=领取","a:has-text('签到')","button:has-text('签到')","[role=button]:has-text('签到')","a:has-text('任务')","button:has-text('任务')",]hit = try_click_candidates(page, entry_selectors)if hit:logger.info(f"已点击入口:{hit}")time.sleep(2)else:logger.info("在当前页面直接找签到按钮。")# 签到按钮候选(点击后可能弹窗/跳转)checkin_selectors = ["text=立即签到","text=签到领取","text=签到","text=打卡","text=领取","text=一键领取","button:has-text('签到')","button:has-text('领取')","a:has-text('签到')","[role=button]:has-text('签到')",]hit2 = try_click_candidates(page, checkin_selectors)if hit2:logger.info(f"已点击签到/领取按钮:{hit2}")time.sleep(3)else:logger.warning("未找到可点击的签到/领取按钮。建议:用开发者工具确认按钮文本/选择器后,补充到列表里。")return False# 粗略成功判断:出现"已签到/成功/领取成功"等success_keywords = ["已签到", "签到成功", "领取成功", "成功", "明天再来", "今日已签到", "已打卡"]try:html = page.content()if any(k in html for k in success_keywords):logger.info("页面出现成功关键词,判定:签到可能成功 ✅")return Trueexcept Exception:pass# 兜底:尝试截一张图供你人工确认ss = shot(page, "after_checkin")logger.info(f"未能从文本确认结果,已截图供人工确认:{ss}")return True # 很多站点成功提示在 canvas/图片里,文本抓不到,这里先不硬判失败def run() -> int:headless = os.getenv("HEADLESS", "false").strip().lower() in ("1", "true", "yes", "on")with sync_playwright() as p:browser = p.chromium.launch(headless=headless)context = browser.new_context(viewport={"width": 1280, "height": 800},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"),locale="zh-CN")# 持久化登录态:用 persistent_context 更稳,这里用"手动保存 storage_state"的方式也可# 为了兼容性:我们用 storage_state 文件保存storage_state_file = USER_DATA_DIR / "storage_state.json"USER_DATA_DIR.mkdir(exist_ok=True)if storage_state_file.exists():try:state = json.loads(storage_state_file.read_text(encoding="utf-8"))context.add_cookies(state.get("cookies", []))# localStorage/sessionStorage 需要在特定 origin 下恢复,复杂一些;cookies 已能覆盖很多场景logger.info("已加载历史登录态(cookies)。")except Exception as e:logger.warning(f"加载历史登录态失败,将按首次流程进行:{e}")page = open_site(context)# 如果没有登录态,给用户手动登录机会if not storage_state_file.exists():logger.info("未检测到历史登录态文件,将进入首次手动登录流程。")ok = wait_for_user_login(page, max_wait_sec=180)ss = shot(page, "first_login_end")logger.info(f"首次流程截图:{ss}")if not ok:logger.error("未检测到登录成功特征,脚本退出(你可重新运行并完成登录)。")browser.close()return 1# 保存 cookies(以及 storage_state 的 cookies 部分)try:state = {"cookies": context.cookies()}storage_state_file.write_text(json.dumps(state, ensure_ascii=False, indent=2), encoding="utf-8")logger.info(f"登录态已保存:{storage_state_file.resolve()}")except Exception as e:logger.warning(f"保存登录态失败:{e}")# 执行签到try:success = do_checkin(page)ss = shot(page, "final")logger.info(f"执行结束截图:{ss}")logger.info(f"签到结果:{'成功/已处理' if success else '失败'}")return 0 if success else 2except Exception as e:logger.error(f"签到过程异常:{e}")logger.error(traceback.format_exc())ss = shot(page, "exception")logger.info(f"异常截图:{ss}")return 3finally:context.close()browser.close()if __name__ == "__main__":sys.exit(run())
该脚本为淘江湖自动签到脚本,主要作用包括:
持久化登录态:第一次你手动登录淘宝,脚本把 cookies 保存到本地,后续运行直接复用登录态。
自动找"签到/任务/福利/领取"入口:因为不同页面/活动入口不固定,脚本用"候选选择器列表"做通用匹配。
执行签到动作并记录结果:点击后尝试从页面关键词判断是否成功,同时截图 + 写日志,便于你排查和定制。
主要方法
wait_for_user_login(page, max_wait_sec)作用:首次运行等待你手动登录,脚本不碰验证码/风控。
做法:循环读取页面内容,检测"我的/退出/消息"等常见登录后关键词。
do_checkin(page)作用:核心签到流程。
做法:
先尝试点击"任务/福利/签到"等入口
再尝试点击"立即签到/签到/领取"等按钮
用"已签到/成功"等关键词做粗判断,并截图兜底
try_click_candidates(page, selectors)作用:把"自动化点击"封装成通用能力。
做法:按顺序尝试多个 selector,只要有一个可见可点就点击并返回命中的 selector。
storage_state_file(登录态保存)作用:把 cookies 写入
./user_data/storage_state.json,让后续运行免登录。注意:有些淘宝页面还会校验更多参数(比如 localStorage),如果你发现 cookies 不够用,我可以把脚本升级为 persistent_context(真正的用户数据目录)模式,更稳。
注意:
本文部分变量已做脱敏处理,仅用于测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。技术层面需要提供帮助,可以通过打赏的方式进行探讨。
没有评论:
发表评论