import requests from module import F6_module import time import pandas as pd import re from typing import Dict, Any, Optional f6_module = F6_module() entry_data = { "data": { "账号": "18742526670", "密码": "Zy18742526670", "公司名称": "F6汽车科技数据组测试(废弃)" } } username = entry_data['data']['账号'] password = entry_data['data']['密码'] company_name = entry_data['data']['公司名称'] res = f6_module.login_in(username, password, company_name) cookies = requests.utils.dict_from_cookiejar(res.cookies) df = pd.read_excel(fr"D:\Idea Project\简道云\模板文件\客户信息修改.xlsx", sheet_name=0).astype( str) # headers = { # 'accept': 'application/json, text/plain, */*', # 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6', # 'priority': 'u=1, i', # 'referer': 'https://yunxiu.f6car.cn/erp/view/index.html', # 'sec-ch-ua': '"Not)A;Brand";v="8", "Chromium";v="138", "Microsoft Edge";v="138"', # '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/138.0.0.0 Safari/537.36 Edg/138.0.0.0', # 'x-requested-with': 'XMLHttpRequest', # # 'cookie': 'memberSESSIONID=51cbcae1-6734-4ff2-8440-0ba499afb046; erpLanguage=zh-CN; prodOrg=11240984669917217520; unp=15865484595890778191; un=15865484595890778191; _up=-NillNN-qyBEJ--t3vnSknvoOF53y_SJuMkA2n43U-daUfnArpjQjaZJ9Q3d-WrAAGgt60MgQHajHWBHMKKxj0CuWypi1JgKCFP1EPEk-HbqEfAQq4Ih0AAM_PBRv-ZNHu3M-GTc1p60EX-sq-RQgeIal1HLPxpurEj90B7u9sDXaGA.; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2215865484595890778191%22%2C%22first_id%22%3A%22198318ea9e5465-0620cc84e196ca8-4c657b58-1327104-198318ea9e61865%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%7D%2C%22%24device_id%22%3A%22198318ea9e5465-0620cc84e196ca8-4c657b58-1327104-198318ea9e61865%22%7D; tmall=false; Hm_lvt_25f5e7a3a5dbb293d7dd35d5f1be8d0a=1753239849,1753319248,1753329553,1753429373; Hm_lpvt_25f5e7a3a5dbb293d7dd35d5f1be8d0a=1753429373; HMACCOUNT=6C57D3B85B36E54F', # } params = { 'pageSize': 100, 'pageNo': '1', } res = requests.get( 'https://yunxiu.f6car.cn/member/customer/listForPermission', params=params, cookies=cookies, # headers=headers, ) total = int(res.json().get("data").get("total")) total_pages = (total // params["pageSize"]) + (1 if total % params["pageSize"] > 0 else 0) total_pages = 2 print(f"总计{total_pages}页") all_customers = [] max_retries = 10 retry_count = 0 for page in range(1, total_pages + 1): print(f"正在请求第 {page} 页...") params["currentPage"] = page while retry_count < max_retries: response = requests.get( 'https://yunxiu.f6car.cn/member/customer/listForPermission', params=params, cookies=cookies, # headers=headers, timeout=10 ) time.sleep(1) if response.status_code == 200: suppliers = response.json().get("data", {}).get("data", []) print(suppliers) all_customers.extend(suppliers) break else: retry_count += 1 print(f"请求第 {page} 页失败,正在重试(第 {retry_count} 次)...") time.sleep(3) # try: # except Exception as e: # print(f"请求第 {page} 页失败,错误:", e) # continue # 获取专属运营顾问列表 json_data = { 'includeStopedEmployee': False, 'pageSize': 1000, 'filterNullUser': False, 'keyword': '', 'idOwnOrgList': [], } response = requests.post( 'https://yunxiu.f6car.cn/hive/employee/searchStaffInGroup', cookies=cookies, # headers=headers, json=json_data, ) # Note: json_data will not be serialized by requests # exactly as it was in the original request. # data = '{"includeStopedEmployee":false,"pageSize":10,"filterNullUser":false,"keyword":"","idOwnOrgList":[]}' # response = requests.post('https://yunxiu.f6car.cn/hive/employee/searchStaffInGroup', cookies=cookies, headers=headers, data=data) staff_list = response.json().get("data").get("list") name_to_userid = { emp['name']: emp['userId'] for emp in staff_list if emp['userId'] is not None } df['userId'] = df['专属运营顾问'].map(name_to_userid) def extract_province_city_district(address: Optional[str]) -> Dict[str, Optional[str]]: """安全解析省市区信息,所有返回值都可能为None""" if not address: return {'省': None, '市': None, '区': None} try: pattern = r'(?P<省>(?:[\u4e00-\u9fa5]+(?:省|自治区|特别行政区))?)' \ r'(?P<市>(?:[\u4e00-\u9fa5]+(?:市|自治州|地区|盟))?)' \ r'(?P<区>(?:[\u4e00-\u9fa5]+区|[\u4e00-\u9fa5]+县|[\u4e00-\u9fa5]+旗)?)' match = re.match(pattern, address.strip()) return {k: v if v else None for k, v in match.groupdict().items()} if match else {'省': None, '市': None, '区': None} except Exception: return {'省': None, '市': None, '区': None} def safe_get(d: Optional[Dict], *keys, default=None): """多层字典安全获取值,始终返回可能为None的值""" if not isinstance(d, dict): return default for key in keys: d = d.get(key, {}) if not isinstance(d, dict): break return d if d != {} else default def convert_to_request_data(original_data: Optional[Dict[str, Any]], df: pd.DataFrame) -> Dict[str, Any]: """ 完全安全的字典转换函数 特点: 1. 每个字段的值都可能为None 2. 不会因为任何字段为空而报错 3. 不使用任何默认值,完全保留原始数据的空值状态 """ # 安全获取嵌套数据,所有中间步骤都可能为None customer_info = safe_get(original_data, 'data', 'customerInfo') if original_data else None # 安全解析地址信息(结果中的省市区都可能为None) address_parts = extract_province_city_district( safe_get(customer_info, 'provinceCityAreaName') if customer_info else None ) # 获取当前客户的手机号 cell_phone = safe_get(customer_info, 'cellPhone') # 从DataFrame中查找匹配的专属运营顾问信息 exclusive_info = None df_row = None if cell_phone and not df.empty: matched_rows = df[df['客户手机号'] == cell_phone] if not matched_rows.empty: df_row = matched_rows.iloc[0] exclusive_info = { 'userId': df_row.get('userId'), 'name': df_row.get('专属运营顾问') } # 构建请求数据字典,所有字段都允许为None request_data = { # 标识字段 "pkId": safe_get(customer_info, 'idCustomer'), "idCustomer": safe_get(customer_info, 'idCustomer'), # 基本信息 - 从DataFrame中获取或保留原值 "name": df_row.get('客户姓名') if df_row is not None and pd.notna(df_row.get('客户姓名')) else safe_get( customer_info, 'name'), "sex": safe_get(customer_info, 'sex'), "customerType": df_row.get('客户类型') if df_row is not None and pd.notna(df_row.get('客户类型')) else safe_get( customer_info, 'customerType'), # 来源信息 - 从DataFrame中获取或保留原值 "customerSource": safe_get(customer_info, 'customerSource'), "customerSourceName": df_row.get('客户来源') if df_row is not None and pd.notna( df_row.get('客户来源')) else safe_get(customer_info, 'customerSourceName'), # 联系信息 - 从DataFrame中获取或保留原值 "companyName": df_row.get('单位名称') if df_row is not None and pd.notna(df_row.get('单位名称')) else safe_get( customer_info, 'companyName'), "cellPhone": cell_phone, "wechart": safe_get(customer_info, 'wechart'), "qq": safe_get(customer_info, 'qq'), "contacts": safe_get(customer_info, 'contacts'), "contactTelephone": safe_get(customer_info, 'contactTelephone'), # 地址信息(全部允许为None) "province": safe_get(customer_info, 'province'), "city": safe_get(customer_info, 'city'), "area": safe_get(customer_info, 'area'), "street": safe_get(customer_info, 'street'), "address": safe_get(customer_info, 'address'), "detailAddress": safe_get(customer_info, 'detailAddress'), "pId": safe_get(customer_info, 'province'), "cId": safe_get(customer_info, 'city'), "aId": safe_get(customer_info, 'area'), "provinceName": address_parts.get('省'), "cityName": address_parts.get('市'), "areaName": address_parts.get('区'), "provinceCityAreaName": safe_get(customer_info, 'provinceCityAreaName'), # 时间信息 "birthday": safe_get(customer_info, 'birthday'), "creationtime": safe_get(customer_info, 'creationtime'), "modifiedtime": safe_get(customer_info, 'modifiedtime'), # 系统信息 "creator": safe_get(customer_info, 'creator'), "creatorName": safe_get(customer_info, 'creatorName'), "modifier": safe_get(customer_info, 'modifier'), "idOwnOrg": safe_get(customer_info, 'idOwnOrg'), "idOwnGroup": safe_get(customer_info, 'idOwnGroup'), # 个人资料 "insuranceCompany": safe_get(customer_info, 'insuranceCompany'), "maritalStatus": safe_get(customer_info, 'maritalStatus'), "monthlyIncome": safe_get(customer_info, 'monthlyIncome'), "idNumber": safe_get(customer_info, 'idNumber'), "personHobby": safe_get(customer_info, 'personHobby'), "credentialsType": safe_get(customer_info, 'credentialsType'), # 数值信息 "points": safe_get(customer_info, 'points'), "maxAccountAmount": safe_get(customer_info, 'maxAccountAmount'), "pointsEnable": safe_get(customer_info, 'pointsEnable'), # 会员信息 "level": safe_get(customer_info, 'level'), "memberCardNo": safe_get(customer_info, 'memberCardNo'), "customerLevel": safe_get(customer_info, 'customerLevel'), # 关联信息 "exclusiveConsultantId": exclusive_info['userId'] if exclusive_info else safe_get(customer_info, 'exclusiveConsultantId'), "exclusiveConsultantName": exclusive_info['name'] if exclusive_info else safe_get(customer_info, 'exclusiveConsultantName'), "exclusiveOrgId": safe_get(customer_info, 'exclusiveOrgId'), "exclusiveOrgName": safe_get(customer_info, 'exclusiveOrgName'), # 备注信息 - 从DataFrame中获取或保留原值 "customerMemo": df_row.get('客户备注') if df_row is not None and pd.notna(df_row.get('客户备注')) else safe_get( customer_info, 'customerMemo'), # 其他字段 "isDel": safe_get(customer_info, 'isDel'), "idFrom": safe_get(customer_info, 'idFrom'), "mnemonic": safe_get(customer_info, 'mnemonic'), "idOrgSource": safe_get(customer_info, 'idOrgSource'), "firstArrivalIdSourceBill": safe_get(customer_info, 'firstArrivalIdSourceBill'), "lastArrivalIdSourceBill": safe_get(customer_info, 'lastArrivalIdSourceBill'), "customerInfoType": safe_get(customer_info, 'customerInfoType'), "customerInfoCompleteDate": safe_get(customer_info, 'customerInfoCompleteDate'), "customerInfoCompleteType": safe_get(customer_info, 'customerInfoCompleteType'), "xczUserId": safe_get(customer_info, 'xczUserId'), "xczUuid": safe_get(customer_info, 'xczUuid'), "idWxbCustomer": safe_get(customer_info, 'idWxbCustomer'), "promoteEmployeeId": safe_get(customer_info, 'promoteEmployeeId'), "promoteEmployeeName": safe_get(customer_info, 'promoteEmployeeName'), "promoteMemberId": safe_get(customer_info, 'promoteMemberId'), "promoteMemberName": safe_get(customer_info, 'promoteMemberName'), "driverExpiryDate": safe_get(customer_info, 'driverExpiryDate'), "crmDeleteExclusiveFlag": safe_get(customer_info, 'crmDeleteExclusiveFlag'), "totalObtainPoints": safe_get(customer_info, 'totalObtainPoints'), "totalUsedPoints": safe_get(customer_info, 'totalUsedPoints'), "orgName": safe_get(customer_info, 'orgName'), "weChatFollower": safe_get(customer_info, 'weChatFollower'), "pointsEnableConfig": safe_get(customer_info, 'pointsEnableConfig'), "personalPointsEnableConfig": safe_get(customer_info, 'personalPointsEnableConfig'), "pointsButtonStatus": safe_get(customer_info, 'pointsButtonStatus'), "tmallInstallMember": safe_get(customer_info, 'tmallInstallMember'), "corpId": safe_get(customer_info, 'corpId'), "thirdCorpId": safe_get(customer_info, 'thirdCorpId'), } return request_data new_customers = [] for customer in all_customers: phone = customer.get("cellPhone") if phone in df["客户手机号"].tolist(): print("开始修改") cus_id = customer.get("idCustomer", {}) # 获取客户id cus_response = requests.get(f'https://yunxiu.f6car.cn/member/customer/{cus_id}', cookies=cookies, # headers=headers ) # 做过滤,如果请求结果少于目前条数,则不执行 original_data = cus_response.json() final_json_data = convert_to_request_data(original_data, df) # 修改 response = requests.post( 'https://yunxiu.f6car.cn/member/customer/modifyCustomer', cookies=cookies, # headers=headers, json=final_json_data, ) print("修改完成") time.sleep(1)