2026年1月4日星期日

红豆社区任务脚本

1.购买服务器阿里云:服务器购买地址https://t.aliyun.com/U/55RK8C若失效,可用地址

1.购买服务器

阿里云:

服务器购买地址

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

2.部署教程

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

3.代码如下

# -*- coding: utf-8 -*-

import osimport reimport sysimport timeimport randomfrom dataclasses import dataclassfrom typing import OptionalDictTupleList
import requests

@dataclassclass SignResult:    ok: bool    status: str          # success / already / failed    message: str    detail: str = ""

class HongdouAutoSign:    def __init__(self, base_url: str, username: str, password: str, ua: Optional[str] = None, timeout: int = 20):        self.base_url = base_url.rstrip("/")        self.username = username        self.password = password        self.timeout = timeout
        self.session = requests.Session()        self.session.headers.update({            "User-Agent": ua or os.getenv("HONGDOU_UA""Mozilla/5.0 (Windows NT 10.0; Win64; x64) "                                                      "AppleWebKit/537.36 (KHTML, like Gecko) "                                                      "Chrome/122.0.0.0 Safari/537.36"),            "Accept""text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",            "Accept-Language""zh-CN,zh;q=0.9",            "Connection""keep-alive",        })
    # ---------- 基础工具方法 ----------    def _get(self, path: str, **kwargs) -> requests.Response:        url = path if path.startswith("http"else f"{self.base_url}{path}"        resp = self.session.get(url, timeout=self.timeout, **kwargs)        resp.raise_for_status()        return resp
    def _post(self, path: str, data=None, headers=None, **kwargs) -> requests.Response:        url = path if path.startswith("http"else f"{self.base_url}{path}"        resp = self.session.post(url, data=data, headers=headers, timeout=self.timeout, **kwargs)        resp.raise_for_status()        return resp
    @staticmethod    def _guess_encoding(resp: requests.Response) -> str:        # Discuz老站可能是 GBK,requests 默认可能不准,做个兜底        # 不强制依赖 chardet,优先用 apparent_encoding        enc = (getattr(resp, "apparent_encoding"Noneor resp.encoding or "utf-8").lower()        return enc
    @staticmethod    def (html_text: str) -> Optional[str]:        # 常见:name="formhash" value="xxxx"        m = re.search(r'name="formhash"\s+value="([^"]+)"', html_text)        if m:            return m.group(1)        # 或者:formhash=xxxx        m = re.search(r"formhash=([0-9a-zA-Z]+)", html_text)        return m.group(1if m else None
    @staticmethod    def _extract_loginhash(html_text: str) -> Optional[str]:        # 常见:loginhash=xxxx        m = re.search(r"loginhash=([0-9a-zA-Z]+)", html_text)        return m.group(1if m else None
    @staticmethod    def _contains_any(text: str, keywords: List[str]) -> bool:        return any(k in text for k in keywords)
    # ---------- 核心流程方法 ----------    def fetch_home_tokens(self) -> Tuple[Optional[str], Optional[str], str]:        """        访问首页,提取 loginhash / formhash,用于登录。        返回:(loginhash, formhash, html_text)        """        resp = self._get("/")        enc = self._guess_encoding(resp)        resp.encoding = enc        html_text = resp.text
        loginhash = self._extract_loginhash(html_text)        formhash = self._extract_formhash(html_text)        return loginhash, formhash, html_text
    def login(self) -> SignResult:        """        执行登录:Discuz 标准登录接口 member.php?mod=logging&action=login&loginsubmit=yes...        """        loginhash, formhash, _ = self.fetch_home_tokens()
        # 有些站点首页未必包含 loginhash/formhash,我们再访问一次登录页兜底        if not loginhash or not formhash:            resp = self._get("/member.php?mod=logging&action=login")            resp.encoding = self._guess_encoding(resp)            html_text = resp.text            loginhash = loginhash or self._extract_loginhash(html_text)            formhash = formhash or self._extract_formhash(html_text)
        if not formhash:            return SignResult(False"failed""无法提取 formhash(站点结构可能不同/被防护拦截)")
        loginhash_q = f"&loginhash={loginhash}" if loginhash else ""        login_url = f"/member.php?mod=logging&action=login&loginsubmit=yes{loginhash_q}&inajax=1"
        data = {            "username"self.username,            "password"self.password,            "cookietime""2592000",            "quickforward""yes",            "handlekey""ls",            "formhash": formhash,        }
        # Discuz 登录常见需要这个        headers = {            "Content-Type""application/x-www-form-urlencoded; charset=UTF-8",            "X-Requested-With""XMLHttpRequest",            "Referer"f"{self.base_url}/member.php?mod=logging&action=login",        }
        try:            resp = self._post(login_url, data=data, headers=headers)        except Exception as e:            return SignResult(False"failed"f"登录请求失败:{e}")
        # 登录响应经常是 html/xml片段        txt = resp.text
        # 常见成功标志:欢迎您回来 / 登录成功 / window.location / succeedhandle_ls        if self._contains_any(txt, ["欢迎您回来""登录成功""succeedhandle_ls""window.location"]):            return SignResult(True"success""登录成功")
        # 常见失败标志        if self._contains_any(txt, ["密码错误""登录失败""security code""验证码""请输入验证码"]):            return SignResult(False"failed""登录失败:可能需要验证码/密码错误/安全校验", detail=txt[:500])
        # 兜底:再访问一次首页,看是否已登录(例如出现"退出")        try:            home = self._get("/")            home.encoding = self._guess_encoding(home)            if self._contains_any(home.text, ["退出""注销""欢迎您回来""设置"]):                return SignResult(True"success""登录成功(通过首页二次确认)")        except Exception:            pass
        return SignResult(False"failed""登录状态不明确,可能登录失败或站点返回结构不同", detail=txt[:500])
    def detect_sign_entry(self) -> Optional[str]:        """        探测签到入口:尝试常见 Discuz 签到插件路径,返回可用的 path(带参数)或 None        """        candidates = [            "/plugin.php?id=dsu_paulsign:sign",            "/plugin.php?id=dsu_paulsign:sign&operation=qiandao",            "/plugin.php?id=dsu_paulsign:sign&operation=qiandao&inajax=1",            "/plugin.php?id=k_misign:sign",            "/plugin.php?id=k_misign:sign&operation=qiandao",        ]
        for path in candidates:            try:                resp = self._get(path)                resp.encoding = self._guess_encoding(resp)                text = resp.text
                # 命中一些常见的签到页面特征                if self._contains_any(text, ["签到""今日已签到""您今天已经签到""dsu_paulsign""k_misign""qiandao"]):                    return path            except Exception:                continue
        return None
    def submit_signin(self, sign_entry: str) -> SignResult:        """        提交签到:        - 先 GET 签到页拿 formhash        - 再 POST 提交(以 dsu_paulsign 常见参数为主)        """        try:            page = self._get(sign_entry)            page.encoding = self._guess_encoding(page)            html_text = page.text        except Exception as e:            return SignResult(False"failed"f"打开签到页失败:{e}")
        # 已签到判定        if self._contains_any(html_text, ["今日已签到""您今天已经签到""已经签过""已签到"]):            return SignResult(True"already""今日已签到")
        formhash = self._extract_formhash(html_text)        if not formhash:            # 有些站点在源码里 formhash=xxxx            formhash = self._extract_formhash(html_text)
        if not formhash:            return SignResult(False"failed""签到页未提取到 formhash,可能需要调整入口或站点有防护")
        # 提交地址:dsu_paulsign 通常是同一个 plugin.php?id=... 带 operation=qiandao&inajax=1        # 若 entry 没带 operation,就补齐        post_path = sign_entry        if "operation=qiandao" not in post_path:            if "?" in post_path:                post_path += "&operation=qiandao"            else:                post_path += "&operation=qiandao"        if "inajax=1" not in post_path:            post_path += "&inajax=1"
        # dsu_paulsign 常用表单参数(站点可能略有不同,但大多数兼容)        # qdxq:心情,qdmode:签到模式        payload = {            "formhash": formhash,            "qdxq""fd",          # 心情:fd/yl/kx... 不同站点定义不同,fd常见可用            "qdmode""3",         # 1/2/3 常见:快速签到            "todaysay""日常签到",            "fastreply""0",        }        headers = {            "Content-Type""application/x-www-form-urlencoded; charset=UTF-8",            "X-Requested-With""XMLHttpRequest",            "Referer"f"{self.base_url}{sign_entry}",        }
        try:            resp = self._post(post_path, data=payload, headers=headers)            txt = resp.text        except Exception as e:            return SignResult(False"failed"f"签到提交失败:{e}")
        # 成功/已签到关键词判定        if self._contains_any(txt, ["签到成功""恭喜""您已签到""成功""已签到""已经签到"]):            return SignResult(True"success""签到成功", detail=txt[:400])
        if self._contains_any(txt, ["今日已签到""您今天已经签到""已经签过"]):            return SignResult(True"already""今日已签到", detail=txt[:400])
        if self._contains_any(txt, ["未登录""先登录""login""权限不足"]):            return SignResult(False"failed""签到失败:疑似未登录或权限不足", detail=txt[:400])
        return SignResult(False"failed""签到失败:返回内容未命中成功特征,可能需要定制参数/入口", detail=txt[:600])
    def run(self) -> SignResult:        """        一键执行:登录 -> 探测签到入口 -> 提交签到        """        login_res = self.login()        if not login_res.ok:            return login_res
        time.sleep(random.uniform(1.22.2))
        entry = self.detect_sign_entry()        if not entry:            return SignResult(False"failed""未探测到可用签到入口:站点可能非Discuz或签到插件路径不同")
        time.sleep(random.uniform(0.81.6))        return self.submit_signin(entry)

def main():    base_url = os.getenv("HONGDOU_BASE_URL""https://hongdou.gxnews.com.cn")    username = os.getenv("HONGDOU_USERNAME")    password = os.getenv("HONGDOU_PASSWORD")
    if not username or not password:        print("❌ 缺少环境变量:HONGDOU_USERNAME / HONGDOU_PASSWORD")        print("示例:")        print("export HONGDOU_USERNAME='你的账号'")        print("export HONGDOU_PASSWORD='你的密码'")        sys.exit(1)
    bot = HongdouAutoSign(base_url=base_url, username=username, password=password)    res = bot.run()
    print("=" * 60)    print(f"站点:{base_url}")    print(f"结果:{res.status}")    print(f"信息:{res.message}")    if res.detail:        print("-" * 60)        print("返回片段(用于排查/适配):")        print(res.detail)    print("=" * 60)
    sys.exit(0 if res.ok else 2)

if __name__ == "__main__":    main()
解析

该脚本为红豆社区自动签到脚本,主要作用包括:

  1. 自动登录红豆社区(通过 Discuz 常见登录接口 member.php?mod=logging&action=login)。

  2. 自动探测"签到插件入口"(不同论坛可能用不同插件,脚本按候选路径逐个尝试)。

  3. 自动提交签到请求(获取签到页的 formhash,再 POST 提交签到表单)。

  4. 输出明确结果:成功 / 已签到 / 失败原因(并附带返回片段,便于你二次适配)。

主要方法

fetch_home_tokens()

  • 作用:访问首页,提取 Discuz 常见的两个关键值:

    • loginhash:登录流程里经常要带的参数(有些站点会有,有些没有)

    • formhash:Discuz 防 CSRF 的核心字段(登录、签到通常必需)

  • 意义:没有 formhash,大概率无法提交登录/签到表单。

login()

  • 作用:执行登录动作

    1. 优先从首页提取 token;不够则访问登录页再提取

    2. POST 到 member.php?mod=logging&action=login&loginsubmit=yes...

    3. 通过返回内容关键字判断是否登录成功(或回首页二次确认)

  • 意义:把 Session 的 cookie 建立好,后续探测签到入口、提交签到才能带登录态。

detect_sign_entry()

  • 作用:探测签到入口

    • plugin.php?id=dsu_paulsign:sign...(Discuz 最常见签到插件之一)

    • plugin.php?id=k_misign:sign...(另一个常见签到插件)

    • 依次 GET 常见的签到插件路径:

    • 命中页面包含"签到/已签到/插件标记"等字样就认为可用

  • 意义:不同论坛插件不同,你又没提供具体签到路径时,这个方法能最大化自动适配。

submit_signin(sign_entry)

  • 作用:真正执行签到提交

    1. GET 签到页面,判断是否已签到

    2. 解析 formhash

    3. POST 提交签到(qdxq/qdmode/todaysay... 这些是 dsu_paulsign 常见参数)

    4. 根据返回内容判断 "签到成功/已签到/失败"

  • 意义:把签到动作封装成可复用模块,后续你要扩展"领积分/领礼包/做任务",也可以按这个模式继续加。

run()

  • 作用:把流程串起来:登录 → 探测入口 → 签到提交 → 返回最终结果

  • 意义:对外只暴露一个"执行入口",方便青龙/cron 调用。


注意

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


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

没有评论:

发表评论

数字游民 :低成本工作室 :云手机,无人直播Tiktok/Youtube,赚美金 (13)

数字游民: 分布式团队   分布式团队 协同办公 数字游民也好,一人公司也罢,并不意味着单打独斗, 众包/兼职/雇佣 等,都是一种人力资源策略 包括前面提到的 UGC (用户产生内容),以及 异业合作 等 有人的流程,就需要沟通,就需要协作,如果人数达到团队的标准,就必要进行...