Python技术迷

用 Python 写了一个电子考勤系统

前段时间我们公司新来了几个实习生,每天上班都要签到,但是 HR 老是抱怨表格太乱了。那天中午我在茶水间喝咖啡,HR 跟我吐槽说:“能不能搞个自动的,不用手动登记那种。”我当时随口一说:“用 Python 搞个电子考勤系统不就行了嘛。”

结果第二天她真发了邮件过来让我试试。于是我就花了两晚,整了一个能扫码签到的系统。

架构思路其实挺简单

说白了,这玩意儿就是三部分:

  1. 人脸或二维码识别(识别是谁)
  2. 时间记录(记录签到签退时间)
  3. 界面展示(让 HR 一眼看到谁迟到早退)

最开始我打算用人脸识别,但后来发现有点麻烦,摄像头角度、光线一搞就识别不出来。后来我就换成二维码,反正每个人一个员工号,签到的时候手机一扫就行。

用 Flask 搭了个小后端

我这系统没用什么花哨的框架,就是一个 Flask + SQLite 的组合,小巧、方便部署。

后端主要负责两个接口:

  • /checkin 负责签到
  • /checkout 负责签退

核心逻辑其实就几行,比如下面这段代码:

from flask import Flask, request, jsonify
import sqlite3, datetime

app = Flask(__name__)

defdb_conn():
    conn = sqlite3.connect("attendance.db")
return conn

@app.route('/checkin', methods=['POST'])
defcheckin():
    emp_id = request.json.get("emp_id")
    now = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    conn = db_conn()
    cursor = conn.cursor()
    cursor.execute("INSERT INTO records (emp_id, checkin_time) VALUES (?, ?)", (emp_id, now))
    conn.commit()
    conn.close()
return jsonify({"status": "ok", "msg": f"{emp_id} 签到成功"})

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=8080)

数据库用的 SQLite,因为小项目够用了。建表也就一行:

CREATE TABLE records (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    emp_id TEXT,
    checkin_time TEXT,
    checkout_time TEXT
);

前端我用的 PyQt5 做的桌面端

虽然是个后端程序员,但 HR 不会用命令行,我就顺手用 PyQt5 做了个简单的可视化界面。界面上就两个按钮:“签到”和“签退”,然后显示当天所有人的状态。

from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLabel, QVBoxLayout
import requests

classAttendanceApp(QWidget):
def__init__(self):
        super().__init__()
        self.init_ui()

definit_ui(self):
        self.label = QLabel('扫描二维码签到或签退')
        self.btn_checkin = QPushButton('签到')
        self.btn_checkout = QPushButton('签退')
        self.btn_checkin.clicked.connect(self.check_in)
        self.btn_checkout.clicked.connect(self.check_out)

        layout = QVBoxLayout()
        layout.addWidget(self.label)
        layout.addWidget(self.btn_checkin)
        layout.addWidget(self.btn_checkout)
        self.setLayout(layout)
        self.setWindowTitle("电子考勤系统")
        self.show()

defcheck_in(self):
        emp_id = "E1001"# 模拟扫码结果
        res = requests.post("http://127.0.0.1:8080/checkin", json={"emp_id": emp_id})
        self.label.setText(res.json().get("msg"))

defcheck_out(self):
        emp_id = "E1001"
        res = requests.post("http://127.0.0.1:8080/checkout", json={"emp_id": emp_id})
        self.label.setText(res.json().get("msg"))

app = QApplication([])
win = AttendanceApp()
app.exec_()

虽然简陋,但 HR 说挺好用,还让我加个导出功能,于是我后来又加了个按钮,可以把考勤数据导出成 Excel:

import pandas as pd
conn = sqlite3.connect("attendance.db")
df = pd.read_sql_query("SELECT * FROM records", conn)
df.to_excel("attendance.xlsx", index=False)

实际部署的时候踩了一些坑

最开始我放在公司服务器上跑,结果第二天就被 IT 部门警告占用端口(笑)。后来我改成放在本地电脑上启动 Flask,局域网内访问。 顺便用 ngrok 开了个内网穿透,这样 HR 在家也能查记录。

有一次我忘了加锁,两个实习生同时点签到按钮,数据库插入冲突了。后来我在接口里加了一个简单的防重机制:

cursor.execute("SELECT * FROM records WHERE emp_id=? AND date(checkin_time)=date('now')", (emp_id,))
if cursor.fetchone():
return jsonify({"status": "fail", "msg": "今天已经签过到了"})

整个项目写下来就三百多行代码,但比想象中好用多了。 后来我还加了个小彩蛋:每天第一个签到的人会显示“今天你最早来公司 👍”,HR 说这个功能太有趣了。

其实用 Python 做这种轻量级系统真的挺方便的,Flask 搭个接口,SQLite 存数据,PyQt5 做个界面,半天就能出原型。 我下个计划是接入摄像头做人脸签到,到时候可能得上 OpenCV,那估计又得掉一堆头发了。

-END-

我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html

🔥虎哥私藏精品🔥

虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB,点击下方公众号回复关键字 python 全部免费领