BYD 签到获取积分

在大佬的帖子下找到的ID 总结了一下,运行签到有点,有大佬研究过吗 帮忙看一下 签到积分?
https://linux.do/t/topic/210710

import argparse
import base64
import hashlib
import json
import os
import sys
import time
import uuid
from dataclasses import dataclass
from typing import Any, Dict
from __future__ import annotations
try:
    import requests
except ImportError as exc:
    raise SystemExit(
        "缺少依赖 requests,请先安装: pip install requests"
    ) from exc

try:
    from Crypto.Cipher import AES
    from Crypto.Util.Padding import pad, unpad
except ImportError as exc:
    raise SystemExit(
        "缺少依赖 pycryptodome,请先安装: pip install pycryptodome"
    ) from exc


BASE_URL = "https://mina.bydoceanauto.com/Forward2Rights/integral"
APP_KEY = "seaMinaApi"
DEFAULT_AES_KEY = "5949577785312731"
DEFAULT_AES_IV = "uDEHPGzSIHIWBlNT"


@dataclass
class BydConfig:
    session_id: str
    service_dir: str
    aes_key: str = DEFAULT_AES_KEY
    aes_iv: str = DEFAULT_AES_IV
    app_key: str = APP_KEY
    timeout: int = 20
    verify_ssl: bool = True
    checksum: str | None = None
    nonce: str | None = None
    curtime: str | None = None


def aes_cbc_encrypt_b64(plain_text: str, key: str, iv: str) -> str:
    cipher = AES.new(key.encode("utf-8"), AES.MODE_CBC, iv.encode("utf-8"))
    encrypted = cipher.encrypt(pad(plain_text.encode("utf-8"), AES.block_size))
    return base64.b64encode(encrypted).decode("utf-8")


def aes_cbc_decrypt_b64(cipher_text_b64: str, key: str, iv: str) -> str:
    raw = base64.b64decode(cipher_text_b64)
    cipher = AES.new(key.encode("utf-8"), AES.MODE_CBC, iv.encode("utf-8"))
    plain = unpad(cipher.decrypt(raw), AES.block_size)
    return plain.decode("utf-8")


def build_checksum(payload_b64: str, cfg: BydConfig) -> str:
    """
    兜底签名策略:
    1) 优先使用显式传入 checksum
    2) 否则使用 sha256(加密后的 body 字符串)
    """
    if cfg.checksum:
        return cfg.checksum
    return hashlib.sha256(payload_b64.encode("utf-8")).hexdigest()


def make_headers(payload_b64: str, cfg: BydConfig) -> Dict[str, str]:
    nonce = cfg.nonce or uuid.uuid4().hex[:16]
    curtime = cfg.curtime or str(int(time.time()))

    headers = {
        "Host": "mina.bydoceanauto.com",
        "Connection": "keep-alive",
        "x-clienttraceid": f"mina-{uuid.uuid4()}",
        "Nonce": nonce,
        "User-Agent": (
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
            "(KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 "
            "MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI "
            "MiniProgramEnv/Windows WindowsWechat/WMPF "
            "WindowsWechat(0x63090c0f)XWEB/11275"
        ),
        "Content-Type": "application/json",
        "Curtime": curtime,
        "xweb_xhr": "1",
        "Checksum": build_checksum(payload_b64, cfg),
        "Appkey": cfg.app_key,
        "Accept": "*/*",
        "Referer": "https://servicewechat.com/wxf62054ec313d6f53/72/page-frame.html",
    }
    return headers


def build_url(service_dir: str) -> str:
    return f"{BASE_URL}?&serviceDir={service_dir}"


def parse_json_maybe(text: str) -> Any:
    try:
        return json.loads(text)
    except Exception:
        return text


