影刀RPA实操指南:校园图书馆与后勤管理系统自动化方案
去年帮某大学图书馆做自动化项目,场景很有意思——图书馆系统分散在三个平台:借还书用图书馆管理系统(ILAS)、入馆统计用闸机系统、设备报修用学校后勤OA。三套系统之间完全没有数据流转,导致逾期催还靠人工打电话、入馆数据分析没人做、报修单处理周期长达一周。我用影刀RPA搭了借还管理→逾期催还→入馆统计→新书编目→设备报修派单→教务通知发布的完整方案,图书馆2个全职工作人员的工作量减到0.5人。
一、业务痛点与校园场景特殊性
校园场景和电商/制造业完全不同,核心差异:
| 维度 | 电商/制造 | 校园图书馆 |
|---|---|---|
| 数据源 | Web/App/API | 图书馆系统+闸机+OA+教务系统,四套互不联通 |
| 用户群体 | 消费者/操作员 | 学生/教师/管理员,有学期周期性 |
| 时效要求 | 实时 | 学期性要求(开学高峰/期末考试周特殊处理) |
| 系统类型 | 互联网/工业系统 | 校园内网老系统,Web界面老旧 |
| 操作权限 | 企业账号 | 学生借阅证号+教师工号,权限分层 |
痛点清单:
-
图书逾期催还靠人工逐个打电话,每天50+逾期记录,根本催不完
-
入馆人次数据在闸机系统里,没人导出来做统计分析
-
新书到馆后编目入库全靠手工录入书目信息,一本书10分钟
-
设备报修提交到后勤OA后没人主动跟踪,修不修看运气
-
-
教务处通知要图书馆手动转发到学生群,经常漏发
二、影刀RPA流程架构
| 子流程 | 功能 | 执行频率 |
|---|---|---|
| sub_overdue_check | 检查逾期借阅记录 | 每日9:00 |
| sub_overdue_notify | 逾期催还通知(短信/飞书/邮件) | 逾期检测后立即 |
| sub_gate_statistics | 闸机入馆人次统计+报表 | 每日22:00 |
[video(video-pDIMi8cU-1785257982713)(type-csdn)(url-live.csdn.net/v/embed/525…)]
| sub_new_book_catalog | 新书信息采集+自动编目 | 每周一9:00 | | sub_repair_dispatch | 设备报修单自动派单+跟踪 | 每2小时 | | sub_notice_publish | 教务通知自动转发到学生群 | 实时监控 |
三、逾期借阅检测与催还通知
3.1 影刀Web界面操作(图书馆ILAS系统)
ILAS系统是老旧的图书馆管理系统,只有Web界面无API:
- 打开网页指令 → ILAS系统
http://library-ilas/patron/overdue - 等待指令(元素出现) → 等待逾期记录表格
table#overdue-table - 获取相似元素列表指令 → 抓取所有逾期记录行
tr.overdue-row - 循环指令(For列表) → 遍历每行:
- 获取元素文本指令 → 借阅证号
td:nth-child(1)(如STU20260001) - 获取元素文本指令 → 读者姓名
td:nth-child(2) - 获取元素文本指令 → 书名
td:nth-child(3) - 获取元素文本指令 → 逾期天数
td:nth-child(7) - 获取元素文本指令 → 手机号
td:nth-child(9) - 数据存入影刀列表变量
overdue_list
- 获取元素文本指令 → 借阅证号
3.2 Python节点处理(逾期分级通知)
# -*- coding: utf-8 -*-
#影刀Python节点:逾期催还分级通知
import json
import requests
from datetime import datetime
FEISHU_WEBHOOK = "https://open.feishu.cn/open-apis/bot/v2/hook/your-hook-id"
SMS_API_BASE = "http://sms-gateway/api/v1" # 校园短信网关
EMAIL_API_BASE = "http://email-gateway/api/v1" # 校园邮件系统
# 逾期分级通知策略
OVERDUE_POLICY = {
"1-7天": {"channel": "飞书", "template": "温馨提示:您借阅的图书已逾期{days}天,请尽快归还"},
"8-30天": {"channel": "短信+飞书", "template": "提醒:您借阅的《{book}》已逾期{days}天,请立即归还,否则产生滞纳金"},
"30天以上": {"channel": "短信+飞书+邮件", "template": "严重逾期:您借阅的《{book}》已逾期{days}天,请立即归还!逾期30天以上将暂停借阅权限"}
}
def send_overdue_notifications(overdue_list):
"""根据逾期天数分级发送催还通知"""
results = {"feishu_count": 0, "sms_count": 0, "email_count": 0}
for record in overdue_list:
reader_name = record.get("reader_name", "")
reader_id = record.get("reader_id", "")
book_title = record.get("book_title", "")
overdue_days = int(record.get("overdue_days", 0))
phone = record.get("phone", "")
email = record.get("email", f"{reader_id}@campus.edu.cn")
# 根据逾期天数选择通知渠道
if overdue_days <= 7:
channel = "飞书"
elif overdue_days <= 30:
channel = "短信+飞书"
else:
channel = "短信+飞书+邮件"
message = f"提醒:您借阅的《{book_title}》已逾期{overdue_days}天,请尽快归还至图书馆。"
# ---- 飞书通知 ----
if "飞书" in channel:
card = {
"config": {"wide_screen_mode": True},
"header": {"title": {"tag": "plain_text", "content": "📚 图书逾期催还提醒"}, "template": "orange"},
"elements": [{"tag": "markdown", "content": f"**读者**:{reader_name}({reader_id})\n**书名**:《{book_title}》\n**逾期天数**:{overdue_days}天\n\n请尽快归还,避免产生滞纳金"}]
}
try:
requests.post(FEISHU_WEBHOOK, json={"msg_type": "interactive", "card": card}, timeout=10)
results["feishu_count"] += 1
except:
pass
# ---- 短信通知 ----
if "短信" in channel and phone:
try:
requests.post(
f"{SMS_API_BASE}/send",
json={"phone": phone, "content": message},
timeout=10
)
results["sms_count"] += 1
except:
pass
# ---- 邮件通知 ----
if "邮件" in channel:
try:
requests.post(
f"{EMAIL_API_BASE}/send",
json={"to": email, "subject": "图书严重逾期催还通知", "body": message},
timeout=10
)
results["email_count"] += 1
except:
pass
print(f"[INFO] 催还通知发送完成:飞书{results['feishu_count']}条,短信{results['sms_count']}条,邮件{results['email_count']}条")
return {"status": "success", "results": results}
四、入馆人次统计与报表
# -*- coding: utf-8 -*-
#影刀Python节点:闸机入馆人次统计
import json
import requests
from datetime import datetime, timedelta
import openpyxl
GATE_API_BASE = "http://gate-system/api/v1" # 闸机系统接口(如果无API则用影刀Web操作)
FEISHU_WEBHOOK = "https://open.feishu.cn/open-apis/bot/v2/hook/your-hook-id"
def generate_gate_daily_report(date=None):
"""统计当日入馆人次并推送飞书日报"""
if date is None:
date = datetime.now().strftime("%Y-%m-%d")
# Step1: 获取闸机进出记录
try:
resp = requests.get(
f"{GATE_API_BASE}/records",
params={"date": date, "type": "enter"},
timeout=15
)
records = resp.json().get("data", [])
except Exception as e:
return {"status": "error", "message": str(e)}
# Step2: 分时段统计入馆人次
hourly_stats = {} # key=时段(如09-10), value=人次
total_count = 0
student_count = 0
teacher_count = 0
for record in records:
enter_time = record.get("enter_time", "")
hour = int(enter_time.split(" ")[1].split(":")[0]) if enter_time else 0
time_slot = f"{hour:02d}-{(hour+1):02d}"
hourly_stats[time_slot] = hourly_stats.get(time_slot, 0) + 1
total_count += 1
reader_type = record.get("reader_type", "")
if reader_type == "student":
student_count += 1
elif reader_type == "teacher":
teacher_count += 1
# Step3: 生成飞书日报卡片
hourly_text = "\n".join(
[f"{slot}: {count}人次" for slot, count in sorted(hourly_stats.items())]
)
card = {
"config": {"wide_screen_mode": True},
"header": {
"title": {"tag": "plain_text", "content": f"📊 图书馆入馆日报 {date}"},
"template": "green" if total_count >= 500 else "blue"
},
"elements": [
{"tag": "markdown", "content": f"**总入馆人次**:{total_count}人\n**学生**:{student_count}人\n**教师**:{teacher_count}人"},
{"tag": "markdown", "content": f"**分时段统计**:\n{hourly_text}"},
{"tag": "markdown", "content": f"\n高峰时段:{max(hourly_stats, key=hourly_stats.get) if hourly_stats else '无数据'}"}
]
}
requests.post(FEISHU_WEBHOOK, json={"msg_type": "interactive", "card": card}, timeout=10)
# Step4: 同时生成Excel周报数据(追加写入)
return {"status": "success", "total_count": total_count, "hourly_stats": hourly_stats}
五、新书编目自动化
新书到馆后,编目员需要从ISBN查询书目信息然后录入ILAS。影刀可以自动从国家图书馆ISBN接口查询:
# -*- coding: utf-8 -*-
#影刀Python节点:ISBN书目信息自动查询与编目
import json
import requests
# 国家图书馆ISBN查询API(实际用OpenISBN或豆瓣图书API)
ISBN_API_BASE = "https://api.openisbn.com/v1" # ISBN查询接口
def query_book_info(isbn_list):
"""根据ISBN列表批量查询书目信息,返回编目所需字段"""
book_info_list = []
for isbn in isbn_list:
try:
resp = requests.get(
f"{ISBN_API_BASE}/book/{isbn}",
timeout=10
)
data = resp.json()
book_info = {
"isbn": isbn, # ISBN号
"title": data.get("title", ""), # 书名
"author": data.get("author", ""), # 作者
"publisher": data.get("publisher", ""), # 出版社
"publish_date": data.get("publish_date", ""), # 出版日期
"category": data.get("category", ""), # 分类号(中图法分类)
"price": data.get("price", ""), # 价格
"pages": data.get("pages", ""), # 页数
"summary": data.get("summary", ""), # 内容摘要(前200字)
}
book_info_list.append(book_info)
print(f"[INFO] ISBN {isbn}书目信息已获取:《{book_info['title']}》")
except Exception as e:
book_info_list.append({"isbn": isbn, "status": "error", "message": str(e)})
print(f"[WARN] ISBN {isbn}查询失败: {e}")
success_count = sum(1 for b in book_info_list if b.get("status") != "error")
print(f"[INFO] 书目查询完成:成功{success_count}/{len(isbn_list)}本")
return {"status": "success", "books": book_info_list}
影刀ILAS编目录入操作
获取书目信息后,影刀自动在ILAS系统录入:
- 打开网页指令 → ILAS新书编目页面
http://library-ilas/catalog/new - 输入文本指令 → ISBN号填入
input#isbn - 点击元素指令 → 点击"查询书目"按钮
button#query-isbn - 等待指令(3秒) → 等待书目信息自动填充
- 如果自动填充不完整,逐字段输入文本指令 → 书名
input#title、作者input#author、出版社input#publisher等 - 输入文本指令 → 分类号填入
input#category(从API获取的中图法分类) - 输入文本指令 → 馆藏位置填入
input#location(默认"A区书架") - 点击元素指令 → 点击"保存编目"按钮
button#save-catalog - 等待指令(元素出现) → 等待"编目成功"提示
六、设备报修自动派单与跟踪
图书馆设备(自助借还机、空调、照明)报修到后勤OA后无人跟踪,影刀实现自动派单:
[video(video-eYkwEogo-1785257989362)(type-csdn)(url-live.csdn.net/v/embed/524…)]
# -*- coding: utf-8 -*-
#影刀Python节点:报修单自动派单与跟踪
import json
import requests
OA_API_BASE = "http://oa-server/api/v1" # 后勤OA接口
FEISHU_WEBHOOK = "https://open.feishu.cn/open-apis/bot/v2/hook/your-hook-id"
# 报修类型与维修人员映射
REPAIR_DISPATCH_MAP = {
"自助借还机故障": {"team": "信息化中心", "priority": "urgent", "sla_hours": 4},
"空调故障": {"team": "后勤维修组", "priority": "normal", "sla_hours": 24},
"照明故障": {"team": "后勤维修组", "priority": "normal", "sla_hours": 48},
"网络故障": {"team": "信息化中心", "priority": "urgent", "sla_hours": 2},
}
def dispatch_repair_orders():
"""从OA获取未派单的报修记录,自动分配维修团队并跟踪"""
headers = {"Authorization": f"Bearer {OA_API_KEY}", "Content-Type": "application/json"}
# Step1: 获取未派单的报修记录
try:
resp = requests.get(
f"{OA_API_BASE}/repair/orders",
headers=headers,
params={"status": "undispatched"},
timeout=10
)
orders = resp.json().get("data", [])
except Exception as e:
return {"status": "error", "message": str(e)}
# Step2: 自动派单
dispatched_count = 0
for order in orders:
repair_type = order.get("repair_type", "")
dispatch_info = REPAIR_DISPATCH_MAP.get(repair_type, {"team": "后勤维修组", "priority": "normal", "sla_hours": 48})
# 更新OA报修单:分配维修团队+设置优先级+SLA时限
update_data = {
"dispatch_team": dispatch_info["team"],
"priority": dispatch_info["priority"],
"sla_deadline": dispatch_info["sla_hours"], # SLA响应时限(小时)
"status": "dispatched"
}
try:
requests.patch(
f"{OA_API_BASE}/repair/orders/{order['order_id']}",
headers=headers,
json=update_data,
timeout=10
)
dispatched_count += 1
except:
pass
# Step3: 飞书推送派单通知给维修团队
if dispatched_count > 0:
card = {
"config": {"wide_screen_mode": True},
"header": {"title": {"tag": "plain_text", "content": f"🔧 图书馆设备报修派单({dispatched_count}条)"}, "template": "blue"},
"elements": [{"tag": "markdown", "content": f"已自动派单{dispatched_count}条报修记录至对应维修团队"}]
}
requests.post(FEISHU_WEBHOOK, json={"msg_type": "interactive", "card": card}, timeout=10)
# Step4: 检查已派单但超SLA未完成的报修,推送催修告警
try:
resp = requests.get(
f"{OA_API_BASE}/repair/orders",
headers=headers,
params={"status": "dispatched", "sla_overdue": True},
timeout=10
)
overdue_orders = resp.json().get("data", [])
if overdue_orders:
overdue_text = "\n".join(
[f"· {o['order_id']}:{o['repair_type']},已超SLA{o['sla_overdue_hours']}小时" for o in overdue_orders]
)
card = {
"config": {"wide_screen_mode": True},
"header": {"title": {"tag": "plain_text", "content": "⚠ 报修超SLA催修通知"}, "template": "red"},
"elements": [{"tag": "markdown", "content": overdue_text}]
}
requests.post(FEISHU_WEBHOOK, json={"msg_type": "interactive", "card": card}, timeout=10)
except:
pass
return {"status": "success", "dispatched_count": dispatched_count}
七、教务通知自动转发
# -*- coding: utf-8 -*-
#影刀Python节点:教务通知自动转发到学生飞书群
import json
import requests
from datetime import datetime
OA_API_BASE = "http://oa-server/api/v1"
FEISHU_WEBHOOK_STUDENT = "https://open.feishu.cn/open-apis/bot/v2/hook/student-group-hook"
def publish_notice_to_student_group():
"""从OA获取最新教务通知,转发到学生飞书群"""
headers = {"Authorization": f"Bearer {OA_API_KEY}", "Content-Type": "application/json"}
# 查询今日教务通知(图书馆相关)
try:
resp = requests.get(
f"{OA_API_BASE}/notices",
headers=headers,
params={"category": "library", "date": datetime.now().strftime("%Y-%m-%d")},
timeout=10
)
notices = resp.json().get("data", [])
except:
return {"status": "error", "message": "OA通知获取失败"}
for notice in notices:
title = notice.get("title", "")
content = notice.get("content", "")
publisher = notice.get("publisher", "")
card = {
"config": {"wide_screen_mode": True},
"header": {"title": {"tag": "plain_text", "content": f"📢 {title}"},
"template": "turquoise"},
"elements": [
{"tag": "markdown", "content": content},
{"tag": "markdown", "content": f"\n发布方:{publisher}\n发布时间:{notice.get('publish_time', '')}"}
]
}
requests.post(FEISHU_WEBHOOK_STUDENT, json={"msg_type": "interactive", "card": card}, timeout=10)
return {"status": "success", "published_count": len(notices)}
八、常见问题速查
| # | 现象 | 原因 | 解决方式 |
|---|---|---|---|
| 1 | ILAS系统逾期记录抓取不完整 | 表格分页显示,影刀只抓了第一页 | 影刀流程增加翻页逻辑:点击"下一页"按钮→继续抓取→直到最后一页 |
| 2 | 短信催还通知发送失败 | 校园短信网关余额不足或接口异常 | 检查短信网关余额;备选方案改用飞书私信通知(需获取学生飞书open_id) |
| 3 | ISBN查询API返回空结果 | ISBN号输入错误或该书未被收录 | 影刀流程增加ISBN校验(13位数字+校验位计算);未收录的书标记为"手工编目" |
| 4 | ILAS编目页面元素定位不稳定 | ILAS系统DOM结构不规范,ID随机 | 用影刀相对定位(从已知元素向相邻元素偏移);或改用XPath定位特定属性组合 |
| 5 | 入馆日报高峰时段统计为空 | 闸机系统API返回时间格式不一致 | Python节点统一时间格式解析:检测2026-07-01 09:30和09:30两种格式 |
| 6 | 报修单派单后维修团队不响应 | OA系统通知不到位 | 影刀流程同时推送飞书告警到维修团队群+图书馆管理员群,双重催修 |
| 7 | 学期开学高峰期逾期催还量大 | 新学期开学前大量借阅集中逾期 | 开学前2周提高催还频率:从每日一次改为每日2次(上午+下午) |
九、推荐资源
- ILAS图书馆系统:国内高校主流图书馆管理系统,有Web界面但无开放API
- OpenISBN API:ISBN书目信息查询接口,免费额度100次/天
- 中图法分类:中国图书馆分类法,新书编目必填的分类号体系
- 影刀Web操作:校园老旧系统必须用Web界面操作,元素定位技巧很重要
- 飞书群机器人:open.feishu.cn/document/ho…
十、内容标签
影刀RPA 图书馆自动化 逾期催还 入馆统计 新书编目 ISBN查询 设备报修 OA系统 教务通知 校园管理
作者:林焱 | 影刀RPA深度使用者,两年以上实操经验,专注IoT/MES/新能源行业自动化方案