20251229 2025-2026-2 《Python程序设计》实验四报告

20251229 2025-2026-2 《Python程序设计》实验四报告

课程:《Python程序设计》
班级: 2512
姓名: 李佳豪
学号:20251229
实验教师:王志强
实验日期:2026年6月3日
必修/选修: 公选课

RedBook思政智慧学习平台

image

一、项目背景与动机

我平时比较喜欢学思政,经常看人民网、新华网和求是网上面的文章。但有个问题一直困扰我——每次想找某个主题(比如“脱贫攻坚”或“文化自信”)的资料,都得一篇一篇地搜,然后手动保存到文件夹里,时间长了桌面乱七八糟,找起来特别费劲。

这学期学了Python爬虫之后,我突然想到一个办法:能不能让程序自动帮我去这些网站找文章,然后按主题分类存好?这样一来我就不用自己一个一个找了。所以我就决定做这么一个小工具,能够帮我自动下载、整理思政文章,并且用书架的形式展示出来,方便我随时查看。

这个项目我给它起了个名字叫“RedBook思政智慧学习平台”,主要包含以下五个核心功能:

  1. 文章自动采集:输入关键词(如“脱贫攻坚”、“文化自信”),程序自动从7个权威思政网站搜索并下载相关文章。
  2. 文献分类整理:下载的文章自动按主题存入对应的文件夹,并统计各主题下的文章数量。
  3. 可视化书架展示:以图形界面将所有主题展示为书本形式,每本书显示主题名称和文章篇数,支持滚动浏览。
  4. 自定义创建新主题:用户可通过界面输入框和按钮,创建任意新主题,系统自动生成对应的文件夹并刷新书架。
  5. 异步下载与进度反馈:下载文章时界面不冻结,通过进度条和百分比实时反馈下载进度。

做完这个项目之后,我才算真正搞懂了爬虫是咋回事、多线程到底是干啥用的、tkinter怎么做界面。更重要的是,我发现编程确实能解决实际生活中的问题,挺有成就感的。

二、实验分析

2.1 需求分析

本平台主要实现以下五个功能:

  1. 文章自动采集

用户输入关键词(如“文化自信”、“红船精神”),程序从多个权威思政网站自动搜索并下载相关文章。下载时需要显示进度,界面不能卡死。

  1. 文献分类整理

下载的文章按主题关键词自动存放到桌面“思政文献库”的对应子文件夹中。每个主题文件夹内存放.html格式的文章文件,系统自动统计文件数量并显示在书架上。

  1. 可视化书架管理

以图形界面展示所有主题,每个主题表现为一本书的图标,下方显示主题名称和文章篇数。书架支持滚动浏览,双击书本或书名可直接打开对应文件夹。

  1. 自定义扩展主题

用户可通过界面上的输入框和按钮创建新主题,系统自动生成对应文件夹并刷新书架。新主题同样支持文章采集。

  1. 异步下载与进度反馈

下载文章时界面不冻结,通过进度条和百分比实时反馈下载进度。

此外还有几点考虑:如果某个网站连不上,程序不能崩溃,要跳过继续执行;代码要分模块写,方便后续修改;由于用到了os.startfile等Windows API,目前仅在Windows环境下测试运行。

2.2 可行性分析

从技术上看,Python有现成的库支持:爬虫用requests和BeautifulSoup,界面用tkinter,图像处理用PIL,打包用PyInstaller。

爬虫这块我想过直接爬人民网,但实际操作发现反爬比较严。后来换了个思路:用Bing搜索的site:语法来搜,从搜索结果里提取文章链接。这样能绕过目标网站的直接反爬。

下载卡界面的问题,用threading开子线程就能解决,主线程继续处理界面事件。

数据存储直接用文件夹加HTML文件,不需要装数据库,够用且简单。

使用上,打包成exe后双击就能运行,不需要配置环境。界面上的按钮和提示比较直观,基本不需要说明书。程序首次运行会在桌面自动创建“思政文献库”文件夹,并生成示例主题。

