2026年1月31日星期六

New 3DFSH Forum Auto-Sign-in Script Guide and Code

Summary: Script automates login and daily sign-in for 3dfsh.com forum. It reuses login sessions, scans for sign-in buttons, saves screenshots for debugging. Requires setting username/password as environment variables FSH_USERNAME and FSH_PASSWORD. Includes server purchase links and deployment tutorial.

1.购买服务器

阿里云:

服务器购买地址

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=201905

2.部署教程

2024年最新青龙面板跑脚本教程(一)持续更新中

3.代码如下

# -*- coding: utf-8 -*-
import osimport reimport timefrom pathlib import Pathfrom typing import OptionalListTuple
from playwright.sync_api import sync_playwright, Page, BrowserContext

BASE_URL = "https://www.3dfsh.com/"STORAGE_STATE = Path("storage_state_3dfsh.json")SCREENSHOT_DIR = Path("screenshots_3dfsh")SCREENSHOT_DIR.mkdir(exist_ok=True)
# 环境变量(你需要自行配置)ENV_USER = "FSH_USERNAME"ENV_PASS = "FSH_PASSWORD"

def now_ts() -> str:    return time.strftime("%Y%m%d_%H%M%S", time.localtime())

def log(msg: str):    print(f"[{time.strftime('%H:%M:%S')}{msg}")

def get_env_credential() -> Tuple[strstr]:    username = os.getenv(ENV_USER, "").strip()    password = os.getenv(ENV_PASS, "").strip()    if not username or not password:        raise RuntimeError(            f"缺少账号密码环境变量:{ENV_USER}/{ENV_PASS}\n"            f"Windows PowerShell 示例:\n"            f"  setx {ENV_USER} \"你的账号\"\n"            f"  setx {ENV_PASS} \"你的密码\"\n"            f"macOS/Linux 示例:\n"            f"  export {ENV_USER}='你的账号'\n"            f"  export {ENV_PASS}='你的密码'\n"        )    return username, password

def new_context(pw, headless: bool) -> BrowserContext:    browser = pw.chromium.launch(headless=headless)    if STORAGE_STATE.exists():        log("检测到历史登录态 storage_state,尝试复用免登录")        ctx = browser.new_context(storage_state=str(STORAGE_STATE))    else:        ctx = browser.new_context()    ctx.set_default_timeout(30_000)    return ctx

def is_logged_in(page: Page) -> bool:    # Discuz 常见:已登录会出现"退出/注销/设置/消息"等    html = page.content()    keywords = ["退出""注销""设置""消息""提醒"]    hit = sum(1 for k in keywords if k in html)    return hit >= 2

def try_login(page: Page, username: str, password: str) -> bool:    """    兼容 Discuz 常见登录入口:    - 点击"登录"    - 或直接访问 member.php?mod=logging&action=login    """    log("开始尝试登录…")    page.goto(BASE_URL, wait_until="domcontentloaded")    page.wait_for_timeout(1200)
    if is_logged_in(page):        log("当前页面判断:已登录(跳过登录)")        return True
    # 1) 尝试点页面上的"登录"    login_clicked = False    for sel in [        "text=登录",        "a:has-text('登录')",        "text=立即登录",    ]:        loc = page.locator(sel)        if loc.count() > 0:            try:                loc.first.click(timeout=3000)                login_clicked = True                break            except Exception:                pass
    # 2) 如果点不到,直接走 Discuz 登录页    if not login_clicked:        login_url = BASE_URL.rstrip("/") + "/member.php?mod=logging&action=login"        log(f"未找到明显登录按钮,直达登录页:{login_url}")        page.goto(login_url, wait_until="domcontentloaded")
    page.wait_for_timeout(1200)
    # Discuz 登录框常见 name:username / password    user_candidates = ["input[name='username']""input[name='email']""input[type='text']"]    pass_candidates = ["input[name='password']""input[type='password']"]
    user_filled = False    for sel in user_candidates:        loc = page.locator(sel)        if loc.count() > 0:            try:                loc.first.fill(username)                user_filled = True                break            except Exception:                pass
    pass_filled = False    for sel in pass_candidates:        loc = page.locator(sel)        if loc.count() > 0:            try:                loc.first.fill(password)                pass_filled = True                break            except Exception:                pass
    if not user_filled or not pass_filled:        page.screenshot(path=str(SCREENSHOT_DIR / f"login_form_not_found_{now_ts()}.png"))        log("未识别到登录输入框,已截图。可能站点结构/编码特殊或需要手动登录一次生成登录态。")        return False
    # 提交按钮:常见是 name=loginsubmit 或者"登录"    submitted = False    for sel in [        "button[name='loginsubmit']",        "button:has-text('登录')",        "input[name='loginsubmit']",        "input[type='submit']",        "text=登录并继续",    ]:        loc = page.locator(sel)        if loc.count() > 0:            try:                loc.first.click()                submitted = True                break            except Exception:                pass
    if not submitted:        # 兜底:回车提交        page.keyboard.press("Enter")
    page.wait_for_timeout(2500)
    # 有些站点会跳回首页    try:        page.goto(BASE_URL, wait_until="domcontentloaded")        page.wait_for_timeout(1500)    except Exception:        pass
    if is_logged_in(page):        log("登录成功 ✅")        return True
    # 可能遇到验证码/风控    page.screenshot(path=str(SCREENSHOT_DIR / f"login_failed_{now_ts()}.png"))    log("登录失败 ❌(可能需要验证码/安全验证),已截图。建议:先用非无头模式手动登录一次。")    return False

