一个完整的小项目案例,涉及到项目的规划,模块的设计功能的衔接等。

以下是一个基于分层架构和模块化设计的项目规划,使用Tkinter作为GUI框架,Playwright进行浏览器操作,SQLite作为数据库:

📂 项目结构

```

web_checker/

├── main.py # 程序入口

├── config.py # 配置管理

├── gui/ # 图形界面模块

│ ├── init.py

│ └── main_window.py

├── services/ # 业务逻辑

│ ├── init.py

│ ├── website_service.py

│ └── database.py

├── browser/ # 浏览器控制

│ ├── init.py

│ └── controller.py

└── models/ # 数据模型

├── init.py

└── website.py

```

  1. 📝 config.py 配置文件

```python

import pathlib

BASE_DIR = pathlib.Path(file).parent.parent

class Config:

DB_PATH = BASE_DIR / "data" / "web_checker.db"

BROWSER_TYPE = "chromium" # chromium, firefox, webkit

HEADLESS = False

TIMEOUT = 30000 # 30秒超时

```

  1. 📦 models/website.py 数据模型

```python

from datetime import datetime

from sqlalchemy import Column, Integer, String, Boolean, DateTime

from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class WebsiteVisit(Base):

tablename = "website_visits"

id = Column(Integer, primary_key=True)

url = Column(String(500), nullable=False)

success = Column(Boolean, nullable=False)

timestamp = Column(DateTime, default=datetime.now)

error_message = Column(String(500))

```

  1. 💾 services/database.py 数据库管理

```python

from sqlalchemy import create_engine

from sqlalchemy.orm import sessionmaker

from config import Config

from models.website import Base, WebsiteVisit

class DatabaseManager:

def init(self):

self.engine = create_engine(f"sqlite:///{Config.DB_PATH}")

Base.metadata.create_all(self.engine)

self.Session = sessionmaker(bind=self.engine)

def add_visit_record(self, url, success, error=None):

with self.Session() as session:

record = WebsiteVisit(

url=url,

success=success,

error_message=error

)

session.add(record)

session.commit()

```

  1. 🌐 browser/controller.py 浏览器控制器

```python

from playwright.sync_api import sync_playwright

from config import Config

class BrowserController:

def init(self):

self.playwright = sync_playwright().start()

self.browser = getattr(self.playwright, Config.BROWSER_TYPE).launch(

headless=Config.HEADLESS

)

self.context = self.browser.new_context()

def visit_website(self, url):

page = self.context.new_page()

try:

response = page.goto(url, timeout=Config.TIMEOUT)

return response.ok

except Exception as e:

return False, str(e)

finally:

page.close()

def del(self):

self.context.close()

self.browser.close()

self.playwright.stop()

```

  1. 🧠 services/website_service.py 业务逻辑

```python

from threading import Thread

from browser.controller import BrowserController

from services.database import DatabaseManager

class WebsiteService:

def init(self):

self.db = DatabaseManager()

self.browser_controller = BrowserController()

def open_website(self, url, callback=None):

def async_task():

success, error = True, None

try:

result = self.browser_controller.visit_website(url)

success = result if isinstance(result, bool) else result.ok

except Exception as e:

success = False

error = str(e)

self.db.add_visit_record(url, success, error)

if callback:

callback(success, error)

Thread(target=async_task).start()

```

  1. 🖥️ gui/main_window.py GUI界面

```python

import tkinter as tk

from tkinter import ttk

from services.website_service import WebsiteService

class MainWindow(tk.Tk):

def init(self, website_list):

super().init()

self.title("Website Checker")

self.service = WebsiteService()

self._create_widgets(website_list)

def _create_widgets(self, website_list):

self.tree = ttk.Treeview(self, columns=("checkbox", "url"), show="headings")

self.tree.heading("checkbox", text="Select")

self.tree.heading("url", text="URL")

for url in website_list:

self._add_website_row(url)

self.tree.pack(fill=tk.BOTH, expand=True)

绑定复选框事件

self.tree.bind("<Button-1>", self._on_checkbox_click)

def _add_website_row(self, url):

item = self.tree.insert("", tk.END, values=("☐", url))

self.tree.set(item, "checkbox", "☐")

def _on_checkbox_click(self, event):

region = self.tree.identify("region", event.x, event.y)

if region != "cell":

return

column = self.tree.identify_column(event.x)

item = self.tree.identify_row(event.y)

if column == "#1": # 复选框列

current_val = self.tree.set(item, "checkbox")

new_val = "☑" if current_val == "☐" else "☐"

self.tree.set(item, "checkbox", new_val)

if new_val == "☑":

url = self.tree.set(item, "url")

self.service.open_website(

url,

lambda success, error: self._update_status(item, success, error)

)

def _update_status(self, item, success, error):

status = "✓" if success else f"✗ ({error[:20]})"

self.tree.set(item, "status", status)

```

  1. 🚀 main.py 程序入口

```python

from gui.main_window import MainWindow

def load_websites():

这里可以替换为从文件读取网站列表

return [

"https://www.google.com",

"https://www.github.com",

"https://www.example.com"

]

if name == "main":

websites = load_websites()

app = MainWindow(websites)

app.mainloop()

```

🔑 关键设计要点:

  1. **多线程架构**:
  • 使用独立线程处理浏览器操作,避免阻塞GUI主线程

  • 通过回调机制更新界面状态

  1. **数据流向**:

```

GUI事件 → 业务服务层 → 浏览器控制 → 数据库记录 → 界面反馈

```

  1. **扩展性设计**:
  • 可在config.py中添加浏览器参数配置

  • 数据库层支持切换不同SQL方言

  • 状态反馈列可扩展显示更多详细信息

  1. **错误处理**:
  • 捕获浏览器操作异常

  • 记录详细的错误信息到数据库

  • 界面显示简明的错误提示

  1. **界面优化建议**:
  • 添加加载状态指示器

  • 增加右键菜单管理网站列表

  • 支持双击打开详细访问记录

🛠️ 扩展建议:

  1. **添加日志系统**:

```python

utils/logger.py

import logging

from config import Config

def setup_logger():

logging.basicConfig(

filename=Config.LOG_PATH,

level=logging.INFO,

format="%(asctime)s - %(levelname)s - %(message)s"

)

```

  1. **支持异步Playwright**:

```python

修改browser/controller.py使用async API

import asyncio

from playwright.async_api import async_playwright

class AsyncBrowserController:

async def visit_website(self, url):

async with async_playwright() as p:

browser = await getattr(p, Config.BROWSER_TYPE).launch()

...

```

  1. **添加数据看板**:

```python

gui/dashboard.py

class Dashboard(ttk.Frame):

def init(self, parent):

super().init(parent)

self._create_charts()

def _create_charts(self):

使用matplotlib嵌入图表

pass

```

这种架构可以实现:

相关推荐
西岸行者5 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意5 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码5 天前
嵌入式学习路线
学习
毛小茛5 天前
计算机系统概论——校验码
学习
babe小鑫5 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms5 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下5 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。5 天前
2026.2.25监控学习
学习
im_AMBER5 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J5 天前
从“Hello World“ 开始 C++
c语言·c++·学习