数据来源都是公开网页,仅用于个人学习,且请求间隔控制在0.5秒以上,对目标网站无压力。

2.3 数据流说明

用户创建新主题时,程序在桌面“思政文献库”下新建同名文件夹,刷新书架即可看到新书。

用户点击下载时,程序启动子线程搜索文章,逐篇下载到对应文件夹,进度窗口实时更新,完成后书架上的数量自动刷新。

用户双击书本图标时,程序调用os.startfile直接打开该主题的文件夹。

三、实验设计

3.1 总体结构

程序划分为五个模块:
GUI模块(BookshelfApp类)负责界面展示与用户交互;
爬虫模块负责文章搜索与下载;文件管理模块负责本地文献库维护;
图标绘制模块动态生成书本图标;
异步任务模块处理耗时下载,避免界面冻结。
各模块之间通过函数调用和回调通信,爬虫与GUI解耦,便于后续扩展。

3.2 模块详细设计

3.2.1 GUI模块

主要属性包括:主窗口root、滚动区域(canvas、scrollbar、scrollable_frame)、书籍卡片列表book_widgets、图标引用列表book_images、输入框new_keyword_entry。

主要方法:__init__初始化窗口并加载书架;load_bookshelf动态创建书籍卡片(每本书包含图标、书名、文章数量、下载按钮);create_new_book创建新主题文件夹并刷新书架;start_download启动子线程执行下载;refresh_book_count更新文章数量;open_folder打开系统文件夹;_on_mousewheel处理滚轮滚动。

布局上,顶部固定区域放置标签、输入框和按钮,中间是Canvas内嵌Frame实现的滚动区域,书籍使用grid布局(每行4本,水平间距30px,垂直间距20px),底部放置提示标签。

3.2.2 爬虫模块

设计思路:通过Bing搜索的site:语法定向搜索目标网站。每次搜索最多两页,每页10条结果,避免请求过于频繁。

函数 功能
search_site 针对单个站点搜索,返回文章列表
search_all_sites 遍历所有站点,汇总并去重
download_article 下载单篇文章的HTML
download_articles_for_keyword 协调搜索与下载,回调更新进度

防反爬措施:设置User-Agent请求头、请求间隔0.5秒、异常捕获后继续执行。

3.2.3 文件管理模块

使用os.path.expanduser("~")获取用户桌面路径,避免硬编码。create_demo_folders首次运行时创建8个示例主题文件夹和说明文件。get_keyword_folders遍历返回所有子文件夹。count_files_in_folder统计文件数量。

文件夹结构:

~/Desktop/思政文献库/
├── 脱贫攻坚/
│   ├── 说明.txt
│   └── 文章1.html
└── 文化自信/
    ├── 说明.txt
    └── 文章2.html

3.2.4 图标绘制模块

用Pillow绘制扁平书本图标:创建80×100透明图像,左侧1/5为深棕色书脊,右侧4/5为浅米色封面,中间画两条黑色横线装饰,转ImageTk.PhotoImage供tkinter.Label使用。

3.2.5 异步任务模块

爬虫下载涉及网络请求,若在主线程执行会阻塞界面。解决方案:用threading.Thread将下载任务放入后台线程,通过root.after将UI更新操作委托给主线程。每完成一篇调用回调更新进度条和百分比标签,全部完成后刷新文章数量。

3.3 数据结构

变量 类型 用途
SITES 列表 权威网站域名列表
HEADERS 字典 请求头,伪装浏览器
self.book_widgets 列表 存(book_frame, count_label, keyword, path)
self.book_images 列表 存PhotoImage引用,防垃圾回收
articles 列表 临时存(title, url)
progress_callback 函数 子线程向主线程汇报进度

3.4 算法流程

启动流程:main → create_demo_folders → 创建Tk根窗口 → 加载书架 → 进入主循环

下载流程:点击下载 → 创建进度窗口 → 启动子线程 → 搜索所有站点 → 遍历下载 → 每完成一篇回调更新进度 → 全部完成 → 关闭进度窗口 → 刷新文章数量

