1.购买服务器阿里云:服务器购买地址https://t.aliyun.com/U/DT4XYh若失效,可用地址
阿里云:
服务器购买地址
https://t.aliyun.com/U/DT4XYh
若失效,可用地址
https://www.aliyun.com/activity/wuying/dj?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.部署教程
3.代码如下
import argparse
import hashlib
import requests
from bs4 import BeautifulSoup
class AutoSign:
LOGIN_PAGE = "https://www.jkju.cc/member.php"
LOGIN_URL = "https://www.jkju.cc/member.php"
SIGN_URL = "https://www.jkju.cc/plugin.php"
SIGN_PAGE_URL = "https://www.jkju.cc/plugin.php?id=zqlj_sign"
LOGIN_FORM_DATA = {
"referer": "https://www.jkju.cc/",
"questionid": 0,
"answer": "",
"cookietime": "2592000",
}
LOGIN_PARAMS = {
"mod": "logging",
"action": "login",
"loginsubmit": "yes",
"inajax": 1,
}
LOGIN_HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0",
"Origin": "https://www.jkju.cc",
"Referer": "https://www.jkju.cc/member.php?mod=logging&action=login",
}
SIGN_HEADERS = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/140.0.0.0 Safari/537.36 Edg/140.0.0.0",
"Referer": "https://www.jkju.cc/",
}
def __init__(self, username: str, password: str, is_email: bool = False) -> None:
self.session = requests.Session()
self.username = username
self.password_md5 = hashlib.md5(password.encode()).hexdigest()
self.login_form_data = self.LOGIN_FORM_DATA.copy()
self.login_form_data["username"] = username
self.login_form_data["password"] = password
self.login_form_data["loginfield"] = "email" if is_email else "username"
self.sign_page_html: str | None = None
self.message = f"签到任务: 镜客居\n登录账号: {username}\n"
def _get_login_hash(self) -> tuple[str, str]:
resp = self.session.get(
self.LOGIN_PAGE, params={"mod": "logging", "action": "login"}
)
if resp.status_code == 403:
resp = self.session.get(
self.LOGIN_PAGE, params={"mod": "logging", "action": "login"}
)
soup = BeautifulSoup(resp.text, "html.parser")
form_tag = soup.find("form", {"name": "login"})
formhash = form_tag.find("input", {"name": "formhash", "type": "hidden"}).get("value")
loginhash = form_tag.get("action").split("&")[-1].split("=")[-1]
return formhash, loginhash
def login(self) -> int:
"""执行两次请求完成登录。"""
formhash, loginhash = self._get_login_hash()
self.login_form_data["formhash"] = formhash
self.LOGIN_PARAMS["loginhash"] = loginhash
resp = self.session.post(
self.LOGIN_URL,
params=self.LOGIN_PARAMS,
data=self.login_form_data,
headers=self.LOGIN_HEADERS,
)
if resp.status_code == 403:
self.session.cookies.clear_expired_cookies()
resp = self.session.post(
self.LOGIN_URL,
params=self.LOGIN_PARAMS,
data=self.login_form_data,
headers=self.LOGIN_HEADERS,
)
text = resp.text
if "请输入验证码继续登录" in text:
return 0
if "欢迎您回来" in text:
return 1
return -1
def _init_sign_page(self) -> None:
resp = self.session.get(self.SIGN_PAGE_URL)
if resp.status_code == 403:
self.session.cookies.clear_expired_cookies()
resp = self.session.get(self.SIGN_PAGE_URL)
self.sign_page_html = resp.text
def _get_sign_hash(self) -> str:
soup = BeautifulSoup(self.sign_page_html, "html.parser")
form_tag = soup.find("form", {"id": "scbar_form"})
return form_tag.find("input", {"name": "formhash", "type": "hidden"}).get("value")
def _get_sign_trend(self) -> str:
soup = BeautifulSoup(self.sign_page_html, "lxml")
trend_lis = soup.select('#wp > div.ct2.cl > div.sd > div:nth-of-type(3) > div.bm_c > ul > li')
return "\n".join(li.text for li in trend_lis)
def _already_signed(self) -> bool:
soup = BeautifulSoup(self.sign_page_html, "html.parser")
sign_status_text = soup.find("div", class_="bm signbtn cl").find("a").text
return "今日已打卡" in sign_status_text
def sign(self) -> int:
"""执行签到操作。"""
sign_hash = self._get_sign_hash()
resp = self.session.get(
self.SIGN_URL,
headers=self.SIGN_HEADERS,
params={"id": "zqlj_sign", "sign": sign_hash},
).text
if "恭喜您,打卡成功!" in resp:
return 1
if "您今天已经打过卡了,请勿重复操作!" in resp:
return 0
return -1
def start(self) -> None:
login_status = self.login()
if login_status == 0:
self.message += "登录状态: 频繁登录,需要验证码\n"
elif login_status == -1:
self.message += "登录状态: 登录失败\n"
print(self.message)
return
self._init_sign_page()
if self._already_signed():
self.message += "执行结果: 今日已签到\n"
self.message += self._get_sign_trend()
else:
sign_status = self.sign()
if sign_status == -1:
self.message += "执行结果: 签到失败\n"
else:
self.message += f"执行结果: {'签到成功' if sign_status == 1 else '今日已签到'}\n"
self._init_sign_page()
self.message += self._get_sign_trend()
print(self.message)
if __name__ == "__main__":
args_parser = argparse.ArgumentParser()
args_parser.add_argument("-u","--user", type=str, required=True, help="用户")
args_parser.add_argument("-p","--password", type=str, required=True, help="密码")
args_parser.add_argument("-m","--mode", type=str, help="模式: username | email ")
arguments = args_parser.parse_args()
if arguments.mode is None or arguments.mode.strip().lower() != "email":
arguments.mode = "username"
signer = AutoSign(arguments.user, arguments.password, arguments.mode.strip().lower() == 'email')
signer.start()
面向 镜客居(jkju.cc) 的自动登录 + 每日签到脚本。
通过账号(用户名或邮箱)与密码登录站点,进入签到插件页,判断是否已签到;未签到则发起签到请求,并输出当天签到结果与站内"打卡趋势"信息。
主要方法
__init__(username, password, is_email=False)
初始化requests.Session
、登录表单数据与请求头;支持用户名或邮箱登录;准备签到页 HTML 缓存与消息前缀。_get_login_hash()
访问登录页,解析登录表单中的formhash
与表单action
里的loginhash
(Discuz! 登录所需动态参数),作为后续提交登录所必需的校验值。login()
组合formhash/loginhash
与表单字段提交登录请求;根据返回文本判断三种状态:1
登录成功,0
触发验证码(频繁登录),-1
登录失败。遇到 403 会清理过期 Cookie 并重试一次。_init_sign_page()
拉取签到插件页(plugin.php?id=zqlj_sign
),保存页面 HTML;遇到 403 同样清理过期 Cookie 后重试。_get_sign_hash()
从签到页 HTML 中解析隐藏字段formhash
(位于id="scbar_form"
的表单里),用于签到请求的签名参数。_already_signed()
从签到页解析"签到按钮"区域文案,判断是否为"今日已打卡",据此确定当天是否已签到。_get_sign_trend()
解析签到页右侧模块里的"打卡趋势/统计"列表,拼成多行文本,用于结果输出。sign()
以GET plugin.php?id=zqlj_sign&sign=<formhash>
发起签到;根据返回文本判断:1
签到成功;0
已签到;-1
失败/未知。start()
入口流程:先登录→加载签到页→如已签到则直接输出趋势;否则执行签到→再次加载签到页→输出趋势与结果消息。
其他要点
常量:站点的登录页、登录提交地址、签到插件入口、通用 UA/Referer 等头部。
容错:对 403 使用"清 Cookie + 重试"的简单策略;对验证码场景给出提示。
命令行参数:
-u/--user
、-p/--password
、-m/--mode
(username
/email
),便于脚本直接运行。
注意:
本文部分变量已做脱敏处理,仅用于测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。技术层面需要提供帮助,可以通过打赏的方式进行探讨。
没有评论:
发表评论