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

以下是一个基于分层架构和模块化设计的项目规划,使用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

```

这种架构可以实现:

相关推荐
小杜不吃糖12 分钟前
llama源码学习·model.py[6]TransformerBlock类
学习·llama
云上艺旅5 小时前
K8S学习之基础四十七:k8s中部署fluentd
学习·云原生·容器·kubernetes
网络安全指导员7 小时前
威胁驱动的网络安全方法论
开发语言·学习·安全·web安全·php
Leo来编程8 小时前
Python学习第二十三天
python·学习
郭逍遥9 小时前
GZCTF平台搭建及题目上传
笔记·学习·ubuntu·docker·容器
吱屋猪_10 小时前
MyBatis 学习经验分享
经验分享·学习·mybatis
落笔画忧愁e12 小时前
数据通信学习笔记之OSPF其他内容1
笔记·学习
GHL28427109012 小时前
mysql学习-B+树相关问题
b树·学习·mysql
中草药z13 小时前
【RabbitMQ高级特性】消息确认机制、持久化、发送方确认、TTL和死信队列
java·学习·rabbitmq·java-rabbitmq·持久化·高级特性
云上艺旅13 小时前
K8S学习之基础四十六:k8s中部署Kibana
学习·云原生·容器·kubernetes