创建新书流程:输入关键词 → 检查是否为空 → 检查是否已存在 → 创建文件夹和说明文件 → 刷新书架

3.5 异常处理

异常场景 处理方式
网络请求超时/失败 捕获异常,跳过当前请求继续下一个
搜索结果为空 返回空列表
页面404 检查响应内容前300字符,含"404"则跳过
线程中更新UI 通过root.after委托给主线程

3.6 界面布局

主窗口900×650像素,背景色#F5E6D3。顶部框架放置“自定义新书关键词:”标签、输入框(宽20字符)、“创建新书架”按钮。
中间为滚动区域,书籍卡片使用grid布局,每行4本,卡片间水平间距30px、垂直间距20px。每本书从上至下依次为:
书本图标(绑定单击事件)、书名(加粗深棕色,绑定单击事件)、文章数量(灰色小字)、下载按钮(棕色背景白字)。底部放置提示标签。

3.7 打包

使用PyInstaller打包命令:

pyinstaller --onefile --windowed --icon=myicon.ico 图书馆模拟器.py

--onefile生成单文件,--windowed不显示控制台,--icon指定图标。打包后dist/图书馆模拟器.exe可直接运行。

四、代码实现

根据第三部分的实验设计,我逐步实现了各个模块。首先搭建开发环境(Python 3.14 + 虚拟环境 + 安装依赖库),
然后依次编写文件管理模块、图标绘制模块、爬虫模块、GUI 主类,并进行了多线程异步下载和进度反馈的优化。
最后使用 PyInstaller 打包为独立 exe。下面是各模块的关键代码实现:

1. 配置与导入

点击查看:导入库与全局配置
import os
import tkinter as tk
from tkinter import messagebox, ttk
from PIL import Image, ImageTk, ImageDraw
import requests
from bs4 import BeautifulSoup
import time
import re
from urllib.parse import quote
import threading

# ================== 配置 ==================
ROOT_DIR = os.path.join(os.path.expanduser("~"), "Desktop", "思政文献库")
BOOKS_PER_ROW = 4
BG_COLOR = "#F5E6D3"          # 米色背景
SHELF_COLOR = "#8B5A2B"       # 木质色(仅用于按钮等)

# 思政权威网站列表
SITES = [
    "people.com.cn",
    "xinhuanet.com",
    "qstheory.cn",
    "gmw.cn",
    "dangjian.cn",
    "cctv.com",
    "gov.cn",
]
HEADERS = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'}

2. 文件管理模块(创建示例文件夹、获取主题列表)

点击查看:文件管理函数
def create_demo_folders():
    if not os.path.exists(ROOT_DIR):
        os.makedirs(ROOT_DIR)
        demo_keywords = ["脱贫攻坚", "文化自信", "红船精神", "中国梦",
                         "一带一路", "生态文明", "科技创新", "依法治国"]
        for kw in demo_keywords:
            folder = os.path.join(ROOT_DIR, kw)
            if not os.path.exists(folder):
                os.makedirs(folder)
                readme = os.path.join(folder, "说明.txt")
                with open(readme, "w", encoding="utf-8") as f:
                    f.write(f"这里存放关于“{kw}”的思政文章。\n请将您的文章文件放入此文件夹。")

def get_keyword_folders():
    if not os.path.exists(ROOT_DIR):
        return []
    items = os.listdir(ROOT_DIR)
    folders = []
    for item in items:
        full = os.path.join(ROOT_DIR, item)
        if os.path.isdir(full):
            folders.append((item, full))
    return folders

3. 书本图标绘制模块

