1.购买服务器阿里云:服务器购买地址https://t.aliyun.com/U/Bg6shY若失效,可用地址
阿里云:
服务器购买地址
https://t.aliyun.com/U/Bg6shY若失效,可用地址
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.代码如下
"""任务名称name: NGA社区 每日签到定时规则cron: 0 3 0 * * ?"""import tracebackimport requestsfrom Utility.common import common_util as utilfrom Utility.common.common_util import get_md5# 从环境变量获取CookieNGA_COOKIE, NGA_UID, NGA_CLIENT_CHECKSUM = util.get_os_env("nga_cookie", "nga_uid", "nga_client_checksum")# 获取一个随机UUID的SHA256值作为设备标识符(IOS版本)UUID_SHA256 = "iOS;" + util.get_sha256(util.get_uuid(4, False, True))# 获取随机校验码,用于填充请求头中不会被检验的值NGA_USER_INFO = "%25" + util.get_radom_string()NGA_USER_INFO_CHECK = get_md5(NGA_USER_INFO)WEBKIT_FORM_BOUNDARY = util.get_radom_string()def doSign():"""NGA社区 每日签到,主要执行部分"""url = "https://ngabbs.com/nuke.php"cookie = (f"ngacn0comInfoCheckTime={util.get_timestamp(None, "s")}; "f"ngacn0comUserInfo={NGA_USER_INFO}; "f"ngacn0comUserInfoCheck={NGA_USER_INFO_CHECK}; "f"bbsmisccookies=%7B%7D; "f"access_token={NGA_COOKIE}; "f"access_uid={NGA_UID}")data = (f'------WebKitFormBoundary{WEBKIT_FORM_BOUNDARY}\nContent-Disposition: form-data; name="__lib"\n\ncheck_in\n'f'------WebKitFormBoundary{WEBKIT_FORM_BOUNDARY}\nContent-Disposition: form-data; name="__output"\n\n11\n'f'------WebKitFormBoundary{WEBKIT_FORM_BOUNDARY}\nContent-Disposition: form-data; name="app_id"\n\n1100\n'f'------WebKitFormBoundary{WEBKIT_FORM_BOUNDARY}\nContent-Disposition: form-data; name="device"\n\n{UUID_SHA256}\n'f'------WebKitFormBoundary{WEBKIT_FORM_BOUNDARY}\nContent-Disposition: form-data; name="__act"\n\ncheck_in\n'f'------WebKitFormBoundary{WEBKIT_FORM_BOUNDARY}\nContent-Disposition: form-data; name="access_uid"\n\n{NGA_UID}\n'f'------WebKitFormBoundary{WEBKIT_FORM_BOUNDARY}\nContent-Disposition: form-data; name="access_token"\n\n{NGA_COOKIE}\n'f'------WebKitFormBoundary{WEBKIT_FORM_BOUNDARY}\nContent-Disposition: form-data; name="__ngaClientChecksum"\n\n{NGA_CLIENT_CHECKSUM}\n'f'------WebKitFormBoundary{WEBKIT_FORM_BOUNDARY}\nContent-Disposition: form-data; name="__inchst"\n\nUTF-8\n'f'------WebKitFormBoundary{WEBKIT_FORM_BOUNDARY}--\n')headers = {'Host': 'ngabbs.com','X-USER-AGENT': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 NGA_skull/10.1.36','Accept': '*/*','Sec-Fetch-Site': 'same-origin','Accept-Language': 'zh-CN,zh-Hans;q=0.9','Accept-Encoding': 'gzip, deflate','Sec-Fetch-Mode': 'cors','Content-Type': f'multipart/form-data; boundary=----WebKitFormBoundary{WEBKIT_FORM_BOUNDARY}','Origin': 'https://ngabbs.com','Content-Length': '1096','User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 NGA_skull/10.1.36','Referer': 'https://ngabbs.com/misc/mission/mission.php','Connection': 'keep-alive','Sec-Fetch-Dest': 'empty','Cookie': cookie}try:response = requests.post(url, headers=headers, data=data)if response.status_code == 200:response_data = response.json()print(response_data)if "data" in response_data:if "签到成功" in response_data["data"][0]:sum = response_data["data"][1]["sum"]continued = response_data["data"][1]["continued"]util.send_log(0, f"NGA社区 今日签到成功。当前连续签到 {continued} 天,累计签到 {sum} 天。")util.send_notify("NGA社区·签到:已完成", f"NGA社区 今日签到成功。\n\n当前连续签到 {continued} 天,累计签到 {sum} 天。")else:util.send_log(1, f"出现了未知错误,错误信息:{response_data['data'][0]}")util.send_notify("【失败】NGA社区·签到", f"出现了未知错误,请查看日志!\n\n错误信息:{response_data['data'][0]}")elif "error" in response_data:if "你今天已经签到了" in response_data["error"][0]:util.send_log(0, "今天已经签到过,无需签到。")util.send_notify("NGA社区·签到:已签到", "今天已经签到过,无需签到。")elif "你必须先登录论坛" in response_data["error"][0]:util.send_log(2, "NGA账号Cookie已过期,无法签到。请更新环境变量nga_cookie的值!")util.send_notify("【Cookie过期】NGA社区·签到", "NGA账号Cookie已过期,无法签到。需要更新环境变量nga_cookie的值!")elif "CLIENT ERROR" in response_data["error"][0]:util.send_log(2, "NGA客户端校验码已过期/不适配/非IOS端抓包的校验码,无法通过NGA服务器验证。请更新环境变量nga_client_checksum的值!")util.send_notify("【Cookie过期】NGA社区·签到", "NGA客户端校验码已过期/不适配/非IOS端抓包的校验码,无法NGA服务器验证。需要更新环境变量nga_client_checksum的值!")else:util.send_log(1, f"出现了未知错误,错误信息:{response_data['error']}")util.send_notify("【失败】NGA社区·签到", f"出现了未知错误,请查看日志!\n\n错误信息:{response_data['error']}")else:util.send_log(1, f"出现了未知错误,状态码: {response.status_code}")util.send_notify("【失败】NGA社区·签到", f"出现了未知错误,请查看日志!\n\n状态码:{response.status_code}")except requests.RequestException as e:util.send_log(3, f"API请求失败 - {e}")util.send_notify("【失败】NGA社区·签到", f"API请求失败,请查看日志!\n\n错误信息:{e}")if __name__ == "__main__":util.send_log(0, "NGA社区 每日签到 - 开始执行")value_check = "" # 存储环境变量为空的变量名用于推送通知正文内容if NGA_COOKIE is None:value_check += "【nga_cookie】"elif NGA_UID is None:value_check += "【nga_uid】"elif NGA_CLIENT_CHECKSUM is None:value_check += "【nga_client_checksum】"if value_check == "":try:doSign()except Exception as e:util.send_log(3, f"程序运行报错 - {e}")util.send_log(3, f"{traceback.format_exc()}")util.send_notify("【程序报错】NGA社区·签到", f"程序运行报错,请查看日志!\n\n错误信息:{e}")else:util.send_log(2, f"缺少环境变量,请添加以下环境变量后再使用:{value_check}")util.send_notify("【缺少环境变量】NGA社区·签到", f"缺少环境变量,请添加以下环境变量后再使用:{value_check}")
这是 NGA 社区(ngabbs.com)每日签到脚本(定时:cron 0 3 0 * * ?)。它通过 模拟 iOS 端 NGA 客户端的签到请求,向 https://ngabbs.com/nuke.php 提交 check_in 表单完成签到,并根据返回结果:
记录日志
util.send_log(...)推送通知
util.send_notify(...)判断:签到成功 / 已签到 / Cookie 过期 / 客户端校验码不匹配 等情况
脚本依赖 3 个环境变量:
nga_cookie:NGA 的access_tokennga_uid:NGA 的access_uidnga_client_checksum:NGA 客户端校验码(必须是对应端/版本抓包得到的)
主要方法
1) doSign()
核心签到函数,做了四件事:
拼装 Cookie
ngacn0comUserInfo是随机串(做了 URL 编码形式%25...)ngacn0comUserInfoCheck是对上面字符串做 MD5(用于配对)把环境变量的
access_token、access_uid放进 Cookie额外伪造了几个"看起来像客户端会带的"字段:
ngacn0comUserInfo / ngacn0comUserInfoCheck / ngacn0comInfoCheckTime / bbsmisccookies其中:
构造 multipart/form-data 请求体
__lib=check_in、__act=check_in:明确是签到动作app_id=1100:客户端/应用标识(固定)device=UUID_SHA256:设备标识(伪造为iOS;+ sha256(uuid))access_uid/access_token:登录态__ngaClientChecksum:客户端校验码(非常关键)__output=11:输出格式参数(常见于 NGA 接口)__inchst=UTF-8:字符集通过
WebKitFormBoundary{随机边界}手工拼 multipart 内容(而不是用 requests 的 files 参数)关键字段:
设置请求头,伪装 iOS NGA 客户端
User-Agent/X-USER-AGENT都伪装成 iPhone +NGA_skull/10.1.36Content-Type指定 multipart boundaryOrigin/Referer指向 NGA 站内页面Cookie放入上面拼好的 Cookie解析响应并分类处理
data字段存在:通常是成功或半成功结果error字段存在:失败原因分支sum:累计签到天数continued:连续签到天数如果包含"签到成功",读取:
"你今天已经签到了" → 视为已完成
"你必须先登录论坛" → 认为
nga_cookie/uid失效"CLIENT ERROR" → 认为
nga_client_checksum不匹配/过期/端不对其他 → 归类未知错误并通知
HTTP 200 时:
response.json()后检查两种结构:
全局变量
UUID_SHA256:伪造设备标识(模拟 iOS 客户端字段device)NGA_USER_INFO:随机用户信息串(用来填 Cookie 的"非关键但看起来真实"的字段)NGA_USER_INFO_CHECK:对NGA_USER_INFO做 MD5,作为配对校验值WEBKIT_FORM_BOUNDARY:multipart 边界字符串(随机生成,和Content-Type/ body 对齐)
主流程
先检查 3 个环境变量是否齐全(缺哪个就通知缺哪个)
齐全就调用
doSign()任何未捕获异常会输出 traceback 并推送"程序报错"通知
注意:
本文部分变量已做脱敏处理,仅用于测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。技术层面需要提供帮助,可以通过打赏的方式进行探讨。
没有评论:
发表评论