2026年1月21日星期三

Sichuan Tianfu Community Auto-Sign Script

This Python script automates daily sign-in on a Sichuan community forum. It logs in via environment variables (username/password or cookie), detects sign-in links, and submits forms. The script supports fallback paths for common Discuz plugins and outputs sign-in results.

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 sysimport timeimport jsonimport requestsfrom bs4 import BeautifulSoupfrom urllib.parse import urljoin, urlparse, parse_qs
BASE_URL = "https://bbs.scol.com.cn/"TIMEOUT = 15

class ScolAutoSign:    def __init__(self):        self.username = os.getenv("SCOL_USERNAME""").strip()        self.password = os.getenv("SCOL_PASSWORD""").strip()        self.cookie_str = os.getenv("SCOL_COOKIE""").strip()
        self.session = requests.Session()        self.session.headers.update({            "User-Agent": (                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "                "AppleWebKit/537.36 (KHTML, like Gecko) "                "Chrome/124.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",        })
        # 如果用户提供 cookie,则直接注入        if self.cookie_str:            self._inject_cookie(self.cookie_str)
    # ------------------ 基础工具 ------------------
    def _inject_cookie(self, cookie_str: str):        """把 'a=1; b=2' 写入 requests.Session cookies"""        cookies = {}        for part in cookie_str.split(";"):            part = part.strip()            if not part or "=" not in part:                continue            k, v = part.split("="1)            cookies[k.strip()] = v.strip()        self.session.cookies.update(cookies)
    def _get(self, url: str, **kwargs) -> requests.Response:        return self.session.get(url, timeout=TIMEOUT, **kwargs)
    def _post(self, url: str, data=None, **kwargs) -> requests.Response:        return self.session.post(url, data=data, timeout=TIMEOUT, **kwargs)
    def _soup(self, html: str) -> BeautifulSoup:        return BeautifulSoup(html, "lxml")
    def _extract_formhash(self, html: str) -> str:        """        Discuz 常见 formhash 提取方式:        - <input type="hidden" name="formhash" value="xxx">        - 或 JS 变量里出现 formhash=xxx        """        m = re.search(r'name="formhash"\s+value="([^"]+)"', html)        if m:            return m.group(1)
        m = re.search(r"formhash=([0-9a-zA-Z]+)", html)        if m:            return m.group(1)
        return ""
    def _is_logged_in(self, html: str) -> bool:        """        粗略判断是否已登录:        - 页面里出现 "退出/注销/登录后可见/欢迎您"        - 或 Discuz 常见 "退出"链接        """        keywords = ["退出""注销""欢迎您""设置""消息""积分"]        hit = sum(1 for k in keywords if k in html)        if hit >= 2:            return True        # 有些 Discuz 会有 logout 链接        if re.search(r"action=logout", html):            return True        return False
    # ------------------ 登录相关 ------------------
    def fetch_home(self) -> str:        """拉取首页 HTML"""        resp = self._get(BASE_URL)        resp.encoding = resp.apparent_encoding or "utf-8"        return resp.text
    def login_if_needed(self) -> bool:        """        若 cookie 已登录则跳过;        若没登录则用用户名密码进行 Discuz 登录尝试。        """        home_html = self.fetch_home()        if self._is_logged_in(home_html):            print("✅ 已处于登录态(Cookie有效或已登录)")            return True
        if not (self.username and self.password):            print("❌ 未登录,且未提供 SCOL_USERNAME / SCOL_PASSWORD(也没有可用 Cookie)")            return False
        # Discuz 登录入口通常是 member.php?mod=logging&action=login        login_page = urljoin(BASE_URL, "member.php?mod=logging&action=login")        resp = self._get(login_page)        resp.encoding = resp.apparent_encoding or "utf-8"        html = resp.text
        formhash = self._extract_formhash(html)        if not formhash:            print("❌ 未能从登录页提取 formhash,可能站点做了特殊处理/风控")            return False
        # Discuz 登录提交一般是:        # member.php?mod=logging&action=login&loginsubmit=yes&infloat=yes&lssubmit=yes        login_submit = urljoin(            BASE_URL,            "member.php?mod=logging&action=login&loginsubmit=yes&infloat=yes&lssubmit=yes"        )
        data = {            "formhash": formhash,            "referer": BASE_URL,            "username"self.username,            "password"self.password,            "questionid""0",            "answer""",        }
        # 有的站点要求带 Cookie/Referer        headers = {"Referer": login_page}
        r2 = self._post(login_submit, data=data, headers=headers)        r2.encoding = r2.apparent_encoding or "utf-8"        text2 = r2.text
        # 登录后再拉首页验证        home_html2 = self.fetch_home()        if self._is_logged_in(home_html2):            print("✅ 登录成功")            return True
        # Discuz 可能返回 XML/JS,尝试从返回里找错误提示        err = self._extract_login_error(text2) or "登录失败(可能需要验证码/二次验证/账号密码不正确)"        print(f"❌ 登录失败:{err}")        return False
    def _extract_login_error(self, html: str) -> str:        """从登录返回中粗略提取错误信息"""        # Discuz 常见错误片段:<p>抱歉,您尚未登录,没有权限访问该页面</p>        soup = self._soup(html)        text = soup.get_text(" ", strip=True)        # 取一段较短的        if "密码" in text or "错误" in text or "验证码" in text or "登录" in text:            return text[:120]        return ""
    # ------------------ 签到相关 ------------------
    def discover_signin_url(self) -> str:        """        从页面自动发现"签到"入口:        - 首页/任务页里 a 标签文本包含:签到/打卡/每日签到        - 或 href 包含:sign / misign / paulsign / checkin        """        html = self.fetch_home()        soup = self._soup(html)
        candidates = []        for a in soup.find_all("a", href=True):            text = (a.get_text() or "").strip()            href = a["href"].strip()
            if any(k in text for k in ["签到""打卡""每日签到"]):                candidates.append(href)                continue
            if re.search(r"(misign|paulsign|checkin|sign)", href, re.I):                candidates.append(href)
        # 去重并补全        seen = set()        cleaned = []        for href in candidates:            full = urljoin(BASE_URL, href)            if full not in seen:                seen.add(full)                cleaned.append(full)
        if cleaned:            # 取最像 Discuz 插件的那种            for u in cleaned:                if "plugin.php" in u or "misign" in u or "paulsign" in u:                    return u            return cleaned[0]
        return ""
    def signin(self) -> tuple[boolstr]:        """        执行签到:        1) 尝试自动发现签到入口        2) 如果发现失败,则 fallback 常见 Discuz 签到插件 URL        3) 自动提取 formhash 并提交        """        # 先尝试自动发现入口        signin_entry = self.discover_signin_url()        if signin_entry:            ok, msg = self._try_signin_by_entry(signin_entry)            if ok:                return True, msg
        # fallback 常见插件路径(不同站点可能不同)        fallbacks = [            urljoin(BASE_URL, "plugin.php?id=k_misign:sign"),            urljoin(BASE_URL, "k_misign-sign.html"),            urljoin(BASE_URL, "plugin.php?id=dsu_paulsign:sign"),            urljoin(BASE_URL, "plugin.php?id=dsu_paulsign:sign&operation=qiandao"),        ]
        last_msg = ""        for u in fallbacks:            ok, msg = self._try_signin_by_entry(u)            last_msg = msg            if ok:                return True, msg
        return False, last_msg or "未找到可用的签到入口(可能站点无签到/需要验证码/路径不一样)"
    def _try_signin_by_entry(self, entry_url: str) -> tuple[boolstr]:        """        对某个疑似签到入口尝试:        - GET 入口页面拿 formhash        - POST 提交(按 Discuz 常见方式)        """        try:            r = self._get(entry_url, headers={"Referer": BASE_URL})            r.encoding = r.apparent_encoding or "utf-8"            html = r.text
            # 若未登录会跳登录页            if "mod=logging" in r.url or "登录" in html and "password" in html:                return Falsef"入口需要登录:{entry_url}"
            formhash = self._extract_formhash(html)            # 有些签到插件直接 GET 一次就完成            if ("签到成功" in html) or ("已签到" in html) or ("今日已" in html):                return Truef"已完成签到(入口直接返回结果):{entry_url}"
            if not formhash:                # 如果没有 formhash,也可能是接口式签到                # 尝试直接 POST event/checkin 之类(尽力而为)                ok, msg = self._try_api_style_sign(entry_url, html)                return ok, msg
            # 尝试构造 POST            post_url = entry_url            if "?" in post_url:                post_url += "&"            else:                post_url += "?"            post_url += "operation=qiandao"
            data = {                "formhash": formhash,                "qdxq""kx",      # 常见:签到心情(开心/难过等),不同插件字段不同                "qdmode""1",     # 常见:签到模式                "todaysay""自动签到",  # 常见:签到留言                "fastreply""0",            }
            r2 = self._post(post_url, data=data, headers={"Referer": entry_url})            r2.encoding = r2.apparent_encoding or "utf-8"            t2 = r2.text
            if any(k in t2 for k in ["签到成功""您今日已经签到""已签到""今日已签到"]):                return Truef"签到成功:{self._short_msg(t2)}"            if any(k in t2 for k in ["权限""未登录""登录""验证码""安全验证"]):                return Falsef"签到被拦截/需要验证:{self._short_msg(t2)}"
            # 再 GET 一次入口看状态            r3 = self._get(entry_url, headers={"Referer": BASE_URL})            r3.encoding = r3.apparent_encoding or "utf-8"            t3 = r3.text            if any(k in t3 for k in ["已签到""今日已""签到成功"]):                return Truef"签到成功(复查确认):{entry_url}"
            return Falsef"签到未成功(站点规则/字段不匹配):{entry_url}"        except Exception as e:            return Falsef"签到尝试异常:{entry_url} -> {e}"
    def _try_api_style_sign(self, entry_url: str, html: str) -> tuple[boolstr]:        """        尽力而为:某些站点签到是按钮触发接口(AJAX),页面里可能出现 endpoint。        这里简单从 html 里抓取包含 sign/checkin 的接口地址尝试 GET/POST。        """        api_candidates = set()
        # 提取类似 "plugin.php?id=xxx&..." 或 "/sign" 的片段        for m in re.findall(r'["\']([^"\']*(?:sign|checkin|misign|paulsign)[^"\']*)["\']', html, flags=re.I):            if len(m) < 6:                continue            if "http" in m:                api_candidates.add(m)            else:                api_candidates.add(urljoin(BASE_URL, m))
        # 加入 entry_url 本身作为候选        api_candidates.add(entry_url)
        for u in list(api_candidates)[:10]:            try:                # 先 GET                r = self._get(u, headers={"Referer": entry_url})                r.encoding = r.apparent_encoding or "utf-8"                t = r.text                if any(k in t for k in ["签到成功""已签到""今日已"]):                    return Truef"签到成功(API/GET):{u}"
                # 再 POST 一个空 body 试试                r2 = self._post(u, data={}, headers={"Referer": entry_url})                r2.encoding = r2.apparent_encoding or "utf-8"                t2 = r2.text                if any(k in t2 for k in ["签到成功""已签到""今日已"]):                    return Truef"签到成功(API/POST):{u}"            except Exception:                continue
        return False"未能通过入口页面推断出可用的签到接口"
    def _short_msg(self, text: str) -> str:        """把返回内容压缩成短信息便于日志展示"""        s = re.sub(r"\s+"" ", text)        return s[:120]
    # ------------------ 主流程 ------------------
    def run(self):        print("=== bbs.scol.com.cn 自动签到脚本启动 ===")        ok_login = self.login_if_needed()        if not ok_login:            print("❌ 登录失败,终止")            sys.exit(1)
        ok, msg = self.signin()        if ok:            print(f"✅ 签到完成:{msg}")            sys.exit(0)        else:            print(f"❌ 签到失败:{msg}")            sys.exit(2)

if __name__ == "__main__":    ScolAutoSign().run()

解析

该脚本为四川天府社区自动签到脚本,主要功能包括:

  • 自动读取环境变量中的账号信息(或 Cookie),登录四川天府社区(Discuz 论坛常见结构)。

  • 自动在页面中发现"签到/打卡"入口并尝试签到;若找不到则按常见 Discuz 签到插件路径进行兜底尝试。

  • 输出签到结果:成功/已签到/需要验证/失败原因等。

主要方法

  • login_if_needed → 判断是否已登录;未登录则用账号密码走 Discuz 登录流程并验证登录态。

  • fetch_home → 拉取论坛首页 HTML,用于判断登录态与发现签到入口。

  • _extract_formhash → 从页面里提取 Discuz 常用的 formhash,用于表单提交(登录/签到常需要)。

  • discover_signin_url → 在首页 HTML 中扫描包含"签到/打卡/每日签到"或包含 misign/paulsign/sign 关键词的链接,自动找到签到入口。

  • signin → 签到主入口:先用自动发现入口签到;失败则使用常见插件路径进行 fallback 尝试。

  • _try_signin_by_entry → 针对某个"可能是签到入口"的 URL:GET 拿页面 + 提取 formhash + POST 提交,最后复查是否已签到。

  • _try_api_style_sign → 当入口页面没有 formhash 时,尝试从 HTML 推断可能的 AJAX 签到接口并用 GET/POST 探测。

  • _inject_cookie → 将 SCOL_COOKIE 注入到 session,直接复用登录态(一般更稳定)。

  • _is_logged_in → 根据页面关键字/退出链接等粗略判断当前是否已登录。


注意

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


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


没有评论:

发表评论

00后春节摆摊狂赚24万,揭秘面具免费送背后的吸金套路

利用押金模式抓住游客贪便宜心理,七天引流10万粉丝,低成本高利润的节日流量变现术 七天赚 24 万的小生意揭秘 马上过年了,告诉你一个只用七天时间就可以赚到 24 万的小生意, 因此,如果今年口袋拿不出3万块钱回家过年的哥们儿,一定要把这篇内容好好地看完。 因为今天这篇内容太...