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 reimport sysimport timeimport jsonimport randomimport tracebackfrom urllib.parse import urljoin, urlparseimport requestsfrom bs4 import BeautifulSoupBASE_URL = "https://bbs.wangjing.cn/"TIMEOUT = 20def log(msg: str):now = time.strftime("%Y-%m-%d %H:%M:%S")print(f"[{now}] {msg}")def pushplus(title: str, content: str):"""可选:PushPlus 通知"""token = os.getenv("PUSHPLUS_TOKEN")if not token:returntry:requests.get("https://www.pushplus.plus/send",params={"token": token, "title": title, "content": content, "template": "txt"},timeout=10,)except Exception as e:log(f"⚠️ PushPlus 推送失败:{e}")class WangJingBBSBot:def __init__(self, username: str, password: str):self.username = username or ""self.password = password or ""self.s = requests.Session()self.s.headers.update({"User-Agent": ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ""(KHTML, like Gecko) Chrome/123.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, url: str, **kwargs) -> requests.Response:for i in range(3):try:resp = self.s.get(url, timeout=TIMEOUT, allow_redirects=True, **kwargs)return respexcept Exception as e:if i == 2:raiselog(f"⚠️ GET 失败重试 {i+1}/3:{e}")time.sleep(1 + i)def _post(self, url: str, data=None, **kwargs) -> requests.Response:for i in range(3):try:resp = self.s.post(url, data=data, timeout=TIMEOUT, allow_redirects=True, **kwargs)return respexcept Exception as e:if i == 2:raiselog(f"⚠️ POST 失败重试 {i+1}/3:{e}")time.sleep(1 + i)def _soup(self, html: str) -> BeautifulSoup:return BeautifulSoup(html, "lxml")def is_discuz_like(self, html: str) -> bool:"""判断站点是否像 Discuz:- 常见关键词:formhash、discuz、member.php、forum.php"""h = html.lower()return ("formhash" in h) and (("member.php" in h) or ("forum.php" in h) or ("discuz" in h))def extract_formhash(self, html: str) -> str:"""Discuz 常见的 formhash:<input type="hidden" name="formhash" value="xxxx">或 JS 变量形式。"""m = re.search(r'name="formhash"\s+value="([^"]+)"', html)if m:return m.group(1)m = re.search(r'formhash\s*=\s*"([^"]+)"', html)if m:return m.group(1)return ""def is_logged_in(self, html: str) -> bool:"""粗略判断登录状态:- Discuz 登录后通常会有 "退出/注销/我的/设置" 等入口- 或存在 uid/username 相关字段"""text = htmlkeywords = ["退出", "注销", "设置", "我的", "消息", "提醒"]if any(k in text for k in keywords) and ("member.php?mod=logging&action=logout" in text or "logout" in text):return True# 兜底:看看是否存在"登录/注册"按钮(存在不代表未登录,但可辅助)if ("登录" in text and "注册" in text) and ("退出" not in text and "注销" not in text):return False# 再兜底:出现"欢迎您"之类if "欢迎" in text and ("退出" in text or "注销" in text):return Truereturn False# -----------------------------# 登录# -----------------------------def login(self) -> bool:"""Discuz 通用登录流程(尽力而为):1) 拉取首页拿 formhash2) POST 到 member.php?mod=logging&action=login&loginsubmit=yes...3) 再拉取首页检查是否登录成功"""if not self.username or not self.password:log("⚠️ 未提供账号密码,将尝试直接签到(如果Cookie/免登/已登录则可能成功)")return Falsehome = self._get(BASE_URL)html = home.textif not self.is_discuz_like(html):log("⚠️ 页面特征不像 Discuz(或被重载/反爬影响),登录流程可能不适用,将继续尝试自动发现签到入口。")return Falseformhash = self.extract_formhash(html)if not formhash:log("⚠️ 未提取到 formhash,登录可能失败,但仍尝试。")login_url = urljoin(BASE_URL, "member.php?mod=logging&action=login&loginsubmit=yes&infloat=yes&lssubmit=yes")payload = {"username": self.username,"password": self.password,"quickforward": "yes","handlekey": "ls",}if formhash:payload["formhash"] = formhashlog("🔐 正在尝试登录...")resp = self._post(login_url, data=payload, headers={"Referer": BASE_URL})# Discuz 登录可能返回 JS/xml,直接再拉一次首页做最终判断time.sleep(1)home2 = self._get(BASE_URL)ok = self.is_logged_in(home2.text)if ok:log("✅ 登录成功(已检测到登录态)")return Truelog("❌ 登录可能失败(未检测到登录态)。后续仍会尝试签到入口(若无需登录/已有Cookie也可能成功)。")return False# -----------------------------# 自动发现签到入口# -----------------------------def discover_signin_url(self) -> str:"""先从首页/常见页面中"搜"签到链接:- 搜 a 标签 text 包含:签到 / 打卡 / sign- 或 href 包含:sign / qiandao / checkin / plugin.php?id=xxxsign"""candidate_pages = [BASE_URL,urljoin(BASE_URL, "forum.php"),urljoin(BASE_URL, "plugin.php"),]patterns_text = ["签到", "打卡", "签 到", "checkin", "sign"]patterns_href = ["sign", "qiandao", "checkin", "plugin.php?id=", "dsu_paulsign", "misign"]for page_url in candidate_pages:try:resp = self._get(page_url)soup = self._soup(resp.text)for a in soup.select("a[href]"):t = (a.get_text() or "").strip()href = a.get("href") or ""if not href:continueif any(p in t for p in patterns_text) or any(p in href.lower() for p in patterns_href):full = urljoin(page_url, href)# 简单过滤:必须同域if urlparse(full).netloc == urlparse(BASE_URL).netloc:log(f"🔎 自动发现疑似签到入口:{t} -> {full}")return fullexcept Exception as e:log(f"⚠️ 发现入口时访问失败:{page_url} -> {e}")return ""def try_common_signin_plugins(self) -> list:"""常见 Discuz 签到插件路径兜底(不同站点插件不同):- dsu_paulsign:sign- k_misign:sign- dc_signin:sign (示例)"""return [urljoin(BASE_URL, "plugin.php?id=dsu_paulsign:sign"),urljoin(BASE_URL, "plugin.php?id=k_misign:sign"),urljoin(BASE_URL, "plugin.php?id=dc_signin:sign"),]# -----------------------------# 执行签到(尽量通用)# -----------------------------def do_signin(self) -> bool:"""签到执行策略:1) 自动发现入口(优先)2) 入口打不开/没有 formhash 时,尝试常见插件入口3) 打开签到页 -> 抓 formhash -> POST 提交"""signin_url = self.discover_signin_url()tried = []if signin_url:tried.append(signin_url)tried.extend(self.try_common_signin_plugins())# 去重seen = set()tried = [x for x in tried if not (x in seen or seen.add(x))]for url in tried:try:log(f"🚀 尝试签到入口:{url}")r = self._get(url, headers={"Referer": BASE_URL})html = r.text# 常见:如果页面提示未登录if any(k in html for k in ["您需要先登录", "请先登录", "登录后才能", "需要登录"]):log("⚠️ 该入口提示需要登录")continueformhash = self.extract_formhash(html)if not formhash:# 有些插件可能是 GET 一下就算签到(或 AJAX),这里先做文本判断if any(k in html for k in ["签到成功", "已签到", "今日已签", "打卡成功", "您已签到"]):log("✅ 可能已签到(页面已返回成功/已签提示)")return Truelog("⚠️ 未提取到 formhash,可能该站签到为JS/AJAX或插件不同。建议用浏览器打开该URL确认实际提交方式。")continue# 通用提交:不同插件字段不同,这里采用"常见字段 + 容错"post_url = url # 很多插件就是同URL POSTpayloads = [# dsu_paulsign 常见字段(不同站可能不同){"formhash": formhash, "qdxq": "kx", "qdmode": "1", "todaysay": "签到", "fastreply": "0"},{"formhash": formhash, "signsubmit": "yes"},{"formhash": formhash, "submit": "true"},]for payload in payloads:time.sleep(random.uniform(0.8, 1.8))pr = self._post(post_url, data=payload, headers={"Referer": url})tx = pr.text# 成功/已签关键词(尽量覆盖)if any(k in tx for k in ["签到成功", "打卡成功", "您已签到", "今日已签", "已签到", "success"]):log("✅ 签到成功/已签到(匹配到成功关键字)")return Truelog("⚠️ 已提交但未识别到成功关键字,可能需要调整 payload 字段(看日志里的入口URL手动确认一次即可)")except Exception as e:log(f"❌ 签到异常:{e}")log(traceback.format_exc())return Falsedef run(self):log("==== 望京网 自动签到任务开始 ====")log(f"站点:{BASE_URL}")# 先访问一次首页,建立Cookietry:self._get(BASE_URL)except Exception as e:log(f"❌ 访问首页失败:{e}")pushplus("望京网签到", f"访问首页失败:{e}")return# 登录(可失败,不影响后续"直接尝试签到")self.login()# 执行签到ok = self.do_signin()if ok:msg = "✅ 签到完成(成功或已签到)"log(msg)pushplus("望京网签到", msg)else:msg = "❌ 签到失败:未找到可用签到入口或提交参数不匹配。请看日志中尝试过的入口URL,浏览器打开确认一次即可修正。"log(msg)pushplus("望京网签到", msg)log("==== 望京网 自动签到任务结束 ====")def main():username = os.getenv("WJ_USERNAME", "").strip()password = os.getenv("WJ_PASSWORD", "").strip()bot = WangJingBBSBot(username=username, password=password)bot.run()if __name__ == "__main__":main()
该脚本为望京网论坛自动签到脚本,主要功能包括:
建立会话(requests.Session):自动管理 Cookie、Referer、UA 等,保证后续请求在同一个登录态里。
自动登录(尽力而为):如果站点像 Discuz,就走通用
member.php?...loginsubmit=yes的登录流程。自动发现签到入口 + 插件兜底:
先从页面里搜"签到/打卡/checkin"按钮链接;
搜不到就尝试常见 Discuz 签到插件地址(
dsu_paulsign/k_misign等);拿到
formhash后尝试 POST 提交完成签到。
主要方法
1)login()
作用:尝试登录论坛账号,为签到做准备
关键点:
先 GET 首页提取
formhash;POST 到
member.php?mod=logging&action=login&loginsubmit=yes...;再次 GET 首页,通过
is_logged_in()检测是否登录成功。
2)discover_signin_url()
作用:不写死签到URL,自动从页面中发现"签到入口链接"
做法:抓取首页/论坛页等,遍历
<a href>如果
a.text包含"签到/打卡",或href包含sign/qiandao/plugin.php?id=等关键字,就判定为候选入口并返回。
3)try_common_signin_plugins()
作用:当"自动发现"失败时,提供常见 Discuz 签到插件地址兜底
返回:如
plugin.php?id=dsu_paulsign:sign、plugin.php?id=k_misign:sign等。
4)do_signin()
作用:统一编排"找到入口 → 打开签到页 → 提取 formhash → POST 提交 → 判断成功"
关键点:
先尝试
discover_signin_url()的结果;再依次尝试
try_common_signin_plugins();如果页面含"请先登录"则跳过;
如果能提取到
formhash就尝试多个 payload 组合提交(提高兼容性)。
5)run()
作用:脚本主流程入口(工程化执行)
流程:访问首页 → 登录 → 签到 → 输出日志/可选推送。
注意:
本文部分变量已做脱敏处理,仅用于测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。技术层面需要提供帮助,可以通过打赏的方式进行探讨。
没有评论:
发表评论