当前位置: 首页 > article >正文

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

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

```

 

2. 📦 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))

```

 

3. 💾 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()

```

 

4. 🌐 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()

```

 

5. 🧠 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()

```

 

6. 🖥️ 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)

```

 

7. 🚀 __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主线程

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

 

2. **数据流向**:

   ```

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

   ```

 

3. **扩展性设计**:

   - 可在config.py中添加浏览器参数配置

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

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

 

4. **错误处理**:

   - 捕获浏览器操作异常

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

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

 

5. **界面优化建议**:

   - 添加加载状态指示器

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

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

 

🛠️ 扩展建议:

 

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"

    )

```

 

2. **支持异步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()

            # ...

```

 

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

```python

# gui/dashboard.py

class Dashboard(ttk.Frame):

    def __init__(self, parent):

        super().__init__(parent)

        self._create_charts()

    

    def _create_charts(self):

        # 使用matplotlib嵌入图表

        pass

```

 

这种架构可以实现:

- 修改浏览器类型只需调整config.py

- 更换数据库只需修改database.py

- 添加新功能模块不会影响核心逻辑

- 各组件可独立测试(浏览器操作、数据库访问等)


http://www.kler.cn/a/596489.html

相关文章:

  • “智改数转”新风口,物联网如何重构制造业竞争力?
  • 996引擎-接口测试:音效测试NPC
  • 1、环境初始化--Linux安装dockerCE
  • OpenCV Calib3d 模块使用指南
  • 科学计算库:Numpy
  • 3389远程桌面爆破
  • 破解内存瓶颈:如何通过内存池优化资源利用
  • Cannon.js 物理引擎入门(Three.js 结合 Cannon.js)
  • Android10 系统截屏功能异常的处理
  • python每日十题(5)
  • HTML超链接
  • 网络层之IP协议
  • 网络HTTPS协议
  • 从碎片化到标准化:案例详解 MCP 如何重塑 AI Agent 开发生态?
  • WEBUI插件和UE5通讯
  • 爬虫——playwright获取亚马逊数据
  • 2025年3月AI搜索发展动态与趋势分析:从技术革新到生态重构
  • 清洁机器人垃圾物识别与智能分类回收系统研究(大纲)
  • 【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring Boot 中的 RESTful API 设计:从上手到骨折
  • MyBatis 中 #{} 和 ${} 的区别详解