244 lines
9.1 KiB
Python
244 lines
9.1 KiB
Python
# -*- coding:UTF-8 -*-
|
||
# 功能:F6系统页面保险机器人状态获取
|
||
|
||
from selenium import webdriver
|
||
from selenium.webdriver.chrome.service import Service
|
||
from selenium.webdriver.support.ui import Select
|
||
from selenium.webdriver import ActionChains
|
||
from selenium.webdriver.common.by import By
|
||
from selenium.webdriver.common.keys import Keys
|
||
from selenium.webdriver.support.ui import WebDriverWait
|
||
from selenium.webdriver.support import expected_conditions as EC
|
||
import time
|
||
import xlrd
|
||
import xlwt
|
||
import re
|
||
from xlutils.copy import copy
|
||
import datetime
|
||
import pandas as pd
|
||
from bs4 import BeautifulSoup
|
||
|
||
# 配置
|
||
name = '13170011097'
|
||
password = 'Aa123456'
|
||
http = 'https://m.f6car.cn/'
|
||
|
||
# 设置 ChromeDriver 路径(Selenium 4+ 使用 Service)
|
||
service = Service(executable_path=r"D:\Program Files\chromedriver-win64\chromedriver-win64\chromedriver.exe")
|
||
options = webdriver.ChromeOptions()
|
||
# options.add_argument('--headless') # 如需无头模式可取消注释
|
||
|
||
# 启动浏览器
|
||
driver = webdriver.Chrome(service=service, options=options)
|
||
driver.maximize_window()
|
||
driver.implicitly_wait(10)
|
||
|
||
# 打开页面并登录
|
||
driver.get(http)
|
||
time.sleep(2)
|
||
|
||
# 输入用户名和密码
|
||
username_input = driver.find_element(By.XPATH, '//*[@id="pane-username"]/form/div[1]/div/div/input')
|
||
password_input = driver.find_element(By.XPATH, '//*[@id="pane-username"]/form/div[2]/div/div[1]/input')
|
||
login_button = driver.find_element(By.XPATH, '//*[@id="pane-username"]/form/div[3]/div/button/span')
|
||
|
||
username_input.send_keys(name)
|
||
password_input.send_keys(password)
|
||
login_button.click()
|
||
|
||
time.sleep(5) # 等待登录完成
|
||
|
||
# 选择门店
|
||
try:
|
||
store_element = WebDriverWait(driver, 20).until(
|
||
EC.element_to_be_clickable(
|
||
(By.XPATH, '//*[@id="app"]/div[2]/div[1]/div[1]/div[2]/div/div/div[2]/div[2]/div/div[1]/div/div[38]'))
|
||
)
|
||
store_element.click()
|
||
except Exception as e:
|
||
print("门店选择失败:", e)
|
||
driver.save_screenshot("error_store_selection.png")
|
||
|
||
time.sleep(2)
|
||
|
||
# 关闭弹窗等操作
|
||
close_element = WebDriverWait(driver, 20).until(
|
||
EC.element_to_be_clickable((By.XPATH, '/html/body/div[3]/div/div[1]/button'))
|
||
)
|
||
close_element.click()
|
||
|
||
close_element2 = WebDriverWait(driver, 20).until(
|
||
EC.element_to_be_clickable((By.XPATH, '//*[@id="subMain"]/div/div[3]/div[1]/div[1]/div/span[2]'))
|
||
)
|
||
close_element2.click()
|
||
|
||
close_element3 = WebDriverWait(driver, 20).until(
|
||
EC.element_to_be_clickable((By.XPATH, '//*[@id="main"]/div[1]/div[1]/div[1]/div/div[2]/div/div[11]/div/div'))
|
||
)
|
||
close_element3.click()
|
||
|
||
# 手动筛选日期
|
||
print("请手动筛选日期")
|
||
time.sleep(10)
|
||
|
||
# 切换到 iframe
|
||
iframe = WebDriverWait(driver, 20).until(
|
||
EC.frame_to_be_available_and_switch_to_it((By.ID, "erp-qiankun-iframe"))
|
||
)
|
||
print("已成功切换到 iframe")
|
||
time.sleep(5)
|
||
|
||
table_data = []
|
||
|
||
# 假设最多翻页到第19页(原逻辑为 range(1,20))
|
||
for i in range(1, 215):
|
||
try:
|
||
tbody_element = WebDriverWait(driver, 20).until(
|
||
EC.presence_of_element_located(
|
||
(By.XPATH, '//*[@id="app"]/div[1]/div[3]/div/div/div[2]/div[3]/div[3]/table/tbody'))
|
||
)
|
||
tbody_html = tbody_element.get_attribute('innerHTML')
|
||
print(f"成功获取第 {i} 页 tbody HTML")
|
||
except Exception as e:
|
||
print("获取 tbody 失败:", e)
|
||
driver.save_screenshot("tbody_error.png")
|
||
break # 不退出,继续尝试下一页或结束
|
||
|
||
# 使用 BeautifulSoup 解析
|
||
soup = BeautifulSoup(tbody_html, 'html.parser')
|
||
rows = soup.find_all('tr', class_='au-table__row')
|
||
|
||
if not rows:
|
||
print("当前页无数据,停止翻页")
|
||
break
|
||
|
||
for tr in rows:
|
||
# 提取门店
|
||
store_elem = tr.select_one('.au-table_1_column_1 .cell span')
|
||
store = store_elem.text.strip() if store_elem else ''
|
||
|
||
# 提取客户姓名、车牌、电话(都在 column_3 的 row-item 按钮中)
|
||
col3_items = tr.select('.au-table_1_column_3 .row-item button span')
|
||
name_val = col3_items[0].text.strip() if len(col3_items) > 0 else ''
|
||
plate = col3_items[1].text.strip() if len(col3_items) > 1 else ''
|
||
phone = col3_items[2].text.strip() if len(col3_items) > 2 else ''
|
||
|
||
# 提取服务顾问(column_4)
|
||
advisor_elem = tr.select_one('.au-table_1_column_4 .cell span')
|
||
advisor = advisor_elem.text.strip() if advisor_elem else ''
|
||
|
||
# --- 提取人工/原始保险信息(column_5)---
|
||
jiaoqiang_expire = ''
|
||
commercial_expire = ''
|
||
insurer = ''
|
||
policy_no = ''
|
||
col5_items = tr.select('.au-table_1_column_5 .row-item-title')
|
||
for item in col5_items:
|
||
text = item.text.strip()
|
||
if '交强险到期日' in text:
|
||
jiaoqiang_expire = text.replace('交强险到期日:', '').strip().replace('-', '').strip()
|
||
elif '商业险到期日' in text:
|
||
commercial_expire = text.replace('商业险到期日:', '').strip().replace('-', '').strip()
|
||
elif '保险公司' in text:
|
||
insurer = text.replace('保险公司:', '').strip()
|
||
elif '保单号' in text:
|
||
policy_no = text.replace('保单号:', '').strip().replace('-', '').strip()
|
||
|
||
# --- 提取保险机器人返回信息(column_6)---
|
||
jiaoqiang_expire1 = ''
|
||
commercial_expire1 = ''
|
||
insurer1 = ''
|
||
policy_no1 = ''
|
||
no_use = ""
|
||
|
||
col6_container = tr.select_one('.au-table_1_column_6')
|
||
if col6_container:
|
||
# 情况1: 未查询 或 查询失败(存在 .no-data)
|
||
no_data_elem = col6_container.select_one('.no-data')
|
||
if no_data_elem:
|
||
span_text = no_data_elem.select_one('span')
|
||
if span_text:
|
||
prompt = span_text.get_text(strip=True)
|
||
if "手动点击“获取保险信息”" in prompt:
|
||
no_use = "手动点击“获取保险信息”"
|
||
elif "查询次数已不足" in prompt:
|
||
no_use = "查询次数已不足,及时充值"
|
||
else:
|
||
no_use = prompt
|
||
else:
|
||
# 情况2: 已成功查询 → 从 .row-item-date 提取
|
||
date_spans = col6_container.select('.row-item-date')
|
||
for span in date_spans:
|
||
text = span.get_text(strip=True) # e.g. "交强险到期日: 2026-10-17"
|
||
if '交强险到期日:' in text:
|
||
jiaoqiang_expire1 = text.split(':', 1)[-1].strip().replace('-', '').strip()
|
||
elif '商业险到期日:' in text:
|
||
commercial_expire1 = text.split(':', 1)[-1].strip().replace('-', '').strip()
|
||
elif '保险公司:' in text:
|
||
insurer1 = text.split(':', 1)[-1].strip()
|
||
elif '保单号:' in text:
|
||
policy_no1 = text.split(':', 1)[-1].strip().replace('-', '').strip()
|
||
|
||
# 提取超期天数(column_8)
|
||
overdue_elem = tr.select_one('.au-table_1_column_8 .text-center')
|
||
overdue = overdue_elem.text.strip() if overdue_elem else ''
|
||
|
||
# 提取跟进状态(checkbox 的 label 文本)
|
||
checkboxes = tr.select('.au-table_1_column_7 .au-checkbox__label')
|
||
follow_status = [cb.text.strip() for cb in checkboxes]
|
||
|
||
# 合并为一行
|
||
row = [
|
||
store,
|
||
name_val,
|
||
plate,
|
||
phone,
|
||
advisor,
|
||
jiaoqiang_expire, # ← 第6列:原始交强险到期日
|
||
commercial_expire,
|
||
insurer,
|
||
policy_no,
|
||
jiaoqiang_expire1, # ← 第10列:机器人返回
|
||
commercial_expire1,
|
||
insurer1,
|
||
policy_no1,
|
||
no_use,
|
||
overdue,
|
||
'; '.join(follow_status)
|
||
]
|
||
table_data.append(row)
|
||
|
||
# 翻页:输入下一页页码
|
||
try:
|
||
next_input = driver.find_element(By.XPATH,
|
||
'//*[@id="app"]/div[1]/div[3]/div/div/div[2]/div[4]/span[1]/div/input')
|
||
|
||
# 更彻底地清空(模拟全选 + 删除)
|
||
next_input.send_keys(Keys.CONTROL + "a") # 全选
|
||
next_input.send_keys(Keys.DELETE) # 删除
|
||
time.sleep(0.3)
|
||
|
||
# 输入下一页
|
||
next_input.send_keys(str(i + 1))
|
||
time.sleep(0.2)
|
||
next_input.send_keys(Keys.ENTER)
|
||
time.sleep(2) # 等待加载
|
||
except Exception as e:
|
||
print(f"翻页失败(第{i}页后):", e)
|
||
break
|
||
|
||
# 转为 DataFrame 并保存
|
||
columns = [
|
||
'门店', '客户姓名', '车牌号', '电话', '服务顾问',
|
||
'交强险到期日', '商业险到期日', '保险公司', '保单号',
|
||
'交强险到期日-机器人', '商业险到期日-机器人', '保险公司-机器人', '保单号-机器人',
|
||
'保险机器人状态',
|
||
'超期状态', '跟进状态'
|
||
]
|
||
df = pd.DataFrame(table_data, columns=columns)
|
||
output_path = r"D:\Idea Project\F6+宜搭+其它(1)\张阳脚本\文件输出\保险机器人状态.csv"
|
||
df.to_csv(output_path, index=False, encoding='utf_8_sig')
|
||
print(f"✅ 数据已保存至: {output_path}")
|
||
|
||
driver.quit()
|