def collect_possible_signin_urls() -> List[str]:    """    Discuz 常见签到插件入口(不同站点不一定都装)    """    base = BASE_URL.rstrip("/")    candidates = [        f"{base}/plugin.php?id=dsu_paulsign:sign",        f"{base}/plugin.php?id=k_misign:sign",        f"{base}/plugin.php?id=dsu_paulsign",        f"{base}/plugin.php?id=k_misign",        f"{base}/home.php?mod=spacecp&ac=credit&op=base",  # 有些站签到在积分页/任务页    ]    return candidates

def find_signin_link_in_page(page: Page) -> Optional[str]:    """    从页面里扫描"签到/打卡"链接    """    html = page.content()    # 粗扫:找包含"签到"的 href    matches = re.findall(r'href="([^"]+)"[^>]*>([^<]{0,20}签到[^<]{0,20})', html)    for href, text in matches[:20]:        if "javascript:" in href:            continue        # 补全相对路径        if href.startswith("//"):            href = "https:" + href        elif href.startswith("/"):            href = BASE_URL.rstrip("/") + href        elif not href.startswith("http"):            href = BASE_URL.rstrip("/") + "/" + href.lstrip("./")        log(f"发现页面签到候选链接:{text.strip()} => {href}")        return href    return None

def try_sign_in(page: Page) -> bool:    """    尝试执行签到:    - 先尝试常见插件 URL    - 再从页面扫描"签到"入口    - 最后在签到页尝试点击"签到/打卡/立即签到"    """    log("开始尝试签到…")
    # 先打开首页    page.goto(BASE_URL, wait_until="domcontentloaded")    page.wait_for_timeout(1200)
    # 1) 先试固定候选入口    for url in collect_possible_signin_urls():        try:            log(f"尝试签到入口:{url}")            page.goto(url, wait_until="domcontentloaded")            page.wait_for_timeout(1500)
            if click_sign_button(page):                page.screenshot(path=str(SCREENSHOT_DIR / f"signin_ok_{now_ts()}.png"))                log("签到执行完成 ✅(已截图)")                return True        except Exception:            continue
    # 2) 扫描页面"签到"链接再试    page.goto(BASE_URL, wait_until="domcontentloaded")    page.wait_for_timeout(1200)    link = find_signin_link_in_page(page)    if link:        try:            page.goto(link, wait_until="domcontentloaded")            page.wait_for_timeout(1500)            if click_sign_button(page):                page.screenshot(path=str(SCREENSHOT_DIR / f"signin_ok_{now_ts()}.png"))                log("签到执行完成 ✅(已截图)")                return True        except Exception:            pass
    page.screenshot(path=str(SCREENSHOT_DIR / f"signin_failed_{now_ts()}.png"))    log("未能完成签到 ❌(已截图)。可能:站点无签到/需要手动验证码/入口变化。")    return False

def click_sign_button(page: Page) -> bool:    """    在当前页面尝试点击签到按钮/提交签到表单    """    # 一些签到页会有"签到/打卡/立即签到/一键签到"    candidates = [        "text=签到",        "text=打卡",        "text=立即签到",        "text=一键签到",        "button:has-text('签到')",        "a:has-text('签到')",        "input[type='submit']",    ]
    for sel in candidates:        loc = page.locator(sel)        if loc.count() > 0:            try:                # 避免误点导航"签到",优先点可见元素                loc.first.scroll_into_view_if_needed()                loc.first.click(timeout=3000)                page.wait_for_timeout(1500)
                # 简单判断:页面出现"已签到/签到成功/已打卡"                html = page.content()                success_keywords = ["签到成功""已签到""今日已签到""打卡成功""已打卡"]                if any(k in html for k in success_keywords):                    log("检测到成功关键词:可能已签到/签到成功")                    return True
                # 有些站点点击后无明显提示,也当作尝试成功(给出截图)                log(f"已点击可能的签到按钮:{sel}(未检测到明确成功词,仍可能成功)")                return True            except Exception:                continue
    return False

def save_storage(context: BrowserContext):    try:        context.storage_state(path=str(STORAGE_STATE))        log(f"已保存登录态:{STORAGE_STATE}")    except Exception as e:        log(f"保存登录态失败:{e}")

def main():    username, password = get_env_credential()    headless = os.getenv("HEADLESS""true").strip().lower() not in ["0""false""off"]
    with sync_playwright() as pw:        ctx = new_context(pw, headless=headless)        page = ctx.new_page()
        ok = try_login(page, username, password)        if not ok:            log("登录未成功,退出。你可以设置 HEADLESS=false 先手动登录一次。")            ctx.close()            return
        save_storage(ctx)
        # 执行签到        sign_ok = try_sign_in(page)        if sign_ok:            log("流程结束:签到完成 🎉")        else:            log("流程结束:签到失败(请结合截图排查)")
        ctx.close()

if __name__ == "__main__":    main()
解析
该脚本为百姓生活论坛自动签到脚本,主要作用包括:
  • 自动登录百姓生活论坛(3dfsh.com)

  • 自动复用历史登录态(storage_state_3dfsh.json),减少重复登录

  • 自动执行"签到/打卡"

    • 优先尝试 Discuz 常见签到插件入口

    • 如果入口变化,则扫描页面中包含"签到"的链接再尝试

  • 结果截图落地(screenshots_3dfsh/),便于定位"验证码/风控/入口变更"

主要方法

  • get_env_credential → 从环境变量读取账号密码(FSH_USERNAME/FSH_PASSWORD),缺失则直接报错提示配置方式

  • new_context → 创建 Playwright 浏览器上下文;如果有 storage_state_3dfsh.json 就加载以复用登录态

  • is_logged_in → 通过页面关键字(退出/注销/设置/消息等)粗略判断当前是否已登录

  • try_login → 自动完成登录流程:优先点击"登录",不行则直达 Discuz 登录页,填表提交并判断是否登录成功

  • collect_possible_signin_urls → 生成常见 Discuz 签到插件的候选入口 URL 列表

  • find_signin_link_in_page → 在页面 HTML 中扫描包含"签到"的链接并返回第一个可用入口

  • try_sign_in → 统一签到流程:依次尝试候选入口、页面扫描入口,并调用点击逻辑完成签到

  • click_sign_button → 在签到页面寻找并点击"签到/打卡/立即签到"等按钮,检测"签到成功/已签到"等关键词

  • save_storage → 将当前登录态保存到 storage_state_3dfsh.json,下次运行可免登录

  • main → 主流程入口:读取配置 → 启动浏览器 → 登录 → 保存登录态 → 签到 → 输出结果并退出



注意

本文部分变量已做脱敏处理,仅用于测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。技术层面需要提供帮助,可以通过打赏的方式进行探讨。


历史脚本txt文件获取>>
服务器搭建,人工服务咨询>>

没有评论:

发表评论

出海网站赚钱秘籍:帮欧美用户提效变现

通过SEO和广告将工具网站推向愿意付费的欧美用户,解决其需求,并接入支付渠道,从而盈利。核心在于:做调研、做网站、做内容、引流量、优体验、接支付。 大家好,我是哥飞。 今天有个非互联网专业的朋友问哥飞,"你们到底怎么赚钱的?适不适合我?" 因为他学的专业的...