在信息爆炸的时代,高效阅读成为提升学习与工作效率的关键。通过分析电子书阅读时长,我们可以优化阅读计划、平衡不同书籍的投入时间。本文将带你开发一个个人电子书阅读时长统计工具,支持文件/手动输入阅读记录,自动计算日/周/月阅读时长,并通过可视化图表直观展示趋势。
技术思路分析
该工具分为5大核心模块:
1. 数据输入:支持从txt文件读取或手动输入阅读记录(格式:日期,开始时间,结束时间,书籍名)。
2. 时间处理:解析字符串格式的时间,计算单次阅读时长(转换为分钟)。
3. 统计分析:按日/周/月分组统计总时长,处理跨周/月的边界情况。
4. 数据可视化:用柱状图展示每日时长,折线图展示周/月趋势。
5. GUI交互:通过tkinter实现文件选择、文本输入、结果展示的友好界面。
代码实现(Python)
我们使用tkinter构建GUI,matplotlib实现可视化,datetime处理时间,collections.defaultdict简化统计。
1. 核心库导入与辅助函数
import tkinter as tk
from tkinter import filedialog, scrolledtext
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from datetime import datetime
from collections import defaultdict
import matplotlib.pyplot as plt
import calendar
2. 时间与记录解析
def parse_datetime(date, time_str):
"""将日期和时间字符串组合为datetime对象"""
time_obj = datetime.strptime(time_str, '%H:%M').time()
return datetime.combine(date, time_obj)
def calculate_duration(start_dt, end_dt):
"""计算阅读时长(分钟)"""
return (end_dt - start_dt).total_seconds() / 60
def parse_record(record):
"""解析单条阅读记录:日期,开始时间,结束时间,书籍名"""
parts = [p.strip() for p in record.split(',')]
if len(parts) != 4:
return None
date_str, start_str, end_str, book = parts
try:
date = datetime.strptime(date_str, '%Y-%m-%d').date()
start_dt = parse_datetime(date, start_str)
end_dt = parse_datetime(date, end_str)
duration = calculate_duration(start_dt, end_dt)
if duration < 0: # 结束时间早于开始时间,无效
return None
return (date, book, duration)
except Exception as e:
print(f"解析失败:{record},错误:{e}")
return None
3. 统计分析函数
def daily_stats(records):
"""按日期统计:{日期: {书籍: 总时长}, 日期: 总时长}"""
daily_books = defaultdict(lambda: defaultdict(float)) # 日期→书籍→时长
daily_total = defaultdict(float) # 日期→总时长
for date, book, dur in records:
daily_books[date][book] += dur
daily_total[date] += dur
return daily_books, daily_total
def weekly_stats(daily_total):
"""按周统计总时长(周数由isocalendar计算)"""
weekly = defaultdict(float)
for date, total in daily_total.items():
year, week, _ = date.isocalendar()
weekly[f"{year} 第{week}周"] += total
return weekly
4. 可视化函数
def plot_daily(daily_total):
"""绘制每日时长柱状图"""
dates = sorted(daily_total.keys())
totals = [daily_total[date] for date in dates]
date_labels = [d.strftime('%Y-%m-%d') for d in dates]
fig, ax = plt.subplots(figsize=(8, 4))
ax.bar(date_labels, totals, color='skyblue')
ax.set_xlabel('日期')
ax.set_ylabel('时长(分钟)')
ax.set_title('每日阅读时长统计')
plt.xticks(rotation=45)
plt.tight_layout()
return fig
def plot_weekly(weekly):
"""绘制每周时长折线图"""
weeks = sorted(weekly.keys())
totals = [weekly[week] for week in weeks]
fig, ax = plt.subplots(figsize=(8, 4))
ax.plot(weeks, totals, marker='o', color='orange')
ax.set_xlabel('周')
ax.set_ylabel('总时长(分钟)')
ax.set_title('每周阅读趋势')
plt.xticks(rotation=45)
plt.tight_layout()
return fig
5. GUI界面实现
class ReadingStatsApp:
def __init__(self, root):
self.root = root
self.root.title("电子书阅读时长统计工具")
self.records = [] # 存储解析后的记录 (date, book, duration)
self.init_ui()
def init_ui(self):
# 文件输入区域
file_frame = tk.Frame(self.root)
file_frame.pack(pady=5)
tk.Button(file_frame, text="选择阅读记录文件", command=self.load_file).pack(side=tk.LEFT, padx=5)
# 手动输入区域
input_frame = tk.Frame(self.root)
input_frame.pack(pady=5)
tk.Label(input_frame, text="手动输入记录(每行:日期,开始时间,结束时间,书籍名):").pack(anchor=tk.W, padx=5)
self.text_input = scrolledtext.ScrolledText(input_frame, width=50, height=5)
self.text_input.pack(pady=5, padx=5)
tk.Button(input_frame, text="提交", command=self.submit_manual).pack(padx=5)
# 统计结果区域
result_frame = tk.Frame(self.root)
result_frame.pack(pady=10)
tk.Label(result_frame, text="统计结果:").pack(anchor=tk.W, padx=5)
self.result_text = scrolledtext.ScrolledText(result_frame, width=60, height=6)
self.result_text.pack(pady=5, padx=5)
# 图表区域
self.fig_frame = tk.Frame(self.root)
self.fig_frame.pack(pady=10)
def load_file(self):
file_path = filedialog.askopenfilename(filetypes=[("文本文件", "*.txt")])
if file_path:
try:
with open(file_path, 'r', encoding='utf-8') as f:
self.parse_and_add(f.readlines())
except Exception as e:
self.result_text.insert(tk.END, f"文件错误:{e}\n")
def submit_manual(self):
text = self.text_input.get('1.0', tk.END).strip()
if text:
self.parse_and_add(text.split('\n'))
def parse_and_add(self, lines):
new_records = []
for line in lines:
line = line.strip()
if line:
record = parse_record(line)
if record:
new_records.append(record)
else:
self.result_text.insert(tk.END, f"解析错误:{line}\n")
self.records.extend(new_records)
self.update_stats()
def update_stats(self):
if not self.records:
self.result_text.insert(tk.END, "无有效记录!\n")
return
daily_books, daily_total = daily_stats(self.records)
weekly = weekly_stats(daily_total)
# 生成统计文本
stats = "每日统计:\n"
for date in sorted(daily_total.keys()):
total = daily_total[date]
books = daily_books[date]
details = " + ".join([f"{b}{d:.0f}分" for b, d in books.items()])
h, m = int(total // 60), int(total % 60)
stats += f"{date.strftime('%Y-%m-%d')}:{h}小时{m}分({details})\n"
stats += "\n每周趋势:\n"
for week in sorted(weekly.keys()):
total = weekly[week]
h, m = int(total // 60), int(total % 60)
avg = total / 7
avg_h, avg_m = int(avg // 60), int(avg % 60)
stats += f"{week}:总时长{h}小时{m}分,日均{avg_h}小时{avg_m}分\n"
# 绘制图表(清空旧图表)
for widget in self.fig_frame.winfo_children():
widget.destroy()
daily_fig = plot_daily(daily_total)
weekly_fig = plot_weekly(weekly)
FigureCanvasTkAgg(daily_fig, self.fig_frame).draw().get_tk_widget().pack(side=tk.LEFT, padx=5)
FigureCanvasTkAgg(weekly_fig, self.fig_frame).draw().get_tk_widget().pack(side=tk.LEFT, padx=5)
self.result_text.delete('1.0', tk.END)
self.result_text.insert(tk.END, stats)
6. 主函数(程序入口)
if __name__ == "__main__":
plt.switch_backend('TkAgg') # 适配tkinter GUI
root = tk.Tk()
app = ReadingStatsApp(root)
root.mainloop()
功能测试与优化
- 输入测试:用示例输入(文件或手动)验证时间解析和时长计算是否正确。
- 统计验证:检查日/周总时长是否与预期一致(如示例中5月1日总时长120分钟)。
- 可视化检查:柱状图的X轴日期、Y轴数值是否正确;折线图的周趋势是否匹配。
优化方向:
– 支持更多时间格式(如12小时制)。
– 增加“月统计”和多书籍对比图。
– 导出统计结果到文件。
总结
通过本项目,我们实践了文件处理、时间计算、数据统计、可视化与GUI开发的全流程。工具不仅能帮助分析阅读习惯,更能锻炼Python综合编程能力。你可以基于此扩展功能,如多设备同步记录、阅读效率分析等,让工具更贴合实际需求!
运行程序后,你可以:
– 点击“选择阅读记录文件”导入txt格式的阅读记录(每行格式:日期,开始时间,结束时间,书籍名)。
– 或在文本框手动输入记录,点击“提交”。
– 工具会自动统计并可视化你的阅读时长,帮助你优化阅读计划!