""" 智联招聘签名算法 (crawler_core) 职责:参数构造 + 签名算法,不涉及 HTTP 请求 """ from __future__ import annotations import math import random from typing import Optional class ZhilianSign: """ 智联招聘请求签名 功能 1: 生成请求所需的签名参数(device_id, action_id, at, rt 等) 功能 2: 根据接口类型(cgate / capi)构造对应的签名头或签名参数 参数说明: at: Access Token(登录后获得,未登录为空) rt: Refresh Token(登录后获得,未登录为空) device_id: 设备 ID(自动生成 UUID,也可手动指定) version: 小程序版本号 channel: 渠道标识 platform: 平台 ID(12 = 微信小程序) """ def __init__( self, *, at: str = "", rt: str = "", device_id: Optional[str] = None, version: str = "4.1.259", channel: str = "wxxiaochengxu", platform: str = "12", ): self.at = at self.rt = rt self.device_id = device_id or self.generate_uuid() self.version = version self.channel = channel self.platform = platform # ── 算法: UUID 生成(与小程序一致)──────── @staticmethod def generate_uuid() -> str: chars = "0123456789ABCDEF" uuid = [""] * 36 for i in range(36): uuid[i] = chars[math.floor(16 * random.random())] uuid[14] = "4" uuid[19] = chars[(int(uuid[19], 16) & 0x3) | 0x8] uuid[8] = uuid[13] = uuid[18] = uuid[23] = "-" return "".join(uuid) # ── cgate 签名头 ───────────────────────── def sign_headers(self, page_code: str = "0") -> dict: """构造 cgate 接口的签名请求头""" return { "x-zp-at": self.at, "x-zp-rt": self.rt, "x-zp-action-id": self.generate_uuid(), "x-zp-page-code": page_code, "x-zp-version": self.version, "x-zp-channel": self.channel, "x-zp-platform": self.platform, "x-zp-device-id": self.device_id, "x-zp-business-system": "73", } # ── capi 签名参数 ──────────────────────── def sign_params(self) -> dict: """构造 capi 接口的签名查询参数""" return { "at": self.at, "rt": self.rt, "channel": self.channel, "platform": self.platform, "version": self.version, "d": self.device_id, }