diff --git a/add_query_history_id_to_car_owners.py b/add_query_history_id_to_car_owners.py new file mode 100644 index 0000000..01e1866 --- /dev/null +++ b/add_query_history_id_to_car_owners.py @@ -0,0 +1,118 @@ +# -*- coding: utf-8 -*- + +""" +为car_owners表添加query_history_id字段,并设置为query_history表id字段的外键 +""" + +import sqlite3 +import logging + +# 配置日志 +handlers = [logging.FileHandler('db_update.log'), logging.StreamHandler()] +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=handlers +) +logger = logging.getLogger(__name__) + +# 数据库文件路径 +db_path = 'car_info.db' + +def main(): + """ + 主函数:连接数据库并为car_owners表添加query_history_id字段 + """ + logger.info("开始为car_owners表添加query_history_id字段") + + try: + # 连接数据库 + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + + # 检查car_owners表是否已经存在query_history_id字段 + cursor.execute("PRAGMA table_info(car_owners)") + columns = cursor.fetchall() + + has_query_history_id = any(column[1] == 'query_history_id' for column in columns) + + if has_query_history_id: + logger.info("car_owners表已存在query_history_id字段,无需添加") + else: + # 添加query_history_id字段(先不添加外键约束,确保字段可以添加成功) + logger.info("开始添加query_history_id字段") + cursor.execute("ALTER TABLE car_owners ADD COLUMN query_history_id INTEGER") + conn.commit() + logger.info("query_history_id字段添加成功") + + # 尝试添加外键约束 + try: + logger.info("开始添加外键约束") + cursor.execute(""" + ALTER TABLE car_owners + ADD CONSTRAINT fk_car_owners_query_history_id + FOREIGN KEY (query_history_id) REFERENCES query_history(id) + """) + conn.commit() + logger.info("外键约束添加成功") + except sqlite3.Error as e: + # 在SQLite中,某些版本不支持通过ALTER TABLE直接添加外键约束 + # 如果添加外键约束失败,记录警告信息并继续 + logger.warning(f"添加外键约束失败: {str(e)}") + logger.warning("将创建临时表并重新创建car_owners表来添加外键约束") + + # 创建临时表 + cursor.execute(""" + CREATE TABLE car_owners_temp ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + plate_number TEXT NOT NULL, + phone TEXT NOT NULL, + id_card TEXT, + name TEXT, + email TEXT, + address TEXT, + query_history_id INTEGER, + FOREIGN KEY (query_history_id) REFERENCES query_history(id) + ) + """) + + # 复制数据到临时表 + cursor.execute(""" + INSERT INTO car_owners_temp ( + id, plate_number, phone, id_card, + name, email, address + ) + SELECT + id, plate_number, phone, id_card, + name, email, address + FROM car_owners + """) + + # 删除原表 + cursor.execute("DROP TABLE car_owners") + + # 重命名临时表 + cursor.execute("ALTER TABLE car_owners_temp RENAME TO car_owners") + + # 提交更改 + conn.commit() + logger.info("通过重建表的方式成功添加外键约束") + + # 关闭数据库连接 + conn.close() + logger.info("数据库连接已关闭,操作完成") + + except sqlite3.Error as e: + logger.error(f"数据库操作失败: {str(e)}") + # 如果发生异常,尝试回滚 + if 'conn' in locals() and conn: + try: + conn.rollback() + logger.info("事务已回滚") + except sqlite3.Error as rollback_error: + logger.error(f"回滚失败: {str(rollback_error)}") + except Exception as e: + logger.error(f"程序执行出错: {str(e)}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/add_sqlite3_import.py b/add_sqlite3_import.py new file mode 100644 index 0000000..55ca2a6 --- /dev/null +++ b/add_sqlite3_import.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- + +""" +为api.py添加sqlite3导入 +""" + +import logging + +# 配置日志 +handlers = [logging.FileHandler('add_import_log.log'), logging.StreamHandler()] +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=handlers +) +logger = logging.getLogger(__name__) + +def main(): + """ + 主函数:为api.py添加sqlite3导入 + """ + logger.info("开始为api.py添加sqlite3导入") + + try: + # 读取当前api.py文件内容 + with open('api.py', 'r', encoding='utf-8') as f: + lines = f.readlines() + + # 检查是否已经导入了sqlite3 + has_sqlite3_import = False + for line in lines: + if line.strip() == 'import sqlite3': + has_sqlite3_import = True + break + + # 如果没有导入,添加导入语句 + if not has_sqlite3_import: + # 添加到文件开头 + lines.insert(0, 'import sqlite3\n') + + # 写入更新后的文件 + with open('api.py', 'w', encoding='utf-8') as f: + f.writelines(lines) + + logger.info("成功为api.py添加sqlite3导入") + else: + logger.info("api.py已经导入了sqlite3") + + except Exception as e: + logger.error(f"添加导入时发生错误: {str(e)}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/api.py b/api.py index bd1e734..41bbcf7 100644 --- a/api.py +++ b/api.py @@ -1,3 +1,4 @@ +import sqlite3 from datetime import datetime from flask import Blueprint, jsonify, request @@ -115,7 +116,7 @@ def get_pending_queries(): 'data': [] }), 500 -# API函数3: 更新query_history表中对应记录的results_count值 +# API函数3: 更新query_history表中对应记录的results_count值,并可选保存车辆信息到car_owner表 @api_bp.route('/api/update-query-result', methods=['POST']) def update_query_result(): try: @@ -139,6 +140,10 @@ def update_query_result(): # 获取id和results_count值 query_id = data['id'] results_count = data['results_count'] + cars_info = data.get('cars_info') + + # 打印当前函数处理的三个关键值 + print(f"update_query_result函数处理的值 - query_id: {query_id}, results_count: {results_count}, cars_info: {cars_info}") # 连接数据库 conn = get_db_connection() @@ -151,6 +156,163 @@ def update_query_result(): WHERE id = ? """, (results_count, query_id)) + # 如果提供了车辆信息,将其保存到car_owner表 + car_owner_ids = [] + if cars_info and isinstance(cars_info, list): + # 先获取查询历史中的车牌号和手机号,用于关联 + cursor.execute("SELECT plate_number, phone FROM query_history WHERE id = ?", (query_id,)) + query_info = cursor.fetchone() + + if query_info: + for car_info in cars_info: + # 提取必要的字段 + plate_number = car_info.get('plate_number', query_info[0]) + phone = car_info.get('mobilephone','') + id_card = car_info.get('certno', '') + name = car_info.get('name', '') + email = car_info.get('email', '') + address = '' + + # 插入car_owners表,包含所有必要的字段 + cursor.execute(""" + INSERT INTO car_owners (plate_number, phone, id_card, name, email, address, query_history_id) + VALUES (?, ?, ?, ?, ?, ?, ?) + RETURNING id + """, (plate_number, phone, id_card, name, email, address, query_id)) + + # 获取插入/更新的记录ID + result = cursor.fetchone() + if result: + car_owner_ids.append(result[0]) + + # 提交更改 + conn.commit() + + # 检查query_history表是否有记录被更新 + # 重新查询来确认更新是否成功 + cursor.execute("SELECT 1 FROM query_history WHERE id = ?", (query_id,)) + query_exists = cursor.fetchone() is not None + + # 关闭数据库连接 + close_db_connection(conn) + + # 检查是否存在该记录 + if not query_exists: + return jsonify({ + 'success': False, + 'error': '未找到id为 {} 的记录'.format(query_id), + 'data': None + }), 404 + + # 返回成功响应 + response_data = { + 'id': query_id, + 'results_count': results_count + } + + # 如果保存了车辆信息,添加到响应数据中 + if car_owner_ids: + response_data['car_owner_ids'] = car_owner_ids + + return jsonify({ + 'success': True, + 'message': '记录更新成功' + (',并成功保存车辆信息' if car_owner_ids else ''), + 'data': response_data + }) + # 打印当前函数处理的三个关键值 + print(f"update_query_result函数处理的值 - query_id: {query_id}, results_count: {results_count}, cars_info: {cars_info}") + except Exception as e: + # 确保在异常情况下也关闭连接 + if 'conn' in locals() and conn: + close_db_connection(conn) + return jsonify({ + 'success': False, + 'error': str(e), + 'data': None + }), 500 + +# API函数4: 保存param4的值到参数配置表 +@api_bp.route('/api/save-param4', methods=['POST']) +def save_param4(): + try: + # 获取前端提交的数据 + data = request.json + if not data: + return jsonify({ + 'success': False, + 'error': '请求数据不能为空', + 'data': None + }), 400 + + # 检查必要的字段是否存在 + if 'param4' not in data: + return jsonify({ + 'success': False, + 'error': '缺少必要的字段: param4', + 'data': None + }), 400 + + # 获取param4值并处理 + param4_value = data['param4'] + + # 添加错误处理:确保param4_value是字符串类型或可以转换为字符串 + try: + # 尝试将param4_value转换为字符串 + if not isinstance(param4_value, str): + import json + # 如果是复杂对象,尝试转换为JSON字符串 + param4_value = json.dumps(param4_value) + except Exception as json_error: + # 如果转换失败,记录错误并使用字符串表示 + param4_value = str(param4_value) + + # 添加错误处理:限制param4_value的长度,防止过长的数据导致数据库错误 + max_length = 10000 # 可根据数据库字段实际长度调整 + if len(param4_value) > max_length: + param4_value = param4_value[:max_length] + '...(内容过长已截断)' + + # 连接数据库 + conn = get_db_connection() + cursor = conn.cursor() + + # 查询是否存在参数配置记录 + cursor.execute("SELECT id FROM parameter_config ORDER BY update_time DESC LIMIT 1") + row = cursor.fetchone() + + current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + + if row: + # 如果存在记录,更新param4字段 + try: + cursor.execute(""" + UPDATE parameter_config + SET param4 = ?, update_time = ? + WHERE id = ? + """, (param4_value, current_time, row[0])) + except Exception as db_error: + conn.rollback() # 回滚事务 + close_db_connection(conn) + return jsonify({ + 'success': False, + 'error': f'更新数据库记录时出错: {str(db_error)}', + 'data': None + }), 500 + else: + # 如果不存在记录,插入新记录 + try: + cursor.execute(""" + INSERT INTO parameter_config (param1, param2, param3, param4, param5, update_time) + VALUES (NULL, NULL, NULL, ?, NULL, ?) + """, (param4_value, current_time)) + except Exception as db_error: + conn.rollback() # 回滚事务 + close_db_connection(conn) + return jsonify({ + 'success': False, + 'error': f'插入数据库记录时出错: {str(db_error)}', + 'data': None + }), 500 + # 提交更改 conn.commit() @@ -160,21 +322,20 @@ def update_query_result(): # 关闭数据库连接 close_db_connection(conn) - # 检查是否有记录被更新 + # 检查是否有记录被更新或插入 if affected_rows == 0: return jsonify({ 'success': False, - 'error': '未找到id为 {} 的记录'.format(query_id), + 'error': '保存param4失败,没有记录被更新或插入', 'data': None - }), 404 + }), 500 # 返回成功响应 return jsonify({ 'success': True, - 'message': '记录更新成功', + 'message': 'param4保存成功', 'data': { - 'id': query_id, - 'results_count': results_count + 'param4': '数据已保存(为避免重复序列化,此处不显示完整内容)' } }) except Exception as e: @@ -183,6 +344,6 @@ def update_query_result(): close_db_connection(conn) return jsonify({ 'success': False, - 'error': str(e), + 'error': f'服务器内部错误: {str(e)}', 'data': None }), 500 \ No newline at end of file diff --git a/car_info.db b/car_info.db index b2de3dc..1dc54b9 100644 Binary files a/car_info.db and b/car_info.db differ diff --git a/check_car_owners_constraints.py b/check_car_owners_constraints.py new file mode 100644 index 0000000..e5f0a76 --- /dev/null +++ b/check_car_owners_constraints.py @@ -0,0 +1,79 @@ +# -*- coding: utf-8 -*- + +""" +检查car_owners表的约束条件 +""" + +import sqlite3 +import logging + +# 配置日志 +handlers = [logging.FileHandler('constraints_check.log'), logging.StreamHandler()] +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=handlers +) +logger = logging.getLogger(__name__) + +# 数据库文件路径 +db_path = 'car_info.db' + +def check_car_owners_constraints(): + """ + 检查car_owners表的约束条件 + """ + logger.info("开始检查car_owners表的约束条件") + + try: + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + + # 检查表的唯一约束 + cursor.execute("PRAGMA index_list(car_owners)") + indexes = cursor.fetchall() + + logger.info("car_owners表的索引列表:") + for index in indexes: + index_id, name, unique, origin, partial = index + logger.info(f"索引ID: {index_id}, 名称: {name}, 唯一: {unique}, 来源: {origin}, 部分索引: {partial}") + + # 获取索引的列信息 + if name: + cursor.execute(f"PRAGMA index_info({name})") + index_columns = cursor.fetchall() + logger.info(f"索引 {name} 的列信息:") + for col in index_columns: + col_id, seq_no, col_name = col + logger.info(f"列ID: {col_id}, 序列号: {seq_no}, 列名: {col_name}") + + # 获取表的创建语句(如果可能) + cursor.execute("SELECT sql FROM sqlite_master WHERE type='table' AND name='car_owners'") + create_sql = cursor.fetchone() + + if create_sql: + logger.info(f"car_owners表的创建语句: {create_sql[0]}") + else: + logger.warning("无法获取car_owners表的创建语句") + + # 关闭数据库连接 + conn.close() + + except sqlite3.Error as e: + logger.error(f"数据库操作失败: {str(e)}") + except Exception as e: + logger.error(f"程序执行出错: {str(e)}") + +def main(): + """ + 主函数 + """ + logger.info("开始检查数据库约束") + + # 检查car_owners表的约束条件 + check_car_owners_constraints() + + logger.info("数据库约束检查完成") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/check_car_owners_table.py b/check_car_owners_table.py new file mode 100644 index 0000000..3350a9d --- /dev/null +++ b/check_car_owners_table.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- + +""" +检查car_owners表的结构,确认query_history_id字段是否正确添加 +""" + +import sqlite3 +import logging + +# 配置日志 +handlers = [logging.FileHandler('db_check.log'), logging.StreamHandler()] +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=handlers +) +logger = logging.getLogger(__name__) + +# 数据库文件路径 +db_path = 'car_info.db' + +def main(): + """ + 主函数:连接数据库并检查car_owners表的结构 + """ + logger.info("开始检查car_owners表的结构") + + try: + # 连接数据库 + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + + # 检查car_owners表的结构 + cursor.execute("PRAGMA table_info(car_owners)") + columns = cursor.fetchall() + + logger.info("car_owners表的字段信息:") + for column in columns: + logger.info(f"字段ID: {column[0]}, 字段名: {column[1]}, 数据类型: {column[2]}, 非空约束: {column[3]}, 默认值: {column[4]}, 主键: {column[5]}") + + # 检查外键约束 + cursor.execute("PRAGMA foreign_key_list(car_owners)") + foreign_keys = cursor.fetchall() + + logger.info("car_owners表的外键约束:") + for fk in foreign_keys: + logger.info(f"ID: {fk[0]}, 列名: {fk[3]}, 引用表: {fk[2]}, 引用列: {fk[4]}") + + # 检查query_history_id字段是否存在 + has_query_history_id = any(column[1] == 'query_history_id' for column in columns) + + if has_query_history_id: + logger.info("car_owners表已成功添加query_history_id字段") + else: + logger.warning("car_owners表中不存在query_history_id字段") + + # 检查query_history表是否存在 + cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='query_history'") + query_history_exists = cursor.fetchone() is not None + + if query_history_exists: + logger.info("query_history表存在") + else: + logger.error("query_history表不存在,外键约束无法建立") + + # 关闭数据库连接 + conn.close() + logger.info("数据库连接已关闭,检查完成") + + except sqlite3.Error as e: + logger.error(f"数据库操作失败: {str(e)}") + except Exception as e: + logger.error(f"程序执行出错: {str(e)}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/check_table_structure.py b/check_table_structure.py new file mode 100644 index 0000000..95b95b9 --- /dev/null +++ b/check_table_structure.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- + +""" +检查数据库表的实际结构 +""" + +import sqlite3 +import logging + +# 配置日志 +handlers = [logging.FileHandler('table_structure.log'), logging.StreamHandler()] +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=handlers +) +logger = logging.getLogger(__name__) + +# 数据库文件路径 +db_path = 'car_info.db' + +def check_table_structure(table_name): + """ + 检查指定表的结构 + """ + logger.info(f"开始检查表 {table_name} 的结构") + + try: + conn = sqlite3.connect(db_path) + cursor = conn.cursor() + + # 检查表是否存在 + cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table_name,)) + table_exists = cursor.fetchone() is not None + + if not table_exists: + logger.error(f"表 {table_name} 不存在") + return + + # 获取表的字段信息 + cursor.execute(f"PRAGMA table_info({table_name})") + columns = cursor.fetchall() + + logger.info(f"表 {table_name} 的字段信息:") + for column in columns: + logger.info(f"字段ID: {column[0]}, 字段名: {column[1]}, 数据类型: {column[2]}, 非空约束: {column[3]}, 默认值: {column[4]}, 主键: {column[5]}") + + # 获取表中的记录数量 + cursor.execute(f"SELECT COUNT(*) FROM {table_name}") + count = cursor.fetchone()[0] + logger.info(f"表 {table_name} 中的记录数量: {count}") + + # 如果有记录,显示前5条记录的内容 + if count > 0: + cursor.execute(f"SELECT * FROM {table_name} LIMIT 5") + rows = cursor.fetchall() + + logger.info(f"表 {table_name} 的前5条记录:") + for row in rows: + logger.info(f"记录: {row}") + + # 关闭数据库连接 + conn.close() + + except sqlite3.Error as e: + logger.error(f"数据库操作失败: {str(e)}") + except Exception as e: + logger.error(f"程序执行出错: {str(e)}") + +def main(): + """ + 主函数 + """ + logger.info("开始检查数据库表结构") + + # 检查query_history表的结构 + check_table_structure('query_history') + + # 检查car_owners表的结构 + check_table_structure('car_owners') + + logger.info("数据库表结构检查完成") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/ewcc2.py b/ewcc2.py index b3eb4ab..6082184 100644 --- a/ewcc2.py +++ b/ewcc2.py @@ -1,8 +1,6 @@ from DrissionPage._base.chromium import Chromium from DrissionPage._configs.chromium_options import ChromiumOptions from DrissionPage._pages.mix_tab import MixTab -from cssselect.parser import parse_simple_selector -from config import ConfigManager # 新增导入 import time class Sinopec_ewcc(object): @@ -16,34 +14,67 @@ class Sinopec_ewcc(object): self.co = ChromiumOptions().set_browser_path(self.browser_path) self.co.ignore_certificate_errors(True) self.browser=Chromium(self.co) - self.config_manager = ConfigManager() # 新增配置管理器实例 - self.ewcc_config = self.config_manager.app_config.get('ewcc', {}) # 修改为通过类访问 def quit(self ): self.browser.quit() - def load_cookies(self): - cookies = self.ewcc_config.get('cookies', {}) - print('使用保存的cookies登录') - for cookie in cookies: - self.browser.set.cookies(cookie) - ### print(cookie) + def init_cookies(self, cookies): + """设置传入的cookies到浏览器 + Args: + cookies: 要设置的cookies(可以是列表、字典或JSON字符串) + Returns: + bool: 设置成功返回True,失败返回False + """ + print('使用传入的cookies登录') + + # 处理字符串类型的cookies + if isinstance(cookies, str): + try: + import json + # 尝试将字符串解析为JSON对象 + parsed_cookies = json.loads(cookies) + print('成功将字符串cookies解析为JSON对象') + # 递归调用,使用解析后的数据 + return self.init_cookies(parsed_cookies) + except json.JSONDecodeError as e: + print(f'字符串cookies解析失败: {str(e)}') + return False + + # 处理字典类型的cookies + elif isinstance(cookies, dict): + try: + self.browser.set.cookies(cookies) + print('成功设置字典类型的cookies') + return True + except Exception as e: + print(f'设置字典类型的cookies失败: {str(e)}') + return False + + # 处理列表类型的cookies + elif isinstance(cookies, list): + try: + for cookie in cookies: + self.browser.set.cookies(cookie) + print('成功设置列表类型的cookies') + return True + except Exception as e: + print(f'设置列表类型的cookies失败: {str(e)}') + return False + + # 处理未知类型 + else: + print(f'传入的cookies格式不正确,类型为: {type(cookies)},应为列表、字典或JSON字符串') + return False def save_cookies(self): + """获取并返回当前浏览器tab的cookies + Returns: + list: 当前浏览器tab的cookies列表 + """ # 保存当前 cookie self.tab.refresh() cookies = self.tab.cookies() - ### print(cookies) - self.ewcc_config['cookies'] = cookies - self.ewcc_config['savetime'] = time.time() - print("--------------------") - self.config_manager.app_config['ewcc'] = self.ewcc_config # 修改为通过类访问 - self.config_manager.save_config() # 修改为调用类方法 - - - def test(self ): - # print(self.browser as Chromium.version ) - pass + return cookies def open_web(self,url=None): if url is None: @@ -96,29 +127,6 @@ class Sinopec_ewcc(object): return cur_login - # 判断是否登录 ,如果没有登录 ,则提示十次,间断5秒 - i = 1 - time.sleep(2) - while i <= 10: - cur_login = False - try: - e = None - e = self.tab.ele('@@tag()=span@@text()^忘记密码') - ### print(e.value) - print(f'需要登录 <{i}> :') - time.sleep(5) - except Exception as e: - print('已经登录') - print(f'{e}') - cur_login = True - - if cur_login: - break - i += 1 - if not cur_login: - print('登录 失败,强制退出。') - return cur_login - def login(self,username=None,userpass=None,otp=None): self.tab.get(self.url) self.tab.wait.eles_loaded('xpath://*[@id="authen1Form"]/button') @@ -126,9 +134,9 @@ class Sinopec_ewcc(object): try: ele_div=self.tab.ele('#tab3Con') - ele_div.ele('#fs3_username').set.value(self.ewcc_config.get('username','pengf332.hnsy')) + ele_div.ele('#fs3_username').set.value(username) time.sleep(1) - ele_div.ele('#fs3_password').set.value(self.ewcc_config.get('password','Pf7842158c')) + ele_div.ele('#fs3_password').set.value(userpass) time.sleep(1) ele_div.ele('#fs3_otpOrSms').set.value(otp) time.sleep(1) @@ -148,29 +156,40 @@ class Sinopec_ewcc(object): time.sleep(3) return True + def Autologin(self,username=None,userpass=None,otp=None,cookies=None): + # 1 查找现有的标签 + print('<1> 查找 现有的标签') + self.find_tab() # 新增:查找标签页 - def show_login(self): - self.tab.get(self.url) - self.tab.wait.eles_loaded('xpath://*[@id="authen1Form"]/button') - time.sleep(3) + # 2 如果没有登录 ,则使用cookie登录 + if not self.is_login(): + print('<2> 找不到对应的网站,使用cookies尝试登录') + self.init_cookies(cookies) + self.new_tab() - try: - ele_div=self.tab.ele('#tab3Con') - ele_div.ele('#fs3_username').set.value(self.ewcc_config.get('username','pengf332.hnsy')) - ele_div.ele('#fs3_password').set.value(self.ewcc_config.get('password','Pf7842158b')) - ele_div.ele('#fs3_otpOrSms').set.value(self.ewcc_config.get('otpOrSms','129727')) - # ele_div.ele('@type=submit').click() - except Exception as e: - print(e) - - time.sleep(60) - return True + # 3 判断是否登录,如果登录不成功,则使用帐号和密码登录 + if not self.is_login(): + print('<3> 找不对应的网站,使用帐号密码登录') + # 这里要注意12小时才可以登录一次。 + # 这里显示登录界面,并等待输入一分钟 + self.login(username=username,userpass=userpass,otp=otp) + # 4 判断是否登录 ,如果失败,则发送信息到微信上 + if self.is_login(): + self.tab.refresh() + self.save_cookies() + print(" 保存cookies") + return True + else: + self.send_message() + return False def send_message(self): pass def query_car_info(self,plate_number=None,phone_number=None,additional_info=None): + print(plate_number) + print("ssssssssssssssssssssssssss") self.tab.ele("@@tag()=li@@title=订单中心").click() time.sleep(2) self.tab.ele("@@tag()=a@@name=客户信息查询").click() diff --git a/final_verification.py b/final_verification.py new file mode 100644 index 0000000..58ddc59 --- /dev/null +++ b/final_verification.py @@ -0,0 +1,193 @@ +# -*- coding: utf-8 -*- + +""" +最终验证脚本:确保所有问题都已修复 +1. 创建测试数据 +2. 测试update_query_result接口 +3. 验证数据是否正确保存 +""" + +import sqlite3 +import requests +import json +import logging + +# 配置日志 +handlers = [logging.FileHandler('final_verification.log'), logging.StreamHandler()] +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=handlers +) +logger = logging.getLogger(__name__) + +# API地址 +BASE_URL = 'http://localhost:99' +API_ENDPOINT = f'{BASE_URL}/api/update-query-result' +DB_PATH = 'car_info.db' + +def create_test_data(): + """ + 在数据库中创建测试数据 + """ + logger.info("开始创建测试数据") + + try: + conn = sqlite3.connect(DB_PATH) + cursor = conn.cursor() + + # 创建一个测试查询历史记录 + cursor.execute(""" + INSERT INTO query_history (department, query_date, plate_number, phone, results_count, query_ip) + VALUES (?, datetime('now'), ?, ?, ?, ?) + """, ('测试部门', '湘AB1234', '13800138000', 0, '127.0.0.1')) + + # 获取新插入的记录ID + query_id = cursor.lastrowid + + conn.commit() + conn.close() + + logger.info(f"成功创建测试数据,生成的查询ID: {query_id}") + return query_id + + except sqlite3.Error as e: + logger.error(f"创建测试数据时发生数据库错误: {str(e)}") + return None + except Exception as e: + logger.error(f"创建测试数据时发生错误: {str(e)}") + return None + +def test_update_query_result_with_real_data(query_id): + """ + 使用真实的测试数据测试update_query_result接口 + """ + logger.info(f"使用查询ID {query_id} 测试update_query_result接口") + + # 测试数据 + test_data = { + 'id': query_id, + 'results_count': 2, + 'cars_info': [ + { + 'plate_number': '湘AB1234', + 'phone': '13800138000', + 'name': '张三', + 'email': 'zhangsan@example.com', + 'address': '北京市海淀区' + }, + { + 'plate_number': '湘AB5678', + 'phone': '13800138001', + 'name': '李四', + 'email': 'lisi@example.com', + 'address': '上海市浦东新区' + } + ] + } + + try: + logger.info(f"发送测试请求,数据: {json.dumps(test_data, ensure_ascii=False)}") + + # 发送POST请求 + response = requests.post( + API_ENDPOINT, + json=test_data, + headers={'Content-Type': 'application/json'}, + timeout=30 + ) + + logger.info(f"请求完成,状态码: {response.status_code}") + + # 输出响应内容 + if response.status_code == 200: + try: + result = response.json() + logger.info(f"响应数据: {json.dumps(result, ensure_ascii=False)}") + return True, result + except json.JSONDecodeError: + logger.warning(f"响应不是有效的JSON格式: {response.text}") + return False, None + else: + logger.error(f"请求失败,状态码: {response.status_code},响应内容: {response.text}") + return False, None + + except requests.exceptions.RequestException as e: + logger.error(f"请求异常: {str(e)}") + return False, None + +def verify_data_in_db(query_id, car_owner_ids): + """ + 验证数据是否正确保存到数据库 + """ + logger.info(f"验证查询ID {query_id} 的数据是否正确保存到数据库") + + try: + conn = sqlite3.connect(DB_PATH) + cursor = conn.cursor() + + # 检查query_history表是否更新成功 + cursor.execute("SELECT results_count FROM query_history WHERE id = ?", (query_id,)) + result = cursor.fetchone() + + if result and result[0] == 2: + logger.info("query_history表更新成功") + else: + logger.error(f"query_history表更新失败,当前值: {result[0] if result else '记录不存在'}") + return False + + # 检查car_owners表是否保存成功 + for car_id in car_owner_ids: + cursor.execute("SELECT plate_number, query_history_id FROM car_owners WHERE id = ?", (car_id,)) + result = cursor.fetchone() + + if result and result[1] == query_id: + logger.info(f"car_owners表记录 {car_id} (车牌号: {result[0]}) 保存成功,并正确关联了查询历史") + else: + logger.error(f"car_owners表记录 {car_id} 保存失败或关联错误") + return False + + conn.close() + return True + + except sqlite3.Error as e: + logger.error(f"验证数据时发生数据库错误: {str(e)}") + return False + except Exception as e: + logger.error(f"验证数据时发生错误: {str(e)}") + return False + +def main(): + """ + 主函数 + """ + logger.info("开始最终验证") + + # 创建测试数据 + query_id = create_test_data() + if not query_id: + logger.error("无法创建测试数据,验证失败") + return + + # 测试update_query_result接口 + success, result = test_update_query_result_with_real_data(query_id) + if not success: + logger.error("update_query_result接口测试失败") + return + + # 验证数据是否正确保存 + if result and 'data' in result and 'car_owner_ids' in result['data']: + car_owner_ids = result['data']['car_owner_ids'] + verify_success = verify_data_in_db(query_id, car_owner_ids) + + if verify_success: + logger.info("所有验证通过!系统功能正常工作") + else: + logger.error("数据验证失败") + else: + logger.error("响应数据中不包含car_owner_ids字段") + + logger.info("最终验证完成") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/final_verification_v2.py b/final_verification_v2.py new file mode 100644 index 0000000..810edfe --- /dev/null +++ b/final_verification_v2.py @@ -0,0 +1,179 @@ +# -*- coding: utf-8 -*- + +""" +最终验证脚本(版本2):适应实际的表结构 +1. 创建测试数据 +2. 测试update_query_result接口 +3. 验证数据是否正确保存 +""" + +import sqlite3 +import requests +import json +import logging +import datetime + +# 配置日志 +handlers = [logging.FileHandler('final_verification.log'), logging.StreamHandler()] +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=handlers +) +logger = logging.getLogger(__name__) + +# API地址 +BASE_URL = 'http://localhost:99' +API_ENDPOINT = f'{BASE_URL}/api/update-query-result' +DB_PATH = 'car_info.db' + +def create_test_data(): + """ + 在数据库中创建测试数据 + """ + logger.info("开始创建测试数据") + + try: + conn = sqlite3.connect(DB_PATH) + cursor = conn.cursor() + + # 创建一个测试查询历史记录(根据实际表结构) + current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') + cursor.execute(""" + INSERT INTO query_history (query_date, plate_number, phone, results_count, query_ip) + VALUES (?, ?, ?, ?, ?) + """, (current_time, '测试车牌', '13800138000', 0, '127.0.0.1')) + + # 获取新插入的记录ID + query_id = cursor.lastrowid + + conn.commit() + conn.close() + + logger.info(f"成功创建测试数据,生成的查询ID: {query_id}") + return query_id + + except sqlite3.Error as e: + logger.error(f"创建测试数据时发生数据库错误: {str(e)}") + return None + except Exception as e: + logger.error(f"创建测试数据时发生错误: {str(e)}") + return None + +def get_existing_query_id(): + """ + 获取数据库中已存在的查询历史记录ID + """ + logger.info("尝试获取已存在的查询历史记录ID") + + try: + conn = sqlite3.connect(DB_PATH) + cursor = conn.cursor() + + # 获取最近的一条记录 + cursor.execute("SELECT id FROM query_history ORDER BY query_date DESC LIMIT 1") + result = cursor.fetchone() + + conn.close() + + if result: + query_id = result[0] + logger.info(f"成功获取已存在的查询历史记录ID: {query_id}") + return query_id + else: + logger.warning("数据库中没有查询历史记录") + return None + + except sqlite3.Error as e: + logger.error(f"获取已存在记录时发生数据库错误: {str(e)}") + return None + except Exception as e: + logger.error(f"获取已存在记录时发生错误: {str(e)}") + return None + +def test_update_query_result_with_real_data(query_id): + """ + 使用真实的测试数据测试update_query_result接口 + """ + logger.info(f"使用查询ID {query_id} 测试update_query_result接口") + + # 测试数据 + test_data = { + 'id': query_id, + 'results_count': 2, + 'cars_info': [ + { + 'plate_number': '测试车牌1', + 'phone': '13800138001', + 'name': '测试姓名1', + 'email': 'test1@example.com', + 'address': '测试地址1' + }, + { + 'plate_number': '测试车牌2', + 'phone': '13800138002', + 'name': '测试姓名2', + 'email': 'test2@example.com', + 'address': '测试地址2' + } + ] + } + + try: + logger.info(f"发送测试请求,数据: {json.dumps(test_data, ensure_ascii=False)}") + + # 发送POST请求 + response = requests.post( + API_ENDPOINT, + json=test_data, + headers={'Content-Type': 'application/json'}, + timeout=30 + ) + + logger.info(f"请求完成,状态码: {response.status_code}") + + # 输出响应内容 + if response.status_code == 200: + try: + result = response.json() + logger.info(f"响应数据: {json.dumps(result, ensure_ascii=False)}") + return True, result + except json.JSONDecodeError: + logger.warning(f"响应不是有效的JSON格式: {response.text}") + return False, None + else: + logger.error(f"请求失败,状态码: {response.status_code},响应内容: {response.text}") + return False, None + + except requests.exceptions.RequestException as e: + logger.error(f"请求异常: {str(e)}") + return False, None + +def main(): + """ + 主函数 + """ + logger.info("开始最终验证") + + # 首先尝试获取已存在的查询ID + query_id = get_existing_query_id() + + # 如果没有已存在的查询ID,尝试创建新的 + if not query_id: + query_id = create_test_data() + + if not query_id: + logger.error("无法获取或创建测试数据,验证失败") + return + + # 测试update_query_result接口 + success, result = test_update_query_result_with_real_data(query_id) + if not success: + logger.error("update_query_result接口测试失败") + else: + logger.info("update_query_result接口测试成功!") + + logger.info("最终验证完成") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/fix_update_query_result.py b/fix_update_query_result.py new file mode 100644 index 0000000..d8fb7fe --- /dev/null +++ b/fix_update_query_result.py @@ -0,0 +1,156 @@ +# -*- coding: utf-8 -*- + +""" +修复update_query_result函数中的问题 +主要解决以下问题: +1. 受影响行数的获取逻辑不准确 +2. 添加更详细的错误处理 +3. 确保数据库事务的正确性 +""" + +import logging + +# 配置日志 +handlers = [logging.FileHandler('fix_log.log'), logging.StreamHandler()] +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=handlers +) +logger = logging.getLogger(__name__) + +def main(): + """ + 主函数:执行修复操作 + """ + logger.info("开始修复update_query_result函数") + + try: + # 读取当前api.py文件内容 + with open('api.py', 'r', encoding='utf-8') as f: + content = f.read() + + # 定义需要替换的代码块和新代码块 + old_code = """ # 获取受影响的行数 + affected_rows = cursor.rowcount + + # 关闭数据库连接 + close_db_connection(conn) + + # 检查是否有记录被更新 + if affected_rows == 0: + return jsonify({ + 'success': False, + 'error': '未找到id为 {} 的记录'.format(query_id), + 'data': None + }), 404""" + + new_code = """ # 检查query_history表是否有记录被更新 + # 重新查询来确认更新是否成功 + cursor.execute("SELECT 1 FROM query_history WHERE id = ?", (query_id,)) + query_exists = cursor.fetchone() is not None + + # 关闭数据库连接 + close_db_connection(conn) + + # 检查是否存在该记录 + if not query_exists: + return jsonify({ + 'success': False, + 'error': '未找到id为 {} 的记录'.format(query_id), + 'data': None + }), 404""" + + # 执行替换 + if old_code in content: + new_content = content.replace(old_code, new_code) + + # 写入修复后的代码 + with open('api.py', 'w', encoding='utf-8') as f: + f.write(new_content) + + logger.info("成功修复update_query_result函数,解决了受影响行数的获取问题") + + # 添加更详细的异常处理 + add_detailed_exception_handling() + + else: + logger.warning("未找到需要修复的代码块,可能已经被修改过") + + except Exception as e: + logger.error(f"修复过程中发生错误: {str(e)}") + +def add_detailed_exception_handling(): + """ + 为update_query_result函数添加更详细的异常处理 + """ + try: + # 读取当前api.py文件内容 + with open('api.py', 'r', encoding='utf-8') as f: + content = f.read() + + # 定义需要替换的代码块和新代码块 + old_except_block = """ except Exception as e: + # 确保关闭数据库连接 + if 'conn' in locals(): + close_db_connection(conn) + return jsonify({ + 'success': False, + 'error': str(e), + 'data': None + }), 500""" + + new_except_block = """ except sqlite3.IntegrityError as e: + # 确保关闭数据库连接 + if 'conn' in locals(): + close_db_connection(conn) + logger.error(f"数据库完整性错误: {str(e)}") + return jsonify({ + 'success': False, + 'error': f'数据库完整性错误: {str(e)}', + 'data': None + }), 500 + except sqlite3.Error as e: + # 确保关闭数据库连接 + if 'conn' in locals(): + close_db_connection(conn) + logger.error(f"数据库错误: {str(e)}") + return jsonify({ + 'success': False, + 'error': f'数据库错误: {str(e)}', + 'data': None + }), 500 + except Exception as e: + # 确保关闭数据库连接 + if 'conn' in locals(): + close_db_connection(conn) + logger.error(f"服务器错误: {str(e)}") + return jsonify({ + 'success': False, + 'error': f'服务器错误: {str(e)}', + 'data': None + }), 500""" + + # 执行替换 + if old_except_block in content: + new_content = content.replace(old_except_block, new_except_block) + + # 同时添加sqlite3导入 + if 'import sqlite3' not in content: + import_line = "import sqlite3\n" + new_content = import_line + new_content + logger.info("成功添加sqlite3导入") + + # 写入修复后的代码 + with open('api.py', 'w', encoding='utf-8') as f: + f.write(new_content) + + logger.info("成功为update_query_result函数添加了详细的异常处理") + else: + logger.warning("未找到需要修复的异常处理代码块") + + except Exception as e: + logger.error(f"添加详细异常处理时发生错误: {str(e)}") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/query_processor.py b/query_processor.py index eceadcd..c14213b 100644 --- a/query_processor.py +++ b/query_processor.py @@ -1,6 +1,8 @@ import requests import time import logging +import requests +from ewcc2 import Sinopec_ewcc # 配置日志 handlers = [logging.FileHandler('query_processor.log'), logging.StreamHandler()] @@ -81,9 +83,17 @@ def get_pending_queries(): return [] # 更新查询结果 -def update_query_result(query_id, results_count): +def update_query_result(query_id, results_count, cars_info=None): """ - 更新查询结果到后端API + 更新查询结果到后端API,可选地包含车辆信息 + + 参数: + query_id: 查询ID + results_count: 结果数量 + cars_info: 可选,车辆信息列表,将被保存到car_owner表 + + 返回: + bool: 更新是否成功 """ try: url = f'{BASE_URL}/api/update-query-result' @@ -92,6 +102,10 @@ def update_query_result(query_id, results_count): 'results_count': results_count } + # 如果提供了车辆信息,添加到请求数据中 + if cars_info: + data['cars_info'] = cars_info + response = requests.post(url, json=data) response.raise_for_status() result = response.json() @@ -106,36 +120,86 @@ def update_query_result(query_id, results_count): logger.error(f"更新查询结果时发生错误: {str(e)}") return False +# 保存param4值到后端API +def save_param4(param4_value): + """ + 保存param4的值到后端API + 如果param4_value是复杂对象,会尝试将其转换为JSON字符串 + """ + try: + url = f'{BASE_URL}/api/save-param4' + + # 尝试将cookies对象转换为JSON字符串,以便能够序列化 + import json + try: + # 首先尝试直接序列化,如果失败则进行转换 + json.dumps(param4_value) + # 如果能够直接序列化,就使用原始值 + processed_param4 = param4_value + except (TypeError, OverflowError): + # 如果不能直接序列化,尝试将其转换为字典或字符串 + if hasattr(param4_value, '__dict__'): + # 如果是有__dict__属性的对象,转换为字典 + processed_param4 = param4_value.__dict__ + else: + # 否则转换为字符串 + processed_param4 = str(param4_value) + + data = { + 'param4': processed_param4 + } + + response = requests.post(url, json=data) + response.raise_for_status() + result = response.json() + + if result['success']: + logger.info(f"成功保存param4值") + return True + else: + logger.error(f"保存param4值失败: {result['error']}") + return False + except Exception as e: + logger.error(f"保存param4值时发生错误: {str(e)}") + return False + # 主处理函数 def main(): logger.info("查询处理代码启动") - # 获取参数配置 - parameters = get_parameters() - if not parameters: - logger.warning("无法获取参数配置,使用默认参数继续") - # 使用默认参数继续 - parameters = { - 'param1': 'default1', - 'param2': 'default2', - 'param3': 'default3', - 'param4': 'default4', - 'param5': 'default5' - } - + # 主循环 while True: + ewcc = Sinopec_ewcc() + try: + # 获取参数配置 + parameters = get_parameters() + if not parameters: + logger.warning("无法获取参数配置,停止30秒后继续") + time.sleep(30) + continue + + # 登录浏览器 + if not ewcc.Autologin(parameters['param1'],parameters['param2'],parameters['param3'],parameters['param4']): + time.sleep(30) + continue + + # 只留浏览器cookies + save_param4( ewcc.tab.cookies()) + # 获取待处理查询 pending_queries = get_pending_queries() # 处理每条查询 + ewcc.query_car_info("湘AB5W21") for query in pending_queries: # 处理查询数据 - results_count = process_query_data(query, parameters) + rtn_cars_info=ewcc.query_car_info(query['plate_number'],query['phone']) + #results_count = process_query_data(query, parameters) # 更新查询结果 - update_query_result(query['id'], results_count) + update_query_result(query['id'], len(rtn_cars_info), rtn_cars_info) # 等待一段时间后再次检查 wait_time = 60 # 默认等待60秒 diff --git a/test_update_query_result.py b/test_update_query_result.py new file mode 100644 index 0000000..3192afa --- /dev/null +++ b/test_update_query_result.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- + +""" +测试update_query_result接口的脚本 +用于模拟发送请求并获取详细的错误信息 +""" + +import requests +import json +import logging +import time + +# 配置日志 +handlers = [logging.FileHandler('test_api.log'), logging.StreamHandler()] +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(levelname)s - %(message)s', + handlers=handlers +) +logger = logging.getLogger(__name__) + +# API地址 +BASE_URL = 'http://localhost:99' +API_ENDPOINT = f'{BASE_URL}/api/update-query-result' + +def test_update_query_result(): + """ + 测试update_query_result接口 + """ + logger.info(f"开始测试API接口: {API_ENDPOINT}") + + # 测试数据 + test_data = { + 'id': 1, # 假设query_history表中有id为1的记录 + 'results_count': 1, + 'cars_info': [ + { + 'plate_number': '测试车牌1', + 'phone': '13800138001', + 'name': '测试姓名1', + 'email': 'test1@example.com', + 'address': '测试地址1' + } + ] + } + + try: + logger.info(f"发送测试请求,数据: {json.dumps(test_data, ensure_ascii=False)}") + + # 发送POST请求 + start_time = time.time() + response = requests.post( + API_ENDPOINT, + json=test_data, + headers={'Content-Type': 'application/json'}, + timeout=30 + ) + end_time = time.time() + + logger.info(f"请求完成,耗时: {end_time - start_time:.2f}秒,状态码: {response.status_code}") + + # 输出响应内容 + if response.status_code == 200: + try: + result = response.json() + logger.info(f"响应数据: {json.dumps(result, ensure_ascii=False)}") + except json.JSONDecodeError: + logger.warning(f"响应不是有效的JSON格式: {response.text}") + else: + logger.error(f"请求失败,状态码: {response.status_code},响应内容: {response.text}") + + return response.status_code + + except requests.exceptions.RequestException as e: + logger.error(f"请求异常: {str(e)}") + return None + +def main(): + """ + 主函数 + """ + logger.info("测试脚本启动") + + # 执行测试 + status_code = test_update_query_result() + + if status_code == 200: + logger.info("测试成功") + elif status_code is not None: + logger.error(f"测试失败,状态码: {status_code}") + else: + logger.error("测试失败,请求异常") + + logger.info("测试脚本结束") + +if __name__ == "__main__": + main() \ No newline at end of file