尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
基于Selenium+Python unittest的CRM自动化测试框架实战
简介这份资源是一套基于Python Selenium与Unittest框架的CRM系统Web自动化测试实战源码面向正在学习自动化测试的初中级测试开发人员也适合需要搭建完整自动化测试项目的从业者参考。内容覆盖CRM系统业务场景下的自动化框架设计从Web元素定位、Selenium核心API到Unittest用例组织与断言方法再到测试报告生成与邮件自动发送完整串起自动化测试的各个关键环节可帮助读者快速建立从脚本编写到结果反馈的整链路认知。压缩包共254个文件以py脚本、pyc缓存、HTML报告、yaml配置、log日志等为主附带sample样例数据与zip压缩包另有大量pytest缓存与git仓库内部对象文件包体约24.19MB。过滤掉工具自动生成的缓存文件后核心源码规模可观适合边读边练。目前已有222人学习下载文件目录结构清晰便于按模块拆解学习。1. 为什么拿 CRM 系统练 Selenium 自动化真实业务比 demo 更锻炼人我见过不少教程拿登录页反复跑第一周有新鲜感第二周就开始觉得这不就是点两下按钮嘛。换成 CRM 系统之后有表单、有弹窗、有日期控件、有列表翻页、有角色权限selenium 自动化测试 python unittest 这套组合才算真正派上用场。这也是我把它拆成可复现源码包的原因你拿到的不是跑通就丢的 demo而是从目录结构、页面对象、测试用例到报告邮件一整条链路。CRM 业务够典型、流程够长适合练手也适合直接改造到自己公司的回归场景里。另外提醒一句有些下载站会把 unittest 错写成 unitest导入的时候一定用标准库 unittest否则 import 直接报错。2. unittestSelenium基础框架PO模式与全局配置怎么写2.1 目录结构设计为什么按 page/testcase/report 拆分先把三十个脚本平铺到一个文件夹里跑完第一轮你连找谁失败都费劲这是不少自动化项目一开始就会踩的乱摊子。真实 CRM 系统模块少说也有七八个用例量上一百之后平铺式管理基本等于给自己埋雷。我现在的拆分习惯是五个目录page 管元素定位和页面动作testcase 管业务和断言report 放执行产物data 放测试数据config 放环境参数。这样一个新人接手打开目录两分钟就能搞清楚该改哪里。framework/ ├── config/ │ └── config.ini # 环境地址、浏览器类型、账号信息 ├── data/ │ ├── login_data.json # 登录模块测试数据 │ └── customer_data.csv # 客户新增测试数据 ├── page/ │ ├── base_page.py # 公共页面对象封装查找、点击、输入 │ ├── login_page.py # 登录页面对象 │ ├── customer_page.py # 客户列表/新增页面对象 │ └── contract_page.py # 合同台账页面对象 ├── testcase/ │ ├── base_test.py # 用例基类统一启动和退出 │ ├── test_login.py # 登录用例 │ ├── test_customer.py # 客户管理用例 │ └── test_contract.py # 合同台账用例 ├── report/ # 生成的 HTML 报告输出目录 └── run_all.py # 用例加载、执行、生成报告、发邮件这个结构的价值不在目录本身而在依赖方向。testcase 只依赖 page 和 datapage 只依赖 config模块之间不互相引用。将来如果要把 unittest 换成 pytesttestcase 层重写断言风格page 和 data 原封不动可以复用如果要做多浏览器兼容只需在 config.ini 增加一个 browserfirefox 配置项驱动工厂多写一个分支就完事。配置文件走 ini 还是 yaml 其实都可以关键是不能把环境地址和账号写死在脚本里。原因很直接一套脚本往往要在本机、测试服务器、预发布环境各跑一遍地址不一样账号密码也分权限。写在 ini 里每次切换环境只需改一行不会为了找是哪个文件里的 IP翻半天代码。提示data 目录专门放测试数据不等于把业务步骤也拆进数据文件。CRM 里删除客户、退出登录这类收尾动作要写在用例里不要拆散到数据文件中。2.2 浏览器驱动初始化复用与独立会话的取舍初学者喜欢用 setUpClass 加 classmethod让整个测试类共用一个浏览器理由是启动快。我的经验是 CRM 这类业务系统页面的状态耦合度太高登录态残留、缓存覆盖、弹窗遮挡都很难在用例结束时清干净。共用浏览器省下的十几秒远不够用来排查那种换个用例执行顺序就变红的怪问题。所以默认策略是每个用例一个独立会话先保证稳定再谈效率。# driver.py from selenium import webdriver import configparser def create_driver(): conf configparser.ConfigParser() conf.read(config/config.ini, encodingutf-8) browser conf.get(env, browser, fallbackchrome) if browser firefox: options webdriver.FirefoxOptions() if conf.getboolean(env, headless, fallbackFalse): options.add_argument(-headless) driver webdriver.Firefox(optionsoptions) else: options webdriver.ChromeOptions() options.add_argument(--window-size1920,1080) if conf.getboolean(env, headless, fallbackFalse): options.add_argument(--headless) driver webdriver.Chrome(optionsoptions) return driver代码逻辑说明create_driver 从 config.ini 里读浏览器类型和 headless 开关决定启用哪个驱动对象。窗口尺寸固定成 1920*1080是因为很多 CRM 页面在窗口缩小时会把菜单折叠进汉堡按钮元素定位直接失败。参数说明headless 默认关本地调试不需要它CI 机器没有显示器的时候才打开。# testcase/base_test.py import unittest from driver import create_driver class BaseTest(unittest.TestCase): def setUp(self): self.driver create_driver() self.driver.get(http://localhost:8080/crm/) self.driver.maximize_window() def tearDown(self): if self.driver: self.driver.quit()代码逻辑说明setUp 在每个用例执行前都会新开一个浏览器并打开 CRM 首页tearDown 则无条件关闭会话。即使用例中途断言失败tearDown 依然会被 unittest 调用不会留下僵尸浏览器进程。2.3 页面对象把定位符集中管理不散落在用例里没有页面对象时用例里满屏都是 WebDriverWait 和 find_element一个操作重复十遍页面细节一改所有用例跟着改。把页面抽象成对象之后用例代码只跟动作打交道定位符只存在于 page 层。# page/base_page.py from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import Select class BasePage: def __init__(self, driver): self.driver driver def find_element(self, locator, timeout10): return WebDriverWait(self.driver, timeout).until( EC.presence_of_element_located(locator) ) def click(self, locator, timeout10): self.find_element(locator, timeout).click() def input_text(self, locator, text, timeout10): element self.find_element(locator, timeout) element.clear() element.send_keys(text) def select_by_visible_text(self, locator, text, timeout10): Select(self.find_element(locator, timeout)).select_by_visible_text(text) def get_text(self, locator, timeout10): return self.find_element(locator, timeout).text代码逻辑说明find_element 是用显式等待拿元素等不到就在超时后抛异常click、input_text 等动作都复用这一个查找入口。参数说明locator 是 (By.XPATH, ...) 这样的二元组timeout 默认 10 秒元素加载慢的页面可以单独把它调大不会影响其他操作。select_by_visible_text 解决的是 CRM 里大量下拉框的问题比如客户等级、合同状态这类原生 select 必须走 Select 封装。这里要提一个容易翻车的地方input_text 里的 clear() 和 send_keys() 顺序不能反。CRM 的客户名称、合同编号这些输入框有的带着默认提示文字有的残留上一次编辑的内容不先 clear 直接 send_keys新旧内容会拼在一起。金额字段尤其致命1000 会变成 10001000断言永远过不了。3. CRM核心流程用例实现登录、客户新增、合同台账的脚本拆解3.1 登录模块数据文件、断言点、失败信息登录是所有用例的前提也是被测系统最容易变化的一层。把登录用例单独拆开一方面验证认证逻辑本身另一方面也确保后面所有用例的 setUp 能稳定通过。CRM 系统的登录页通常有四个关键点用户名输入框、密码输入框、登录按钮、错误提示条。# page/login_page.py from page.base_page import BasePage from selenium.webdriver.common.by import By class LoginPage(BasePage): username_input (By.XPATH, //input[placeholder用户名]) password_input (By.XPATH, //input[placeholder密码]) login_btn (By.XPATH, //button[contains(text(), 登 录)]) error_msg (By.XPATH, //div[contains(class, login-error)]) def do_login(self, username, password): self.input_text(self.username_input, username) self.input_text(self.password_input, password) self.click(self.login_btn) def get_error(self): return self.get_text(self.error_msg) def is_login_success(self): return home in self.driver.current_url代码逻辑说明do_login 按先用户名、再密码、最后点按钮的顺序执行操作之间不带强制 sleep因为 input_text 内部已经做了显式等待。is_login_success 用 URL 判断跳转比去找首页某个欢迎语更稳定很多 CRM 首页元素是异步加载的URL 变化早于 DOM 渲染完成。登录用例的数据和断言我是这样设计的{ success: {username: admin, password: 123456}, wrong_password: {username: admin, password: 123123}, locked_user: {username: locked_user, password: 123456} }# testcase/test_login.py import json import unittest from testcase.base_test import BaseTest from page.login_page import LoginPage class TestLogin(BaseTest): classmethod def setUpClass(cls): with open(data/login_data.json, encodingutf-8) as f: cls.data json.load(f) def test_login_success(self): d self.data[success] page LoginPage(self.driver) page.do_login(d[username], d[password]) self.assertTrue(page.is_login_success()) def test_login_wrong_password(self): d self.data[wrong_password] page LoginPage(self.driver) page.do_login(d[username], d[password]) self.assertEqual(用户名或密码错误, page.get_error())代码逻辑说明setUpClass 只读一次 json 文件多个用例共享同一份加载结果减少重复 IO。test_login_success 断言的是跳转结果test_login_wrong_password 断言的是页面上的错误提示文本。参数说明json 里每个键对应一种测试场景新增锁定时长、验证码错误等场景只需往 json 加一段不需要新增用例代码。提醒一点错误提示的定位方式尽量用 class 关键词而不是完整固定文本比如 contains(class, login-error)。原因是不同环境下面该文本可能有语言包差异但 class 多半相对稳定。3.2 客户新增与列表查询表单填写、下拉选择、翻页等待客户模块是 CRM 里最重要的重复操作场景新增客户、填写等级、保存后回到列表、断言新记录出现。这个用例能够暴露出一类典型问题——保存操作之后页面要刷新如果立刻去列表里找刚新增的记录刷新没完成就会只看到旧数据。# page/customer_page.py from page.base_page import BasePage from selenium.webdriver.common.by import By class CustomerPage(BasePage): customer_menu (By.XPATH, //li[data-menucustomer]) add_btn (By.XPATH, //button[contains(text(), 新增客户)]) name_input (By.XPATH, //input[idcustomerName]) level_select (By.XPATH, //select[idcustomerLevel]) save_btn (By.XPATH, //button[contains(text(), 保 存)]) table_rows (By.XPATH, //table[idcustomerTable]/tbody/tr) def goto_customer_list(self): self.click(self.customer_menu) def add_customer(self, name, level): self.click(self.add_btn) self.input_text(self.name_input, name) self.select_by_visible_text(self.level_select, level) self.click(self.save_btn) def get_all_customer_names(self): rows self.driver.find_elements(*self.table_rows) return [row.text for row in rows]代码逻辑说明customer_menu 定位用的是># testcase/test_customer.py from testcase.base_test import BaseTest from page.login_page import LoginPage from page.customer_page import CustomerPage class TestCustomer(BaseTest): def setUp(self): super().setUp() LoginPage(self.driver).do_login(admin, 123456) def test_add_customer_success(self): name 测试客户A_20250220 page CustomerPage(self.driver) page.goto_customer_list() page.add_customer(name, 重要客户) page.goto_customer_list() self.assertIn(name, page.get_all_customer_names())代码逻辑说明setUp 里先做登录保证每个客户用例进来时都有有效会话。add_customer 完成后再次调 goto_customer_list是为了触发表格刷新然后 assertIn 去查新增记录是否出现在列表里。参数说明客户名称带上日期后缀是为了避免和上一轮跑出的历史数据重名也让报告里的人一看就知道是哪次回归新增的。注意不要在用例里固定 sleep 3 秒等表格刷新。可以改用某个预期行文本出现的显式等待再进一步做列表查询如果你手里的 CRM 前端组件是异步表格建议在 BasePage 里预留一个 wait_row_count 方法等待表格行数从 N 变成 N1。3.3 合同台账日期控件、金额边界、保存后的状态流转合同台账比客户新增更麻烦一点日期控件通常是自研弹层金额字段可能有千分位格式化保存后状态从草稿跳到待审批。这三个点每个都能让脚本写完后翻车。# page/contract_page.py from page.base_page import BasePage from selenium.webdriver.common.by import By class ContractPage(BasePage): contract_name (By.XPATH, //input[idcontractName]) sign_date_input (By.XPATH, //input[idsignDate]) amount_input (By.XPATH, //input[idamount]) save_btn (By.XPATH, //button[contains(text(), 保存)]) def add_contract(self, name, sign_date, amount): self.input_text(self.contract_name, name) self.click(self.sign_date_input) self.click((By.XPATH, f//td[data-date{sign_date}])) self.input_text(self.amount_input, str(amount)) self.click(self.save_btn) return self.get_text((By.XPATH, //div[contains(class, contract-state)]))代码逻辑说明日期输入框再点击后会弹出日历面板面板里每天都是一个 td用>def test_add_contract_amount_rounded(self): page ContractPage(self.driver) state page.add_contract(采购合同20250220, 2025-02-20, 1000) self.assertIn(待审批, state)代码逻辑说明test_add_contract_amount_rounded 验证的是保存后进入待审批状态这正是合同台账里最有业务价值的流转断言。参数说明如果断言失败第一步先看保存时页面上是否出现了金额校验提示第二步再确认日期是否选到了正确月份这两类问题在合同模块里占八成的失败原因。4. 测试报告与邮件发送HTML报告和SMTP配置的完整链路4.1 HTMLTestRunner 报告生成、分类、保留现场unittest 自带的 TextTestRunner 输出到控制台跑完就没了CRM 系统回归要给别人看需要一份能保存下来的报告。HTMLTestRunner 是单文件工具将 unittest 的 result 渲染成带统计和截图的 HTML 页面。虽然它很多年没有更新但依然是最简单、不需要额外安装的方案。# run_all.py import unittest from HTMLTestRunner import HTMLTestRunner from datetime import datetime if __name__ __main__: suite unittest.defaultTestLoader.discover(testcase, patterntest_*.py) report_path freport/{datetime.now().strftime(%Y%m%d_%H%M%S)}_report.html with open(report_path, wb) as f: runner HTMLTestRunner( streamf, titleCRM系统自动化回归报告, description浏览器Chrome 执行环境测试环境 ) runner.run(suite)代码逻辑说明defaultTestLoader.discover 会自动发现 testcase 目录里所有 test_ 开头的 py 文件不需要手动一个一个加用例。报告文件名带上时间戳是为了保留多次执行的历史现场避免每次执行都覆盖上一份。参数说明title 和 description 会显示在报告页头建议把浏览器版本和执行环境写进去隔一个月再翻报告时能想起来这份是在哪台机器跑的。4.2 SMTP 邮件发送HTML 附件与登录鉴权报告生成后如果不发出去测试执行的价值就少了一大半。这个项目里的最终流程是跑完所有用例、生成 HTML 报告、再通过 SMTP 发给相关人。邮件部分我用 Python 标准库 smtplib 和 email 实现这两兄弟不需要额外装包。# send_report.py import smtplib from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.header import Header from datetime import datetime def send_report(report_path): with open(report_path, rb) as f: content f.read() msg MIMEMultipart() msg[From] senderexample.com msg[To] leaderexample.com msg[Subject] Header(fCRM自动化测试报告 {datetime.now():%Y-%m-%d}, utf-8) msg.attach(MIMEText(content, html, utf-8)) smtp smtplib.SMTP_SSL(smtp.example.com, 465) smtp.login(senderexample.com, your_auth_code) smtp.send_message(msg) smtp.quit()代码逻辑说明MIMEMultipart 允许同一邮件里附带 HTML 正文和后续要加的附件SMTP_SSL 直接走 465 端口加密通道现在大多数邮箱都要求 SSL 登录。参数说明登录密码一般不是邮箱登录密码而是服务商提供的授权码如果你所在网络禁止 465可以把 587 配合 starttls 作为备选。4.3 批量回归与定时执行接入 CI 的入口脚本当用例数量超过十几个以后手动在 IDE 里点 run 就不现实了。这个项目最后 run_all.py 的调用方式设计成能被命令行或定时任务直接拉起。结合 cron 或 Windows 任务计划每天夜里跑一遍回归第二天早上打开邮箱看报告这是最省心的工作方式。# 先在源码包根目录安装依赖再执行主脚本 pip install -r requirements.txt python run_all.py代码逻辑说明pip install 把 selenium、webdriver-manager 这类依赖装齐python run_all.py 完成加载用例、执行、生成报告、发送邮件四条动作。参数说明如果你把 run_all.py 放到 CI 平台上跑建议在脚本前面加一个环境变量判断比如只允许 TEST_ENVdev 时发送邮件避免开发环境的数据不小心发给所有人。邮件发送失败时不要直接让整个任务 fail 掉。常见做法是把发邮件放到 report 生成之后的独立函数里发信失败打印日志但不影响报告文件本身报告留在服务器上人还能去手动拿。把测试执行和结果通知解耦是这一层设计的原则。5. 自动化测试避坑指南定位失效、等待超时与数据污染的排查记录5.1 找不到元素多半不是路径写错而是 iframe 没切换现象脚本跑 CRM 里的客户列表click 新增客户按钮时报 NoSuchElementException但手动在浏览器里操作按钮明明就在那里。原因不少 CRM 的后台页面把内容区域放进 iframe新增按钮在 iframe 里而 selenium 默认只在主文档里找元素。定位符写得再精确也够不到 iframe 内部的元素。解决先通过 name 或 id 切入 iframe操作完成后再切回主文档。常见做法是给 BasePage 加一个 switch_iframe 方法调用方传入 iframe 的定位符用完立刻切回 default_content。我在这个源码包里就是这么处理的新增客户和合同台账两个页面都要走这一步。5.2 显式等待设了 10 秒还是没等到数据加载现象登录成功之后直接去点客户菜单偶尔能过偶尔报元素不可点击加了 WebDriverWait 以后依然隔三差五失败。原因页面元素确实出现了但背后的数据接口还没返回表格区域是一片空白。Selenium 的可见性等待只判断 DOM 上元素的 CSS 状态不判断业务数据是否渲染完成。解决在 BasePage 增加一个 wait_text_appear 方法等待表格中某个关键文本出现再去执行下一步。比如客户列表用例先等客户名称表头出现再点新增按钮。这里还有一个习惯不要用 time.sleep 去兜底sleep 只会把问题从随机失败变成每次都多等三秒。5.3 数据没清理干净用例之间互相污染现象单独跑新增客户用例全绿把登录用例和客户用例连起来跑新增后断言通过但列表里多了一条历史遗留客户数量断言永远对不上。原因上一轮测试数据残留在数据库里没有在用例开头或结尾做清理。CRM 的客户列表又是分页的因为数据多了新加的记录被挤到了第二页第一次用例只能看到第一页。解决新增客户的用例必须在执行前先删除同名记录或者客户名称加唯一时间戳并在断言时跳过历史数据。我在代码里用了测试客户A_日期时间这种带时间戳的名字断言改成 assertIn 而不是 assertEquals。从那以后这类换顺序就红的问题基本没有再现过。5.4 报告文件被写入占用第二次运行报错现象第二次运行 run_all.py 时报告文件写入失败报 PermissionError。原因上一次运行生成的 HTML 报告被浏览器或者编辑器打开占用了Windows 下文件被占用时无法用同名文件覆盖写入。解决报告文件名加时间戳生成新文件而不是覆盖旧文件历史报告就永远不会冲突。如果公司有报告保留策略再加一个定时清理脚本只保留最近 30 天的报告文件。这个改动成本极低收益却很高至少不用每次跑之前先手工去看哪个文件被谁占了。5.5 SMTP 连接失败不是账号问题先确认端口策略现象邮件发送逻辑在本地可以跑通放到某台测试服务器上就报 timeout。原因企业办公网络或云环境常常把 25 端口、465 端口拦掉一部分只放开常用端口。解决先确认服务器出网策略再选择对应端口一般先用 465 SSL 连一次连不上再用 587 加 starttls 试试。发送失败时捕获异常并记录日志不要让整个回归任务因为这个报错直接崩溃。这种换个端口就能用的坑排查顺序一定是从网络端口开始而不是先怀疑授权码写错。6. 把脚本变工程数据驱动与失败重跑技巧6.1 用 JSON 数据驱动扩用例不用改代码接新需求时最麻烦的事是加一条用例要复制一整段代码。把数据从用例里拿出来后新增场景只要往 JSON 里加一条记录。比如客户等级今天只测重要客户明天加一个普通客户改 JSON 就行。{ customer_levels: [ {name: 测试客户A_{ts}, level: 重要客户}, {name: 测试客户B_{ts}, level: 普通客户} ] }# 在test_customer.py中做数据驱动读取 for item in CustomerData[customer_levels]: name item[name].replace({ts}, str(int(time.time()))) page.add_customer(name, item[level]) self.assertIn(name, page.get_all_customer_names())代码逻辑说明列表里的每一条数据都当一次独立场景执行名字里的 {ts} 在执行时替换成时间戳避免不同轮次的数据重复。6.2 失败用例自动重跑但别把重跑当成遮羞布CRM 回归最容易遇到偶发失败比如弹窗动画还没结束点快了。我会给断言加一层轻量重试第二次还失败才上报。实现上写一个装饰器包住测试函数失败后先截图再重跑一次。# 简洁版用例失败后自动重跑一次 def rerun(func): def wrapper(self): try: func(self) except Exception: self.driver.save_screenshot(report/failure.png) func(self) return wrapper代码逻辑说明第一次失败先截图留证据然后重置状态再跑第二次还失败就把异常按原样抛出给报告统计。参数说明重跑次数设成 1 就够重跑次数太多会把报告里真实失败刷成绿色领导看到绿就以为版本没问题这是很危险的习惯。从那以后我每个版本上线前跑全量回归都只看去掉重跑后仍失败的用例这份列表那才是真正要修的。这个源码包从目录到邮件都串好了希望帮到你。本文还有配套的精品资源点击获取
RELATED