def call_api(cfg: BydConfig, payload_obj: Dict[str, Any]) -> Dict[str, Any]:
    plain = json.dumps(payload_obj, ensure_ascii=False, separators=(",", ":"))
    body_encrypted = aes_cbc_encrypt_b64(plain, cfg.aes_key, cfg.aes_iv)
    body_json = json.dumps(body_encrypted, ensure_ascii=False)
    headers = make_headers(body_encrypted, cfg)
    url = build_url(cfg.service_dir)

    resp = requests.post(
        url=url,
        headers=headers,
        data=body_json.encode("utf-8"),
        timeout=cfg.timeout,
        verify=cfg.verify_ssl,
    )

    result: Dict[str, Any] = {
        "url": url,
        "status_code": resp.status_code,
        "headers_sent": headers,
        "request_body_plain": plain,
        "request_body_encrypted": body_encrypted,
        "response_raw": resp.text,
    }

    if resp.ok:
        raw = parse_json_maybe(resp.text)
        if isinstance(raw, str):
            # 部分接口会直接返回加密字符串
            try:
                result["response_decrypted"] = aes_cbc_decrypt_b64(raw, cfg.aes_key, cfg.aes_iv)
            except Exception:
                pass
        else:
            result["response_json"] = raw
            if isinstance(raw, str):
                try:
                    result["response_decrypted"] = aes_cbc_decrypt_b64(raw, cfg.aes_key, cfg.aes_iv)
                except Exception:
                    pass
            elif isinstance(raw, dict):
                # 常见结构 {"data":"xxxx"} 或 {"result":"xxxx"}
                encrypted_field = None
                for k in ("data", "result", "payload"):
                    if isinstance(raw.get(k), str):
                        encrypted_field = raw[k]
                        break
                if encrypted_field:
                    try:
                        result["response_decrypted"] = aes_cbc_decrypt_b64(
                            encrypted_field, cfg.aes_key, cfg.aes_iv
                        )
                    except Exception:
                        pass
    return result


def read_payload_from_env(session_id: str) -> Dict[str, Any]:
    payload = os.getenv("BYD_PAYLOAD_JSON", "").strip()
    if payload:
        try:
            return json.loads(payload)
        except Exception as exc:
            raise SystemExit(f"BYD_PAYLOAD_JSON 不是合法 JSON: {exc}") from exc
    return {"session_id": session_id}


def build_config(args: argparse.Namespace) -> BydConfig:
    session_id = os.getenv("BYD_SESSION_ID", "").strip()
    if not session_id:
        raise SystemExit("请先设置环境变量 BYD_SESSION_ID")

    service_dir = args.service_dir
    if args.action == "rank" and not args.service_dir_set:
        service_dir = "/Experience/User/ranks"
    if args.action == "sign" and not args.service_dir_set:
        service_dir = "/Experience/User/signIn"

    return BydConfig(
        session_id=session_id,
        service_dir=service_dir,
        aes_key=os.getenv("BYD_AES_KEY", DEFAULT_AES_KEY),
        aes_iv=os.getenv("BYD_AES_IV", DEFAULT_AES_IV),
        app_key=os.getenv("BYD_APPKEY", APP_KEY),
        timeout=args.timeout,
        verify_ssl=not args.insecure,
        checksum=os.getenv("BYD_CHECKSUM", "").strip() or None,
        nonce=os.getenv("BYD_NONCE", "").strip() or None,
        curtime=os.getenv("BYD_CURTIME", "").strip() or None,
    )


def main() -> None:
    parser = argparse.ArgumentParser(description="BYD 小程序接口签到脚本(手动 session 版)")
    parser.add_argument("--action", choices=["rank", "sign"], default="rank")
    parser.add_argument("--service-dir", default="/Experience/User/ranks")
    parser.add_argument("--timeout", type=int, default=20)
    parser.add_argument("--insecure", action="store_true", help="关闭 SSL 证书校验")
    args = parser.parse_args()
    args.service_dir_set = "--service-dir" in sys.argv

    cfg = build_config(args)
    payload_obj = read_payload_from_env(cfg.session_id)

    try:
        result = call_api(cfg, payload_obj)
    except requests.RequestException as exc:
        raise SystemExit(f"请求失败: {exc}") from exc

    print(json.dumps(result, ensure_ascii=False, indent=2))

    # 常见成功提示,方便脚本化判断
    text = json.dumps(result, ensure_ascii=False)
    if any(k in text for k in ("签到成功", "已签到", "already")):
        raise SystemExit(0)
    if result.get("status_code", 500) >= 400:
        raise SystemExit(2)


if __name__ == "__main__":
    main()

2 个赞

我好想再GitHub 看到有模拟的,但是都不是开源的

对,那个大佬的帖子里面也是,有研究过吗,想搞个BYD的签到积分 2年的快到期了(流量)

感谢大佬

你能跑起来?

今天休息在外面,回去试试佬这个脚本能不能跑起来

大水龙是脚本 :bili_001:

还没弄呢

啥?没懂

大帅哥之前的绰号

这个可以,确实需要,我也是拿积分换流量,哈哈

一起研究一下 看一下能不能做出来

哈哈哈 没get 到点

签到的脚本还没出来吗?插眼等待。

同蹲一个,也需要签到的脚本,哈哈

蹲蹲蹲,等一手脚本,哈哈哈哈哈哈