点击查看:扁平书本图标绘制函数
def create_flat_book_icon(size=(80, 100)):
    """扁平风格书本图标"""
    img = Image.new('RGBA', size, (255, 255, 255, 0))
    draw = ImageDraw.Draw(img)
    # 书脊
    draw.rectangle([0, 0, size[0] // 5, size[1]], fill="#6B3E1F")
    # 封面
    cover_color = (200, 180, 140)
    draw.rectangle([size[0] // 5, 0, size[0], size[1]], fill=cover_color)
    # 书名线
    line_y = size[1] // 2
    draw.line([(size[0] // 5 + 5, line_y), (size[0] - 10, line_y)], fill=(0, 0, 0), width=2)
    draw.line([(size[0] // 5 + 5, line_y + 15), (size[0] - 10, line_y + 15)], fill=(0, 0, 0), width=1)
    return ImageTk.PhotoImage(img)

4. 爬虫模块

4.1 单站点搜索

点击查看:search_site 函数
def search_site(keyword, site, max_pages=2):
    base_url = "https://cn.bing.com/search?q=site%3A{}+{}&first={}"
    articles = []
    for page in range(max_pages):
        first = page * 10 + 1
        search_url = base_url.format(site, quote(keyword), first)
        try:
            resp = requests.get(search_url, headers=HEADERS, timeout=10)
            resp.encoding = 'utf-8'
            soup = BeautifulSoup(resp.text, 'html.parser')
            for li in soup.find_all('li', class_='b_algo'):
                h2 = li.find('h2')
                if not h2:
                    continue
                a = h2.find('a')
                if not a:
                    continue
                title = a.get_text(strip=True)
                url = a.get('href')
                if url and site in url and not url.startswith('https://cn.bing.com'):
                    clean_url = url.split('&')[0]
                    articles.append((title, clean_url))
            time.sleep(0.5)
        except Exception:
            continue
    return articles

4.2 多站点汇总与去重

点击查看:search_all_sites 函数
def search_all_sites(keyword, max_pages_per_site=2):
    all_articles = []
    for site in SITES:
        articles = search_site(keyword, site, max_pages_per_site)
        all_articles.extend(articles)
        time.sleep(1)
    seen = set()
    unique = []
    for title, url in all_articles:
        if url not in seen:
            seen.add(url)
            unique.append((title, url))
    return unique

4.3 单篇文章下载

点击查看:download_article 函数
def download_article(title, url, save_dir):
    try:
        resp = requests.get(url, headers=HEADERS, timeout=15)
        if resp.status_code != 200:
            return False
        resp.encoding = 'utf-8'
        if "404" in resp.text[:300] or "Not Found" in resp.text[:300]:
            return False
        safe_title = re.sub(r'[\\/*?:"<>|]', '_', title[:50])
        filename = f"{safe_title}.html"
        save_path = os.path.join(save_dir, filename)
        with open(save_path, 'w', encoding='utf-8') as f:
            f.write(resp.text)
        return True
    except Exception:
        return False

4.4 下载调度器(含进度回调)

点击查看:download_articles_for_keyword 函数
def download_articles_for_keyword(keyword, target_folder, progress_callback=None):
    if progress_callback:
        progress_callback(0, 0, 0, f"正在搜索关键词:{keyword} ...")
    articles = search_all_sites(keyword, max_pages_per_site=2)
    if not articles:
        if progress_callback:
            progress_callback(0, 0, 0, "未找到任何文章")
        return 0
    total = len(articles)
    success = 0
    for i, (title, url) in enumerate(articles, 1):
        percent = int(i / total * 100)
        if progress_callback:
            progress_callback(i, total, percent, f"下载中 ({i}/{total}, {percent}%): {title[:40]}...")
        if download_article(title, url, target_folder):
            success += 1
        time.sleep(0.5)
    return success

5. GUI 主类 BookshelfApp

5.1 初始化与界面布局

点击查看:__init__ 及滚动区域创建
class BookshelfApp:
    def __init__(self, root):
        self.root = root
        self.root.title("思政书架 - 智能下载器")
        self.root.geometry("900x650")
        self.root.configure(bg=BG_COLOR)

        # 顶部:自定义关键词区域
        top_frame = tk.Frame(root, bg=BG_COLOR, pady=10)
        top_frame.pack(fill="x", padx=20)

        tk.Label(top_frame, text="自定义新书关键词:", bg=BG_COLOR, font=("微软雅黑", 10)).pack(side="left")
        self.new_keyword_entry = tk.Entry(top_frame, width=20, font=("微软雅黑", 10))
        self.new_keyword_entry.pack(side="left", padx=5)
        self.new_keyword_entry.bind("<Return>", lambda e: self.create_new_book())
        tk.Button(top_frame, text="📚 创建新书架", command=self.create_new_book,
                  bg=SHELF_COLOR, fg="white", font=("微软雅黑", 9)).pack(side="left", padx=5)

        # 滚动区域
        self.canvas = tk.Canvas(root, bg=BG_COLOR, highlightthickness=0)
        self.scrollbar = tk.Scrollbar(root, orient="vertical", command=self.canvas.yview)
        self.scrollable_frame = tk.Frame(self.canvas, bg=BG_COLOR)
        self.scrollable_frame.bind("<Configure>", lambda e: self.canvas.configure(scrollregion=self.canvas.bbox("all")))
        self.canvas.create_window((0, 0), window=self.scrollable_frame, anchor="nw")
        self.canvas.configure(yscrollcommand=self.scrollbar.set)

        self.canvas.pack(side="left", fill="both", expand=True)
        self.scrollbar.pack(side="right", fill="y")

        self.canvas.bind_all("<MouseWheel>", self._on_mousewheel)

        self.book_widgets = []
        self.book_images = []

        self.load_bookshelf()

5.2 鼠标滚轮与创建新书

点击查看:滚轮事件、创建新书架方法
    def _on_mousewheel(self, event):
        self.canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")

    def create_new_book(self):
        keyword = self.new_keyword_entry.get().strip()
        if not keyword:
            messagebox.showwarning("提示", "请输入关键词")
            return
        new_folder = os.path.join(ROOT_DIR, keyword)
        if os.path.exists(new_folder):
            messagebox.showinfo("提示", f"「{keyword}」书架已存在,无需重复创建")
            self.new_keyword_entry.delete(0, tk.END)
            return
        os.makedirs(new_folder, exist_ok=True)
        readme = os.path.join(new_folder, "说明.txt")
        with open(readme, "w", encoding="utf-8") as f:
            f.write(f"这是“{keyword}”主题的思政文章存放处。\n可使用下载按钮自动获取相关内容。")
        messagebox.showinfo("成功", f"已创建「{keyword}」书架")
        self.new_keyword_entry.delete(0, tk.END)
        self.load_bookshelf()

5.3 加载书架(动态创建书籍卡片)

点击查看:load_bookshelf 方法
    def load_bookshelf(self):
        for widget in self.scrollable_frame.winfo_children():
            widget.destroy()
        self.book_widgets.clear()
        self.book_images.clear()

        folders = get_keyword_folders()
        if not folders:
            label = tk.Label(self.scrollable_frame, text="暂无书架,请使用上方输入框创建新书架",
                             bg=BG_COLOR, font=("微软雅黑", 12))
            label.pack(pady=50)
            return

        row, col = 0, 0
        for keyword, path in folders:
            book_frame = tk.Frame(self.scrollable_frame, bg=BG_COLOR)
            book_frame.grid(row=row, column=col, padx=30, pady=20, sticky="n")

            icon_img = create_flat_book_icon((80, 100))
            self.book_images.append(icon_img)
            icon_label = tk.Label(book_frame, image=icon_img, bg=BG_COLOR, cursor="hand2")
            icon_label.pack()
            icon_label.bind("<Button-1>", lambda e, p=path: self.open_folder(p))

            name_label = tk.Label(book_frame, text=keyword, bg=BG_COLOR, font=("微软雅黑", 10, "bold"),
                                  cursor="hand2", fg="#4A2A1A")
            name_label.pack()
            name_label.bind("<Button-1>", lambda e, p=path: self.open_folder(p))

            file_count = self.count_files_in_folder(path)
            count_label = tk.Label(book_frame, text=f"{file_count}篇", bg=BG_COLOR, font=("微软雅黑", 8), fg="gray")
            count_label.pack()

            download_btn = tk.Button(book_frame, text="📥 下载文章", font=("微软雅黑", 8),
                                     command=lambda kw=keyword, p=path: self.start_download(kw, p))
            download_btn.pack(pady=(5, 0))

            self.book_widgets.append((book_frame, count_label, keyword, path))

            col += 1
            if col >= BOOKS_PER_ROW:
                col = 0
                row += 1

        tip = tk.Label(self.scrollable_frame,
                       text="💡 单击书本图标打开文件夹,点击「下载文章」自动爬取思政文章",
                       bg=BG_COLOR, font=("微软雅黑", 9), fg="gray")
        tip.grid(row=row+1, column=0, columnspan=BOOKS_PER_ROW, pady=20)

    def count_files_in_folder(self, folder):
        if not os.path.exists(folder):
            return 0
        return len([f for f in os.listdir(folder) if os.path.isfile(os.path.join(folder, f))])

    def refresh_book_count(self, path, count_label):
        new_count = self.count_files_in_folder(path)
        count_label.config(text=f"{new_count}篇")

5.4 异步下载与进度窗口

点击查看:start_download 及进度更新
    def start_download(self, keyword, target_folder):
        progress_win = tk.Toplevel(self.root)
        progress_win.title("下载进度")
        progress_win.geometry("450x150")
        progress_win.transient(self.root)
        progress_win.grab_set()
        progress_win.resizable(False, False)

        label_status = tk.Label(progress_win, text="准备开始下载...", font=("微软雅黑", 10))
        label_status.pack(pady=10)
        progress_bar = ttk.Progressbar(progress_win, orient="horizontal", length=350, mode="determinate")
        progress_bar.pack(pady=10)
        label_percent = tk.Label(progress_win, text="0%", font=("微软雅黑", 9))
        label_percent.pack(pady=5)
        label_detail = tk.Label(progress_win, text="", font=("微软雅黑", 9), fg="gray")
        label_detail.pack(pady=5)

        def update_progress(current, total, percent, message):
            self.root.after(0, lambda: label_status.config(text=message))
            if total > 0:
                self.root.after(0, lambda: progress_bar.configure(maximum=total, value=current))
                self.root.after(0, lambda: label_percent.config(text=f"{percent}%"))
            self.root.after(0, lambda: label_detail.config(text=f"进度: {current}/{total}" if total > 0 else message))

        def download_task():
            try:
                success = download_articles_for_keyword(keyword, target_folder, update_progress)
                self.root.after(0, progress_win.destroy)
                self.root.after(0, lambda: messagebox.showinfo("完成", f"成功下载 {success} 篇文章到「{keyword}」文件夹"))
                for _, count_label, kw, path in self.book_widgets:
                    if kw == keyword and path == target_folder:
                        self.root.after(0, lambda p=path, lbl=count_label: self.refresh_book_count(p, lbl))
                        break
            except Exception as e:
                self.root.after(0, progress_win.destroy)
                self.root.after(0, lambda: messagebox.showerror("错误", f"下载失败:{str(e)}"))

        threading.Thread(target=download_task, daemon=True).start()

    def open_folder(self, folder_path):
        if os.path.exists(folder_path):
            os.startfile(folder_path)
        else:
            messagebox.showerror("错误", f"文件夹不存在:\n{folder_path}")

6. 主程序入口

点击查看:主程序启动
if __name__ == "__main__":
    create_demo_folders()
    root = tk.Tk()
    app = BookshelfApp(root)
    root.mainloop()

五、实验结果

图标界面

image

书架界面

image

用华为云运行

d7bcca9999acb4f43af06aa2b652b2bc
a2fb20a2fee6eae9bcab648eea961beb

用华为云运行视频

【尝试在云上运行】

视频呈现

【容成工业】

Gitee链接

我的Gitee代码仓库

六、实验过程中遇到的问题和解决过程

1. 爬虫频繁遭遇反爬,一度想要放弃项目

问题描述:
在项目初期,我尝试直接请求人民网、新华网等思政网站的文章页面,
但很快发现这些站点对陌生爬虫不友好——要么返回 404 状态码,要么跳转到验证页面,甚至直接封锁 IP。
连续几天无法获取任何数据,让我几度想要放弃这个项目。

解决过程:
经过查阅资料和请教同学,我意识到直接爬取目标网站难度太大,转而采用“曲线救国”策略:
使用 Bing 搜索引擎的 site: 语法进行定向搜索。构造 URL https://cn.bing.com/search?q=site:people.com.cn+关键词,
然后解析搜索结果页面中的真实链接。这种方法避开了目标站点的反爬机制,而且 Bing 对普通爬虫的容忍度较高。
同时,我在请求头中设置了合理的 User-Agent,并在每次请求后 time.sleep(0.5) 降低频率,最终成功稳定获取文章链接。
(对应源代码:SITES 列表、search_site 函数、HEADERS、time.sleep)

2. 打包 exe 时图标文件找不到

问题描述:
使用 PyInstaller 打包时,命令 --icon=myicon.ico 一直报错 FileNotFoundError:
Icon input file not found。我明明已经把图标文件放在项目文件夹里了,为什么还是找不到?

解决过程:
经过反复检查,我发现问题出在文件层级上:我把 myicon.ico 放在了代码的子文件夹(比如 build/剪刀石头布/图标/)里,
而 PyInstaller 默认只在脚本所在的目录和当前工作目录查找图标文件。解决方案是将图标文件移到与 图书馆模拟器.py 同一级目录下,
并确保文件名和扩展名完全正确。此后打包时图标都能正常应用。

3. 界面美化尝试多次,最终放弃复杂设计

问题描述:
为了提升视觉体验,我曾尝试加入木质背景、立体书图标、圆角卡片等效果。
但经过多次修改和测试,不是背景错位,就是书本图标显示异常,甚至导致滚动区域卡顿。花了很多时间,效果依然不理想。

解决过程:
反思后,我认识到自己的前端美学功底不足,与其做出一个漏洞百出的“花哨”界面,不如回归简约、清晰、稳定的设计。
最终采用了米色纯背景(#F5E6D3)、扁平书本图标(PIL 简单绘制)、规整的网格布局。这个版本虽然不惊艳,但运行流畅、
功能完整、用户能直观理解,符合“够用就好”的原则。
(对应源代码:BG_COLOR、create_flat_book_icon 函数、无立体书/木纹背景代码)

4. 下载文章时界面卡死,进度条不更新

问题描述:
点击“下载文章”后,整个窗口像死机一样无法拖动或滚动,直到所有文章下载完毕才恢复。
进度窗口虽然弹出了,但进度条一直停在 0%,下载完成后才突然跳到 100%。

解决过程:
原因在于网络请求是在主线程中同步执行的,阻塞了 tkinter 的事件循环。
解决方案是将下载任务放到子线程中执行,同时通过回调函数和 root.after 方法将 UI 更新操作(修改进度条数值、百分比标签)委托给主线程。
改造后,下载过程中界面可以正常滚动,进度条实时刷新百分比,用户体验大幅提升。
(对应源代码:threading.Thread、update_progress 中的 self.root.after、start_download 方法)

对全课所学知识的总结

本学期的第一次课程令我印象非常深刻。王老师首先讲了几组概念的区别:Python是解释性语言,C语言是编译性语言;高级语言是给人看的,低级语言是给机器看的。其中最生动的莫过于面向对象与面向过程的区别——王老师巧妙地把它比喻成“蛋炒饭”与“盖浇饭”:面向过程好比蛋炒饭,每一步都得自己按顺序炒;面向对象好比盖浇饭,只需把封装好的模块拼装起来就能完成特定需求。通过这些形象的比喻,王老师引出了Python的几个关键特点:①跨平台(可在不同操作系统运行);②面向对象;③解释性;④动态数据类型。这些特点为我们后续学习做了很好的铺垫。

本学期Python课程循序渐进,从基础数据结构起步,依次学习正则表达式、面向对象编程、文件操作、数据库、Socket网络通信,最后学习爬虫开发,整套知识由浅入深、层层铺垫。课程最先讲解四大内置序列:列表有序可修改,元组创建后无法改动,字典依靠键值对存储信息,集合会自动剔除重复元素,这四类结构是处理各种数据的底层基础。随后我们学习正则表达式,它并非Python独有,核心作用是文本模式匹配,能高效筛选、提取文本中的目标内容。

课程的重难点是面向对象编程,封装、继承、多态是其三大核心要素。类如同设计图纸,由属性和方法组成,实例化后生成可操作的对象;子类可以继承父类全部功能,还能重写原有方法实现新逻辑。文件操作依靠open()函数,区分只读、写入、追加、二进制等打开模式,规范完成文件的打开、读写与关闭。数据库章节区分了结构化、半结构化、非结构化三类数据;Socket由IP地址加端口号构成,是设备间进程网络通信的基础。最后学习爬虫,通过HTTP协议发起URL请求,配置请求头模拟浏览器以降低被反爬的风险,搭配lxml、BeautifulSoup等工具解析网页并提取数据。

整门课程知识点覆盖全面,搭建起完整的Python编程体系。在学期末的综合实践中,我将爬虫、文件管理、图形界面(tkinter)、多线程等技术融合,完成了“RedBook思政智慧学习平台”,真正做到了学以致用。通过这一学期的学习,我不仅掌握了Python语法和常用库,更培养了独立解决问题和调试代码的能力,为今后的学习和项目开发打下了扎实的基础。

课程感想与体会

一、学习过程回顾

初次听说王老师的课是从学长们的推荐中得来的:“这节课老师很认真,真的能学到东西。”我便兴致冲冲地报名而来。虽然平时课业很忙,大多没有时间自己练习代码,但每一节课我都抓紧每一分钟,生怕漏掉某个知识点。由于编程基础不好,老师的上课节奏对我来说还是有点快,但能用一学期十几次课把整个Python讲得差不多,也不能全怪老师,更多是自己课下有些懒惰,没有花时间练习。

老师课堂上的提问环节真的帮了我大忙。学了一周的东西不去复习,当时再怎么听懂也忘得差不多了。幸亏有王老师的“温故知新”环节,每次都帮助我重拾记忆,让我对知识有了更深刻的理解。

二、综合实践感悟

记得第一次课,王老师就说:这门课的最终目的是让每位同学都能自主编写一个程序。我一开始觉得很高大上,也很感兴趣。这次综合实验,我想编写一个我能实际用得着的程序——网络安全、舆情分析对我来说有点遥远,小游戏又没什么实际用途。联想到近年国考加入了思想政治的考察,阅读思政文章成为重要需求,我的想法便一触即发:设计一个能直接帮我下载、分类、整理文献资料的程序。于是,“RedBook思政智慧学习平台”诞生了!

虽然这个成果看起来有点简陋,甚至根本谈不上“智慧”,但它现在真的实现了我最初设想的所有功能。当设想最终变成现实的那一刻,我真的很激动。我的代码功底和计算机基础不好,很多时候遇到棘手的问题一头雾水,只能疯狂查资料、求助于网络。这次程序的成功,DeepSeek帮了我很大的忙,让我以为自己不可能实现的事情变成了可能。我也真切感受到:在AI爆发的时代,每一个人都有潜力成为自己的工程师。

三、对课程的建议

如果要说一点建议,我希望王老师以后可以多带大家写几个实用的程序,或者讲得慢一点,给基础弱的同学多一点关照。这样我们能更好地跟上节奏,也能从实际案例中更牢固地掌握知识点。

四、寄语与感悟

最打动我的,是王老师在结课时的几个寄语:

① 不要完全依赖于大模型,不要做只会复制粘贴的提线木偶。
② 大学最珍贵的,从来不是分数,而是真正长出来的本事(核心竞争力)。
③ 迷茫不可怕,松懈最可惜。“最慢的脚步不是跬步,而是徘徊;最快的脚步不是冲刺,而是坚持。”

相比于学到的Python知识点,这些寄语带给我的思考与警醒、激励与反思,才是我上这门课最重要的精神收获。感谢王老师的辛勤付出!

参考资料

posted @ 2026-06-15 15:11  20251229李佳豪  阅读(7)  评论(0)    收藏  举报