相关推荐

网站内容监控实战:轮询策略、指纹比对与告警通知

网站内容监控实战:轮询策略、指纹比对与告警通知

简介:SiteMonitor是一款面向企业及个人的多目标网站资讯监控工具,主要用于同时跟踪多个网站的页面更新与关键字变化,帮助用户在信息竞争环境中及时捕获重要动态。该资源为RAR压缩包,共3个文件,包含可直接运行的exe安装…

📅 2026/10/13 16:10:39
给知识工作流配一套轻量插件:采集、写作、复习自动化

给知识工作流配一套轻量插件:采集、写作、复习自动化

1. 为什么我给自己的知识工作流配了一套插件先说个很多脑力劳动者都有的体验:一天打开十几个窗口,浏览器里躺着二十多个标签页,笔记软件里存了几百条“以后再整理”的碎片,任务清单里堆着上周就该完成的事项。真正坐下来写东西、做…

📅 2026/10/13 16:05:36
石化智能工厂落地实践:边缘计算、数据治理与实施路线全解析

石化智能工厂落地实践:边缘计算、数据治理与实施路线全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/13 16:05:36
MORE NEWS

更多资讯

📰

GOCI2波段手册全解读:从波段表到月球辐射定标与在轨监测

简介:GOCI2说明手册聚焦第二代静止轨道海洋水色成像仪波段设计,面向海洋遥感科研人员、卫星数据处理工程师及相关专业学生。系统梳理了传感器波段设置、辐射性能指标与硬件组成,助读者理解各通道中心波长、带宽、标称辐射亮度、最大海洋辐射亮…

