| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753 |
- #!/usr/bin/env python
- # -*- coding: utf-8 -*-
- """
- 超星系统 - 专业信息完整同步脚本
- 功能:
- 1. 从超星API获取专业信息(API路径: ysjpi_71522/list)
- 2. 保存到cx_zysj表
- 3. 从cx_zysj表同步到sys_dept表(学工系统部门表)
- 同步规则:
- - 筛选条件:zysj_kbzt='是'
- - 判断是否已存在:dept_category='zy-' + zysj_zybh AND dept_name=zysj_zymc
- - 父部门查找:通过 dept_category='xy-' + zysj_xbdm AND dept_name=zysj_ssyx 找到父dept_id
- - 插入到父部门下
- """
- import hashlib
- import base64
- import json
- import requests
- import pymysql
- import time
- from datetime import datetime
- from typing import Dict, Any, Optional, List
- from Crypto.Cipher import AES
- from Crypto.Util.Padding import unpad
- from db_config import DB_CONFIG, TABLE_MAPPING
- class ChaoxingMajorAPI:
- """超星专业信息API请求类"""
-
- def __init__(self, app_id: str, app_key: str, fid: str = "19628"):
- """
- 初始化API客户端
-
- Args:
- app_id: API的appId
- app_key: API的appKey
- fid: 单位ID,默认19628
- """
- self.app_id = app_id
- self.app_key = app_key
- self.fid = fid
- self.base_url = "https://appswh.chaoxing.com/biapi/api"
- self.api_path = "ysjpi_71522"
- # 生成AES解密密钥:appId去除'-'后取前16位
- self.aes_key = app_id.replace("-", "")[:16].encode('utf-8')
-
- def generate_enc(self, page_num: int, page_size: int) -> str:
- """
- 生成enc加密验证串
-
- enc加密方式:32位大写的MD5字符串
- 格式:[apiPath=ysjpi_71522#$pageNum=页码#$pageSize=单页条数#$fid=19628#$appKey=授权appKey]
-
- Args:
- page_num: 页码
- page_size: 单页条数
-
- Returns:
- 32位大写MD5字符串
- """
- # 构建加密字符串
- enc_string = f"[apiPath={self.api_path}#$pageNum={page_num}#$pageSize={page_size}#$fid={self.fid}#$appKey={self.app_key}]"
-
- # MD5加密并转为大写
- md5_hash = hashlib.md5(enc_string.encode('utf-8')).hexdigest().upper()
-
- return md5_hash
-
- def decrypt_data(self, ciphertext: str) -> Any:
- """
- AES解密data字段
-
- 解密算法:AES/ECB/PKCS5Padding
- 密钥:appId去除'-'后前16位字符
-
- Args:
- ciphertext: Base64编码的密文
-
- Returns:
- 解密后的数据(可能是JSON字符串,需要进一步解析)
- """
- try:
- # Base64解码
- encrypted_bytes = base64.b64decode(ciphertext)
-
- # AES解密
- cipher = AES.new(self.aes_key, AES.MODE_ECB)
- decrypted_bytes = cipher.decrypt(encrypted_bytes)
-
- # PKCS5Padding去填充
- decrypted_bytes = unpad(decrypted_bytes, AES.block_size)
-
- # 转为字符串
- decrypted_text = decrypted_bytes.decode('utf-8')
-
- # 尝试解析为JSON
- try:
- return json.loads(decrypted_text)
- except json.JSONDecodeError:
- # 如果不是JSON,直接返回字符串
- return decrypted_text
-
- except Exception as e:
- print(f"解密失败: {e}")
- return None
-
- def get_major_list(self, page_num: int = 1, page_size: int = 100) -> Dict[str, Any]:
- """
- 获取专业信息列表
-
- Args:
- page_num: 页码,默认1
- page_size: 页条数,默认100,最大1000
-
- Returns:
- API响应结果
- """
- # 验证page_size
- if page_size > 1000:
- page_size = 1000
- print("警告: pageSize超过最大限制1000,已自动调整为1000")
-
- # 生成enc加密串
- enc = self.generate_enc(page_num, page_size)
-
- # 构建请求URL
- url = f"{self.base_url}/{self.api_path}/list"
-
- # 构建请求参数
- params = {
- "pageNum": page_num,
- "pageSize": page_size,
- "fid": self.fid,
- "enc": enc
- }
-
- # 构建请求头
- headers = {
- "appId": self.app_id,
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
- }
-
- try:
- # 发送GET请求
- print(f"正在请求: {url}")
- print(f"参数: {params}")
- print(f"请求头appId: {self.app_id}")
-
- response = requests.get(url, params=params, headers=headers, timeout=30)
-
- # 检查HTTP状态码
- response.raise_for_status()
-
- # 解析JSON响应
- result = response.json()
-
- # 解密data字段
- if result.get("data") and isinstance(result.get("data"), str):
- decrypted_data = self.decrypt_data(result["data"])
- if decrypted_data is not None:
- result["data"] = decrypted_data
- else:
- print("警告: data字段解密失败,保持原始值")
-
- return result
-
- except requests.exceptions.RequestException as e:
- print(f"请求失败: {e}")
- return {
- "code": -1,
- "message": f"请求异常: {str(e)}",
- "data": None
- }
- except ValueError as e:
- print(f"JSON解析失败: {e}")
- return {
- "code": -1,
- "message": f"响应解析失败: {str(e)}",
- "data": None
- }
-
- def get_all_majors(self, max_page_size: int = 500) -> list:
- """
- 获取所有专业信息(自动分页)
-
- Args:
- max_page_size: 每页最大条数,默认500
-
- Returns:
- 所有专业信息列表
- """
- all_data = []
- page_num = 1
- total_pages = None # 总页数,从第一页响应中获取
-
- while True:
- print(f"\n正在获取第 {page_num} 页数据...")
- result = self.get_major_list(page_num, max_page_size)
-
- # 超星API成功时code=1,失败时code!=1
- if result.get("code") != 1:
- print(f"获取第 {page_num} 页失败: {result.get('message', '未知错误')}")
- break
-
- # 获取分页信息(从extendData中)
- extend_data = result.get("extendData", {})
- if total_pages is None and extend_data:
- total_pages = int(extend_data.get("pages", 0))
- total_count = int(extend_data.get("count", 0))
- print(f"总页数: {total_pages}, 总条数: {total_count}")
-
- data = result.get("data")
- if not data:
- print("没有更多数据")
- break
-
- # 如果是列表,直接添加
- if isinstance(data, list):
- all_data.extend(data)
- print(f"第 {page_num} 页获取 {len(data)} 条数据,累计 {len(all_data)} 条")
-
- # 如果知道总页数,检查是否已获取完所有页
- if total_pages and page_num >= total_pages:
- break
- # 如果返回的数据少于page_size,说明已经是最后一页
- if len(data) < max_page_size:
- break
- # 如果是字典,可能包含分页信息
- elif isinstance(data, dict):
- items = data.get("list", data.get("records", []))
- if items:
- all_data.extend(items)
- print(f"第 {page_num} 页获取 {len(items)} 条数据,累计 {len(all_data)} 条")
- # 检查是否还有下一页
- total = data.get("total", 0)
- if total and len(all_data) >= total:
- break
- else:
- break
- else:
- break
-
- page_num += 1
-
- print(f"\n总共获取 {len(all_data)} 条专业信息")
- return all_data
-
- def clear_table(self) -> bool:
- """
- 清空专业数据表
-
- Returns:
- 是否成功
- """
- try:
- connection = pymysql.connect(**DB_CONFIG)
- try:
- with connection.cursor() as cursor:
- table_name = TABLE_MAPPING["major"]
- cursor.execute(f"TRUNCATE TABLE `{table_name}`")
- connection.commit()
- print(f"✓ 已清空表 {table_name}")
- return True
- finally:
- connection.close()
- except Exception as e:
- print(f"✗ 清空表失败: {e}")
- return False
-
- def save_to_database(self, data_list: List[Dict]) -> int:
- """
- 将专业数据保存到数据库
-
- Args:
- data_list: 专业数据列表
-
- Returns:
- 成功插入的记录数
- """
- if not data_list:
- print("数据列表为空,跳过保存")
- return 0
-
- try:
- connection = pymysql.connect(**DB_CONFIG)
- try:
- current_time = int(time.time() * 1000) # 毫秒时间戳
- table_name = TABLE_MAPPING["major"]
-
- with connection.cursor() as cursor:
- # 构建插入SQL
- insert_sql = f"""
- INSERT INTO `{table_name}` (
- `inserttime`, `updatetime`,
- `zysj_zymc`, `zysj_zybh`, `zysj_ssyx`, `zysj_xbdm`,
- `zysj_kbzt`, `zysj_xz`, `zysj_pycc`, `zysj_xzm`,
- `zysj_sfdlmc`, `zysj_zyywmc`, `zysj_zyjc`, `zysj_sfkz`,
- `zysj_qyyxsx`, `zysj_xxdm`, `zysj_zymldm`, `zysj_pzszny`,
- `zysj_sczsny`, `zysj_sfzdzy`, `zysj_zdzyjbmc`, `zysj_zdzyjbm`,
- `zysj_zdzylxmc`, `zysj_zdzylxm`, `zysj_sszyqmc`, `zysj_sszyqh`,
- `zysj_sjzt`, `zysj_sjztm`, `zysj_sjcjsj`, `dataMigrateUniqueId`
- ) VALUES (
- %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
- %s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
- %s, %s, %s, %s, %s, %s, %s, %s, %s, %s
- )
- """
-
- success_count = 0
- for item in data_list:
- try:
- cursor.execute(insert_sql, (
- current_time, current_time, # inserttime, updatetime
- item.get('zysj_zymc'), item.get('zysj_zybh'), item.get('zysj_ssyx'), item.get('zysj_xbdm'),
- item.get('zysj_kbzt'), item.get('zysj_xz'), item.get('zysj_pycc'), item.get('zysj_xzm'),
- item.get('zysj_sfdlmc'), item.get('zysj_zyywmc'), item.get('zysj_zyjc'), item.get('zysj_sfkz'),
- item.get('zysj_qyyxsx'), item.get('zysj_xxdm'), item.get('zysj_zymldm'), item.get('zysj_pzszny'),
- item.get('zysj_sczsny'), item.get('zysj_sfzdzy'), item.get('zysj_zdzyjbmc'), item.get('zysj_zdzyjbm'),
- item.get('zysj_zdzylxmc'), item.get('zysj_zdzylxm'), item.get('zysj_sszyqmc'), item.get('zysj_sszyqh'),
- item.get('zysj_sjzt'), item.get('zysj_sjztm'), item.get('zysj_sjcjsj'), item.get('dataMigrateUniqueId')
- ))
- success_count += 1
- except Exception as e:
- print(f"插入单条数据失败: {e}, 数据: {item}")
-
- connection.commit()
- print(f"✓ 成功插入 {success_count}/{len(data_list)} 条数据到表 {table_name}")
- return success_count
- finally:
- connection.close()
- except Exception as e:
- print(f"✗ 保存数据到数据库失败: {e}")
- return 0
- class MajorSync:
- """专业数据同步类 - 从cx_zysj表同步到sys_dept表"""
-
- def __init__(self):
- """初始化"""
- self.tenant_id = '000000'
-
- def get_valid_majors(self) -> List[Dict[str, Any]]:
- """
- 从cx_zysj表中获取符合条件的数据
-
- Returns:
- 符合条件的专业数据列表
- """
- try:
- connection = pymysql.connect(**DB_CONFIG)
- try:
- with connection.cursor(pymysql.cursors.DictCursor) as cursor:
- # 查询符合条件的数据:zysj_kbzt='是'
- sql = """
- SELECT
- zysj_zymc, zysj_zybh, zysj_ssyx, zysj_xbdm, zysj_kbzt
- FROM cx_zysj
- WHERE zysj_kbzt = '是'
- ORDER BY inserttime ASC
- """
- cursor.execute(sql)
- results = cursor.fetchall()
- print(f"✓ 从cx_zysj表中查询到 {len(results)} 条符合条件的数据")
- return results
- finally:
- connection.close()
- except Exception as e:
- print(f"✗ 查询cx_zysj表失败: {e}")
- return []
-
- def find_parent_dept(self, zysj_xbdm: str, zysj_ssyx: str) -> Optional[Dict[str, Any]]:
- """
- 查找父部门信息
-
- 通过 dept_category='xy-' + zysj_xbdm AND dept_name=zysj_ssyx 找到父部门
-
- Args:
- zysj_xbdm: 系部代码
- zysj_ssyx: 所属院系名称
-
- Returns:
- 父部门信息字典,包含dept_id和ancestors,如果未找到则返回None
- """
- if not zysj_xbdm or not zysj_ssyx:
- return None
-
- try:
- connection = pymysql.connect(**DB_CONFIG)
- try:
- with connection.cursor(pymysql.cursors.DictCursor) as cursor:
- dept_category = f"xy-{zysj_xbdm}"
- sql = """
- SELECT dept_id, ancestors
- FROM sys_dept
- WHERE dept_category = %s AND dept_name = %s
- LIMIT 1
- """
- cursor.execute(sql, (dept_category, zysj_ssyx))
- result = cursor.fetchone()
- return result
- finally:
- connection.close()
- except Exception as e:
- print(f"✗ 查找父部门失败: {e}")
- return None
-
- def check_major_exists(self, dept_name: str, dept_category: str) -> bool:
- """
- 检查专业是否已存在
-
- Args:
- dept_name: 专业名称
- dept_category: 专业类别编码
-
- Returns:
- 是否存在
- """
- try:
- connection = pymysql.connect(**DB_CONFIG)
- try:
- with connection.cursor() as cursor:
- sql = """
- SELECT COUNT(*) as count
- FROM sys_dept
- WHERE dept_name = %s AND dept_category = %s
- """
- cursor.execute(sql, (dept_name, dept_category))
- result = cursor.fetchone()
- return result[0] > 0
- finally:
- connection.close()
- except Exception as e:
- print(f"✗ 检查专业是否存在失败: {e}")
- return False
-
- def get_max_order_num(self, parent_id: int) -> int:
- """
- 获取指定父节点下的最大order_num
-
- Args:
- parent_id: 父部门ID
-
- Returns:
- 最大order_num,如果没有数据则返回0
- """
- try:
- connection = pymysql.connect(**DB_CONFIG)
- try:
- with connection.cursor() as cursor:
- sql = """
- SELECT MAX(order_num) as max_order
- FROM sys_dept
- WHERE parent_id = %s
- """
- cursor.execute(sql, (parent_id,))
- result = cursor.fetchone()
- return result[0] if result[0] is not None else 0
- finally:
- connection.close()
- except Exception as e:
- print(f"✗ 获取最大order_num失败: {e}")
- return 0
-
- def generate_dept_id(self, base_timestamp: str, index: int) -> int:
- """
- 生成dept_id
- 格式:当前时间戳(%Y%m%d%H%M%S)+ 0001开始递增
-
- Args:
- base_timestamp: 基础时间戳字符串(格式:%Y%m%d%H%M%S)
- index: 序号(从1开始)
-
- Returns:
- dept_id
- """
- # 序号格式化为4位数字(0001, 0002, ...)
- sequence = str(index).zfill(4)
- # 拼接:时间戳 + 序号
- dept_id_str = base_timestamp + sequence
- return int(dept_id_str)
-
- def sync_majors(self) -> Dict[str, Any]:
- """
- 同步专业数据到sys_dept表
-
- Returns:
- 同步结果统计(包含成功、跳过、失败的专业编号列表)
- """
- # 获取符合条件的数据
- valid_majors = self.get_valid_majors()
- if not valid_majors:
- print("没有符合条件的数据需要同步")
- return {
- "total": 0,
- "inserted": 0,
- "skipped": 0,
- "failed": 0,
- "inserted_zybh": [],
- "skipped_zybh": [],
- "failed_zybh": []
- }
-
- # 生成基础时间戳(用于生成dept_id)
- base_timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
-
- # 统计信息
- stats = {
- "total": len(valid_majors),
- "inserted": 0,
- "skipped": 0,
- "failed": 0,
- "inserted_zybh": [], # 成功插入的专业编号列表
- "skipped_zybh": [], # 跳过的专业编号列表
- "failed_zybh": [] # 失败的专业编号列表
- }
-
- # 当前时间
- current_time = datetime.now()
-
- # 用于生成dept_id的序号计数器(只对实际插入的数据计数)
- insert_index = 0
-
- # 按父部门分组,以便管理order_num
- parent_order_map = {} # {parent_id: current_order_num}
-
- try:
- connection = pymysql.connect(**DB_CONFIG)
- try:
- with connection.cursor() as cursor:
- # 准备插入SQL
- insert_sql = """
- INSERT INTO sys_dept (
- dept_id, tenant_id, parent_id, ancestors, dept_name, dept_category,
- order_num, leader, phone, email, status, del_flag,
- create_dept, create_by, create_time, update_by, update_time
- ) VALUES (
- %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s
- )
- """
-
- # 遍历数据,逐个处理
- for major in valid_majors:
- zysj_zymc = major.get('zysj_zymc')
- zysj_zybh = major.get('zysj_zybh')
- zysj_ssyx = major.get('zysj_ssyx')
- zysj_xbdm = major.get('zysj_xbdm')
-
- # 验证数据
- if not zysj_zymc:
- print(f"⚠ 跳过:专业名称为空 (zysj_zybh: {zysj_zybh})")
- stats["skipped"] += 1
- if zysj_zybh:
- stats["skipped_zybh"].append(zysj_zybh)
- continue
-
- if not zysj_zybh:
- print(f"⚠ 跳过:专业编号为空 (zysj_zymc: {zysj_zymc})")
- stats["skipped"] += 1
- # 专业编号为空,无法记录
- continue
-
- if not zysj_ssyx:
- print(f"⚠ 跳过:所属院系为空 (zysj_zymc: {zysj_zymc}, zysj_zybh: {zysj_zybh})")
- stats["skipped"] += 1
- stats["skipped_zybh"].append(zysj_zybh)
- continue
-
- if not zysj_xbdm:
- print(f"⚠ 跳过:系部代码为空 (zysj_zymc: {zysj_zymc}, zysj_zybh: {zysj_zybh})")
- stats["skipped"] += 1
- stats["skipped_zybh"].append(zysj_zybh)
- continue
-
- # 检查dept_name长度(sys_dept表中dept_name是varchar(30))
- if len(zysj_zymc) > 30:
- print(f"⚠ 警告:专业名称超过30字符,将被截断: {zysj_zymc} (长度: {len(zysj_zymc)})")
- zysj_zymc = zysj_zymc[:30]
-
- # 构建dept_category
- dept_category = f"zy-{zysj_zybh}"
-
- # 检查是否已存在
- if self.check_major_exists(zysj_zymc, dept_category):
- print(f"⏭ 跳过已存在的专业: {zysj_zymc} (dept_category: {dept_category})")
- stats["skipped"] += 1
- stats["skipped_zybh"].append(zysj_zybh)
- continue
-
- # 查找父部门
- parent_dept = self.find_parent_dept(zysj_xbdm, zysj_ssyx)
- if not parent_dept:
- print(f"⚠ 跳过:未找到父部门 (zysj_ssyx: {zysj_ssyx}, zysj_xbdm: {zysj_xbdm}, zysj_zymc: {zysj_zymc})")
- stats["skipped"] += 1
- stats["skipped_zybh"].append(zysj_zybh)
- continue
-
- parent_id = parent_dept['dept_id']
- parent_ancestors = parent_dept['ancestors']
-
- # 构建ancestors:父部门的ancestors + 父部门的dept_id
- if parent_ancestors:
- ancestors = f"{parent_ancestors},{parent_id}"
- else:
- ancestors = str(parent_id)
-
- # 获取或初始化该父部门下的order_num
- if parent_id not in parent_order_map:
- max_order_num = self.get_max_order_num(parent_id)
- parent_order_map[parent_id] = max_order_num
-
- # 递增order_num
- parent_order_map[parent_id] += 1
- current_order_num = parent_order_map[parent_id]
-
- # 递增插入序号(只对实际插入的数据计数)
- insert_index += 1
-
- # 生成dept_id
- dept_id = self.generate_dept_id(base_timestamp, insert_index)
-
- # 准备插入数据
- try:
- cursor.execute(insert_sql, (
- dept_id, # dept_id
- self.tenant_id, # tenant_id
- parent_id, # parent_id
- ancestors, # ancestors
- zysj_zymc, # dept_name
- dept_category, # dept_category
- current_order_num, # order_num
- None, # leader
- None, # phone
- None, # email
- '0', # status
- '0', # del_flag
- 0, # create_dept
- 1, # create_by
- current_time, # create_time
- 1, # update_by
- current_time # update_time
- ))
- stats["inserted"] += 1
- stats["inserted_zybh"].append(zysj_zybh)
- print(f"✓ 插入专业: {zysj_zymc} (dept_id: {dept_id}, dept_category: {dept_category}, parent_id: {parent_id}, order_num: {current_order_num})")
- except Exception as e:
- stats["failed"] += 1
- stats["failed_zybh"].append(zysj_zybh)
- print(f"✗ 插入专业失败: {zysj_zymc}, 错误: {e}")
-
- # 提交事务
- connection.commit()
- print(f"\n✓ 事务提交成功")
-
- finally:
- connection.close()
- except Exception as e:
- print(f"✗ 同步过程发生错误: {e}")
- stats["failed"] = stats["total"] - stats["inserted"] - stats["skipped"]
-
- return stats
-
- def print_statistics(self, stats: Dict[str, Any]):
- """
- 打印统计信息
-
- Args:
- stats: 统计信息字典(包含专业编号列表)
- """
- print("\n" + "=" * 60)
- print("同步统计信息")
- print("=" * 60)
- print(f"总数: {stats['total']}")
- print(f"成功插入: {stats['inserted']}")
- print(f"跳过: {stats['skipped']}")
- print(f"失败: {stats['failed']}")
- print("=" * 60)
-
- # 输出专业编号列表(逗号分隔)
- if stats.get('inserted_zybh'):
- inserted_zybh_str = ','.join(stats['inserted_zybh'])
- print(f"\n成功插入的专业编号: {inserted_zybh_str}")
-
- if stats.get('skipped_zybh'):
- skipped_zybh_str = ','.join(stats['skipped_zybh'])
- print(f"跳过的专业编号: {skipped_zybh_str}")
-
- if stats.get('failed_zybh'):
- failed_zybh_str = ','.join(stats['failed_zybh'])
- print(f"失败的专业编号: {failed_zybh_str}")
-
- print("=" * 60)
- def main():
- """主函数 - 示例用法"""
- # API配置信息
- APP_ID = "36c1e58c-7f0a-4567-8ea8-93c7acadbbde"
- APP_KEY = "dyjs_zyxx"
- FID = "19628" # 单位ID
-
- # 创建API客户端
- api = ChaoxingMajorAPI(app_id=APP_ID, app_key=APP_KEY, fid=FID)
-
- # 获取所有数据并保存到数据库
- print("=" * 60)
- print("获取所有专业信息并保存到数据库")
- print("=" * 60)
-
- # 步骤1: 清空表
- print("\n步骤1: 清空专业数据表...")
- api.clear_table()
-
- # 步骤2: 获取所有数据
- print("\n步骤2: 获取所有专业信息(自动分页)...")
- all_majors = api.get_all_majors(max_page_size=500)
-
- # 步骤3: 保存到数据库
- if all_majors:
- print(f"\n步骤3: 保存数据到数据库...")
- saved_count = api.save_to_database(all_majors)
- print(f"\n✓ 完成!共获取 {len(all_majors)} 条数据,成功保存 {saved_count} 条")
-
- print(f"\n前3条数据示例:")
- for i, major in enumerate(all_majors[:3], 1):
- print(f"{i}. {major}")
- else:
- print("\n✗ 未获取到数据")
-
- # ========== 第二阶段:从cx_zysj表同步到sys_dept表 ==========
- print("\n" + "=" * 60)
- print("第二阶段:从cx_zysj表同步到sys_dept表")
- print("=" * 60)
- print(f"筛选条件: zysj_kbzt='是'")
- print(f"判断是否已存在: dept_category='zy-' + zysj_zybh AND dept_name=zysj_zymc")
- print(f"父部门查找: dept_category='xy-' + zysj_xbdm AND dept_name=zysj_ssyx")
- print("=" * 60)
-
- # 创建同步实例
- sync = MajorSync()
-
- # 执行同步
- stats = sync.sync_majors()
-
- # 打印统计信息
- sync.print_statistics(stats)
- if __name__ == "__main__":
- main()
|