import base64 import json import os import platform import ddddocr import execjs from curl_cffi import requests from observability.logging import get_logger_with_trace logger = get_logger_with_trace(__name__) class LoginSpider: def __init__(self, phone_): self.phone = phone_ self.headers = { "accept": "application/json, text/plain, */*", "accept-language": "zh-CN,zh;q=0.9", "cache-control": "no-cache", "content-type": "application/x-www-form-urlencoded", "origin": "https://plogin.m.jd.com", "pragma": "no-cache", "priority": "u=1, i", "referer": "https://plogin.m.jd.com/login/login?appid=300&returnurl=https%3A%2F%2Fm.jd.com%2F&source=wq_passport", "sec-ch-ua": '"Microsoft Edge";v="131", "Chromium";v="131", "Not_A Brand";v="24"', "sec-ch-ua-mobile": "?0", "sec-ch-ua-platform": '"Windows"', "sec-fetch-dest": "empty", "sec-fetch-mode": "cors", "sec-fetch-site": "same-origin", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0", } self.cookies = {} self.current_os = platform.system() self.js_path = None self.node_modules_path = None self.load_directory() self.slide_ctw = self.init_verify_data_js() self.user_ctw = self.init_user_encrypt_js() self.h5st_ctw = self.init_h5st_js() self.session = requests.Session() self.ocr = ddddocr.DdddOcr() self.eid = "" self.fp = "26114226dc0c6ee7f1eaf3d4abb30cf2" self.s_token = None self.rsa_modulus = None self.api_st = None self.api_fp = None self.img1 = None self.img2 = None self.vt = None self.img = None self.jd_risk_token_id = None self.jcap_sid = None self.ck = None def load_directory(self): if self.current_os == "Linux": self.js_path = r"/app/js" self.node_modules_path = r"/app/node_modules" else: self.js_path = "js" self.node_modules_path = "./node_modules" def do_execjs(self, path): return execjs.compile( open(path, encoding="utf8").read(), cwd=self.node_modules_path ) def init_verify_data_js(self): js_path = os.path.join(self.js_path, "modules.js") return execjs.compile( open(js_path, encoding="gbk", errors="ignore").read(), cwd=self.node_modules_path, ) def init_user_encrypt_js(self): js_path = os.path.join(self.js_path, "user_encrypt.js") return execjs.compile( open(js_path, encoding="gbk", errors="ignore").read(), cwd=self.node_modules_path, ) def init_h5st_js(self): js_path = os.path.join(self.js_path, "h5st-5.0.js") return execjs.compile( open(js_path, encoding="gbk", errors="ignore").read(), cwd=self.node_modules_path, ) def request_jd_risk_token_id(self): response = self.session.get( "https://payrisk.jd.com/m.html", cookies=self.cookies, headers=self.headers ) return response.text def build_jcapsid_data(self): return self.user_ctw.call( "init", self.phone, self.fp, self.jd_risk_token_id, self.s_token ) def request_jcapsid(self): url = "https://plogin.m.jd.com/cgi-bin/mm/jcapsid" data = self.build_jcapsid_data() response = self.session.post(url, headers=self.headers, data=data) print(f"request_jcapsid返回:{response.text}") return response.json() def request_new_login_entrance(self): url = "https://plogin.m.jd.com/cgi-bin/mm/new_login_entrance" params = { "lang": "chs", "returnurl": "https://my.m.jd.com/", "risk_jd\\[eid\\]": self.eid, "risk_jd\\[fp\\]": self.fp, } response = self.session.get( url, headers=self.headers, cookies=self.cookies, params=params ) print(response.text) return response.json() def get_jcap_sid(self): jcapsid_res = self.request_jcapsid() self.jcap_sid = jcapsid_res["jcap_sid"] def get_login_entrance(self): login_entrance_res = self.request_new_login_entrance() self.s_token = login_entrance_res["s_token"] self.rsa_modulus = login_entrance_res["rsa_modulus"] def build_fp_data(self): return self.slide_ctw.call("getFp", self.phone, self.jcap_sid) def request_data_fp(self): data = self.build_fp_data() url = "https://jcap.m.jd.com/cgi-bin/api/fp" response = self.session.post(url, headers=self.headers, data=data) print(response.text) return response.json() def get_api_params(self): fp_res = self.request_data_fp() self.api_st = fp_res["st"] self.api_fp = fp_res["fp"] def build_captcha_data(self): return self.slide_ctw.call("getImage", self.phone, self.jcap_sid, self.api_st) def request_captcha(self): url = "https://jcap.m.jd.com/cgi-bin/api/check" data = self.build_captcha_data() response = requests.post(url, headers=self.headers, data=data) print(response.text) return response.json() def set_img(self, captcha_res): self.img = captcha_res["img"] img_json = json.loads(captcha_res["img"]) self.api_st = captcha_res["st"] self.img1 = img_json["b1"] self.img2 = img_json["b2"] def get_captcha(self): captcha_res = self.request_captcha() if captcha_res.get("vt"): self.vt = captcha_res["vt"] self.api_st = captcha_res["st"] return True self.set_img(captcha_res) return False def verify_captcha(self): bg = self.img1.replace("data:image/jpg;base64,", "") background = base64.b64decode(bg) fg = self.img2.replace("data:image/png;base64,", "") target = base64.b64decode(fg) result = self.ocr.slide_match(target, background, simple_target=True) x = round(result["target"][0] * (290 / 275)) url = "https://jcap.m.jd.com/cgi-bin/api/check" data = self.slide_ctw.call( "verify", self.phone, self.jcap_sid, self.img, self.api_st, x ) response = self.session.post(url, headers=self.headers, data=data) print(response.text) return response.json() def check_captcha(self): captcha_res = self.verify_captcha() if captcha_res.get("vt"): self.vt = captcha_res["vt"] self.api_st = captcha_res["st"] return True self.set_img(captcha_res) return False def build_send_code_data(self): return self.user_ctw.call( "sendMsg", self.phone, self.vt, self.jd_risk_token_id, self.s_token, self.rsa_modulus, ) def send_code(self): url = "https://plogin.m.jd.com/cgi-bin/mm/dosendlogincode" data = self.build_send_code_data() response = self.session.post(url, headers=self.headers, data=data) print(response.text) self.ck = self.get_cookie() return response.json() def get_h5st(self, code): return self.h5st_ctw.call("getH5st", code, self.s_token) def build_verify_data(self, phone_, code, s_token, jd_risk_token_id, rsa_modulus): h5st = self.get_h5st(code) return self.user_ctw.call( "login", phone_, code, s_token, h5st, jd_risk_token_id, rsa_modulus ) def get_cookie(self): cookie_dict = self.session.cookies.get_dict() return "; ".join([f"{key}={value}" for key, value in cookie_dict.items()]) + ";" def request_sms_login(self, ck, code, s_token, jd_risk_token_id, rsa_modulus): url = "https://plogin.m.jd.com/cgi-bin/mm/dosmslogin" h5st = self.get_h5st(code) data = self.user_ctw.call( "login", phone, code, s_token, h5st, jd_risk_token_id, rsa_modulus ) self.headers["cookie"] = ck response = requests.post(url, headers=self.headers, data=data) print(response.text) self.ck = self.get_cookie() return response.json() def get_jd_risk_token_id(self): self.jd_risk_token_id = ( self.request_jd_risk_token_id() .split("var jd_risk_token_id = ")[1] .strip(";") .strip("'") ) def get_code_res(self): send_res = self.send_code() if send_res.get("err_code") == 0: return 100, { "ck": self.ck, "s_token": self.s_token, "jd_risk_token_id": self.jd_risk_token_id, "rsa_modulus": self.rsa_modulus, } else: return 101, { "ck": "", "s_token": "", "jd_risk_token_id": "", "rsa_modulus": "", } @staticmethod def my_response(status_code, data): return {"code": status_code, "data": data, "msg": "请求成功"} def run_get_ck(self, ck, code, s_token, jd_risk_token_id, rsa_modulus): login_res = self.request_sms_login( ck, code, s_token, jd_risk_token_id, rsa_modulus ) if login_res.get("err_code") == 0: data = {"ck": self.ck} return self.my_response(status_code=100, data=data) else: data = {"ck": ""} return self.my_response(status_code=101, data=data) def run_send_code(self): try: # 获取risk_token_id self.get_jd_risk_token_id() # 获取登录所需初始sid self.get_login_entrance() self.get_jcap_sid() # 获取验证码 self.get_api_params() captcha_status = self.get_captcha() if not captcha_status: print("出现滑块验证") # 验证验证码 check_status = self.check_captcha() if check_status: print("滑块验证通过,发送验证码") status_code, data = self.get_code_res() return self.my_response(status_code, data) return None else: print("没有出现滑块验证,直接发送验证码") status_code, data = self.get_code_res() return self.my_response(status_code, data) except: return self.my_response(status_code=111, data={}) if __name__ == "__main__": phone_ = "13071534209" res = LoginSpider( phone_=phone_, ).run_send_code() print(res) res = LoginSpider( phone_=phone_, ).run_get_ck( ck="jcap_dvzw_fp=7Hq5_QuYK92sDlclFxhJ8m28JaYU1hDYJ-U-gC59LmJRPuo3ERCbiMGzn5vdc3WcTX0ndWGFZNOs3BDenMr7lw==; guid=a5bb2dc650ab23a2cf5cb58afef19b3f35adba9613421b4cba79aa59ea891803; lang=chs; lsid=503346699194megeguncgrf6gvwb9tdujp2md5p27pkt1737276375048; lstoken=vvwcnbi4;", code="315572", s_token="vvwcnbi4", jd_risk_token_id="SH6IDCXBUWZNAV3SJPRGIXLVNHGLZR6AYHJ3244TGU5Z35SFJU76TAQ3OMNTXE7XA3SBRMPVTZJVW", rsa_modulus="B03744DE9EAB28F6FA6B9C8FB1873CF57D42A2B6D382B79B276C2079A42B24C11D641EA642CF62485A632AE244DE6DE05A92A20EEFE8B6C7743F09FCE0BF78E6D614C115CDAEC2F4825F82E06770A2599D69BBADBE678DD25F2E5B9E2D0E3E15BEB749B436860872D30676794D3C3E8C37B71372DE52F223917FA730EC21F047", ) print(res)