📰

OpenClaw本地接入QQ Bot全流程:从零配置到消息互通

我自己在本地折腾 OpenClaw 接 QQ Bot 的时候,说实话踩了不少坑。网上能搜到的资料大多是“配置成功”的结果展示,真正把从零到打通这条链路讲透的很少。这篇博文就围绕 OpenClaw 本地配置 QQ Bot 的完整流程展开,把每一步背后的逻辑、容易翻…

📰

JavaEE酒店管理系统源码解析:从房态订单联动到毕设部署避坑

简介:这份资源是面向计算机专业毕业生与JavaEE初学者的小型酒店管理系统完整项目,基于经典SSH框架组合开发,适合用作毕业设计参考或企业级Web开发入门实践。项目模拟真实酒店业务流程,涵盖用户管理、房间状态与价格设置、预订入住…

📰

React Native鸿蒙跨平台 Badge 徽章组件动态样式封装实践

做移动端基础组件的时候,最容易被人忽略的就是 Badge 这种“小东西”。红点、数字角标、提示标签,几乎每个 App 都躲不开它,但真要动手封装一个经得起多端验证的徽章组件,才发现里面全是细节。这篇文章就聊聊我用 React Native 在…

📰

仓库架构风格:数据一致性与组件解耦的架构实践

我见过太多团队在架构选型时只盯着微服务和消息队列,一提仓库架构风格就觉得是"老古董"或者"太简单"。但说实话,仓库架构风格是软件系统里最常被低估、却又最能扛住业务演进的一种组织方式。它把组件之间的交互从"互相调用&quo…

📰

Python机器学习预测分析核心算法源码拆解:弹性网、随机森林与GBM实战

简介:这份资源面向具备一定Python基础、希望系统掌握预测建模的学习者与数据从业者,围绕Python核心预测算法展开,从线性回归、逻辑回归、决策树与随机森林,到支持向量机、神经网络、时间序列分析、梯度提升机、K近邻、朴素贝叶斯及…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