Files
F6--/张阳脚本/F6汽车系统/客户专属运营顾问修改.py
2026-01-30 11:28:35 +08:00

320 lines
14 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)