4. 数据采集基础:数据源类型与 Python 连接示例
在催收触达波动监控中,数据采集是脚本运行的起点。你需要从不同数据源获取催收记录、触达结果和客户状态。本章将梳理三种主流数据源类型,并给出 Python 连接 MySQL 与 PostgreSQL 的完整示例。
4.1 数据源类型概览
催收监控脚本通常对接以下三类数据源:
| 数据源类型 | 典型场景 | 采集方式 | 注意事项 |
|---|---|---|---|
| 关系型数据库 | 催收系统核心库(MySQL / PostgreSQL) | SQL 查询 + Python 驱动 | 连接池管理、慢查询优化 |
| API 接口 | 第三方催收平台、短信网关、外呼系统 | HTTP 请求(requests / httpx) | 鉴权、限流、重试机制 |
| 日志文件 | 催收系统运行日志、拨测记录 | 文件读取 + 正则解析 | 日志轮转、编码、大文件分片 |
选型建议: 催收触达数据优先从数据库直接采集,保证实时性与完整性;API 用于补充外部平台数据;日志文件仅作为兜底或离线分析使用。
4.2 数据源架构关系
下图展示了监控脚本与三种数据源之间的采集关系:
4.3 Python 连接 MySQL 示例
使用 pymysql 驱动连接 MySQL,执行催收记录查询:
import pymysql
from pymysql.cursors import DictCursor
# 数据库连接配置
DB_CONFIG = {
"host": "192.168.1.100",
"port": 3306,
"user": "monitor_user",
"password": "secure_pass_2024",
"database": "collection_db",
"charset": "utf8mb4"
}
def fetch_collection_records(start_time, end_time):
"""采集指定时间段的催收触达记录"""
connection = pymysql.connect(**DB_CONFIG)
try:
with connection.cursor(DictCursor) as cursor:
sql = """
SELECT
id, case_id, collector_name,
contact_channel, contact_result,
contact_time, duration_seconds
FROM collection_contact_log
WHERE contact_time BETWEEN %s AND %s
ORDER BY contact_time ASC
"""
cursor.execute(sql, (start_time, end_time))
records = cursor.fetchall()
return records
finally:
connection.close()
# 使用示例
if __name__ == "__main__":
from datetime import datetime, timedelta
end = datetime.now()
start = end - timedelta(hours=1)
data = fetch_collection_records(start, end)
print(f"采集到 {len(data)} 条催收记录")
关键点: 使用
DictCursor 让返回结果以字典形式呈现,字段名直接作为键;务必在 finally 中关闭连接,避免连接泄漏。
4.4 Python 连接 PostgreSQL 示例
使用 psycopg2 驱动连接 PostgreSQL,适用于更复杂的催收数据仓库:
import psycopg2
import psycopg2.extras
PG_CONFIG = {
"host": "192.168.1.101",
"port": 5432,
"user": "pg_monitor",
"password": "pg_strong_pass",
"database": "collection_warehouse"
}
def fetch_touch_wave_data(threshold_minutes=30):
"""采集触达波动异常数据"""
conn = psycopg2.connect(**PG_CONFIG)
try:
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
query = """
SELECT
channel_type,
COUNT(*) AS total_touches,
COUNT(*) FILTER (WHERE result = 'SUCCESS') AS success_count,
ROUND(
COUNT(*) FILTER (WHERE result = 'SUCCESS') * 100.0 / NULLIF(COUNT(*), 0),
2
) AS success_rate
FROM touch_wave_log
WHERE log_time >= NOW() - INTERVAL '1 hour'
GROUP BY channel_type
HAVING COUNT(*) FILTER (WHERE result = 'SUCCESS') * 100.0 / NULLIF(COUNT(*), 0) < %s
"""
cur.execute(query, (threshold_minutes,))
results = cur.fetchall()
return results
finally:
conn.close()
# 使用示例
if __name__ == "__main__":
anomalies = fetch_touch_wave_data(threshold_minutes=30)
for row in anomalies:
print(f"渠道: {row['channel_type']}, 成功率: {row['success_rate']}%")
注意: PostgreSQL 的
INTERVAL 语法与 MySQL 不同;使用 RealDictCursor 实现字典游标;FILTER 子句是 PG 特有的聚合过滤语法,比 CASE WHEN 更简洁。
4.5 两种数据库连接对比
| 对比维度 | MySQL (pymysql) | PostgreSQL (psycopg2) |
|---|---|---|
| 驱动安装 | pip install pymysql |
pip install psycopg2-binary |
| 游标类型 | DictCursor |
RealDictCursor |
| 占位符 | %s |
%s |
| 时间函数 | NOW() - INTERVAL 1 HOUR |
NOW() - INTERVAL '1 hour' |
| 聚合过滤 | SUM(CASE WHEN ...) |
COUNT(*) FILTER (WHERE ...) |
| 连接池推荐 | DBUtils / SQLAlchemy |
psycopg2.pool / SQLAlchemy |
4.6 连接管理最佳实践
- 使用连接池: 避免每次查询都创建新连接,推荐
SQLAlchemy统一管理。 - 设置超时: 数据库连接与查询都要设置超时,防止脚本卡死。
- 参数化查询: 永远使用占位符传参,防止 SQL 注入。
- 异常捕获: 区分连接异常与查询异常,分别记录日志。
- 敏感信息保护: 数据库密码通过环境变量或密钥管理服务注入,不硬编码。
生产建议: 在催收监控脚本中,将数据库连接配置统一放在
config.py 或环境变量中,并实现 get_connection() 工厂函数,方便后续切换数据源或增加读写分离。