尧图网站建设 尧图网络
  • 首页
  • 关于我们
  • 服务项目
  • 案例展示
  • 建站流程
  • 资讯中心
  • 联系我们
首页/资讯中心/详情

Selenium自动化测试框架实战:从脚本到CI/CD集成

Selenium自动化测试框架实战:从脚本到CI/CD集成
📅 发布时间:2026/6/22 19:32:57

1. 项目概述:从单点脚本到体系化质量保障

最近在做一个语音识别模型(SenseVoice-small)的WebUI自动化测试项目,核心目标是把零散的Selenium脚本整合起来,实现批量执行,并最终集成到CI/CD流水线里,让测试成为每次代码提交后自动触发的环节。这听起来像是测试工程师的常规操作,但实际操作中,从写一个能跑的脚本,到构建一套稳定、可维护、能集成进流水线的自动化体系,中间隔着不少“坑”。很多团队可能停留在“脚本能跑通”的阶段,一旦要批量运行、要持续集成,各种环境问题、稳定性问题、报告管理问题就全冒出来了。这个项目就是要把这些“坑”填平,构建一个从本地开发到云端部署都顺畅的自动化测试闭环。

SenseVoice-small本身是一个轻量级的语音识别模型,它的WebUI可能提供了上传音频、选择模型、查看识别结果、调整参数等功能。我们的自动化测试就是要模拟真实用户,去操作这些界面元素,验证功能是否正常、结果是否准确。而“批量测试+CI/CD集成”意味着我们不再满足于手动点几下,而是要追求效率、覆盖率和反馈速度。这非常适合敏捷开发团队,或者任何希望提升前端或Web应用质量保障水平的开发者。无论你是测试开发、后端开发兼管前端质量,还是DevOps工程师,这套思路都能直接拿来参考。

2. 核心思路与架构设计:为什么是Selenium+CI/CD?

在技术选型上,我们选择了Selenium WebDriver作为核心的UI自动化工具,并通过Jenkins(或其他CI/CD工具如GitLab CI、GitHub Actions)来搭建流水线。这个组合背后有清晰的逻辑。

为什么是Selenium?首先,它成熟、稳定、社区庞大,几乎支持所有主流浏览器(Chrome, Firefox, Edge等)。对于WebUI测试,浏览器兼容性是个绕不开的话题,Selenium提供了统一的WebDriver API来操作不同浏览器,这比绑定在某一个浏览器内核上的工具(如早期的一些录制工具)要灵活得多。其次,它支持多种编程语言(Python, Java, JavaScript等),我们的项目用Python来写,语法简洁,生态丰富(有Pytest这样的测试框架完美搭配),学习成本和开发效率都很好。最后,Selenium的定位策略(如ID, XPath, CSS Selector)非常强大,能够应对绝大多数复杂的Web页面元素定位需求。

为什么需要CI/CD集成?自动化脚本如果只躺在工程师的本地机器上,其价值就大打折扣。CI/CD(持续集成/持续部署)的核心思想是频繁地、自动化地构建、测试和部署软件。将UI自动化测试集成到CI/CD流水线中,可以实现:

  1. 即时反馈:每次开发人员提交代码(Push)或合并请求(Merge Request)时,自动触发测试套件执行。任何因代码变更导致的界面功能回归,能在几分钟内被发现并报告,而不是等到测试阶段甚至上线后。
  2. 环境一致性:流水线通常在干净的、预先配置好的代理机(Agent)或容器中运行测试,避免了“在我机器上是好的”这类环境问题。
  3. 测试资产与流程标准化:测试脚本、依赖库、浏览器驱动版本等都通过代码库和流水线配置文件管理,确保了团队内任何成员都能以相同的方式复现和执行测试。

我们的架构设计可以概括为:“脚本仓库 + 调度执行器 + 报告中心”。

  • 脚本仓库:使用Git管理所有的Selenium测试脚本(基于Pytest组织)、页面对象模型(Page Object Model, POM)类、测试数据等。
  • 调度执行器:CI/CD服务器(如Jenkins)。它监听代码库变更,拉取代码,在一个准备好的测试环境(可能是有图形界面的Linux服务器或通过Xvfb实现无头模式)中,执行测试命令(如pytest)。
  • 报告中心:测试执行后,生成格式化的测试报告(如Allure报告、HTML报告),并归档或通过邮件、即时通讯工具通知相关人员。

2.1 关键挑战与应对策略

在架构设计阶段,就必须预见并解决几个核心挑战:

  1. 浏览器驱动管理:Selenium需要通过浏览器驱动(如ChromeDriver)与真实浏览器通信。驱动版本必须与浏览器版本严格匹配。在CI环境中,如何确保每次都能获取到正确版本的驱动?
    • 策略:使用像webdriver-manager这样的Python库。它可以在运行时自动下载、匹配和管理所需版本的驱动,极大简化了环境配置。在流水线中,只需确保安装了此库即可。
  2. 测试稳定性(Flaky Tests):UI自动化最头疼的就是不稳定。页面加载慢、元素未及时出现、异步操作都会导致脚本失败。
    • 策略:采用“显式等待”(Explicit Wait)替代“隐式等待”(Implicit Wait)或硬性等待(time.sleep)。显式等待会针对某个特定条件(如元素可点击、元素可见)进行等待,超时后才报错。这比固定等待时间更智能、更稳定。配合Pytest的重试机制(pytest-rerunfailures插件),可以对偶发失败进行自动重试。
  3. 测试数据与环境隔离:批量测试可能需要不同的测试数据,并且测试不应该对生产数据造成污染。
    • 策略:使用独立的测试数据库或每次测试前重置测试数据。测试数据可以放在JSON、YAML文件或独立的测试数据管理模块中。通过Pytest的fixture机制,可以方便地在测试开始前准备数据,测试结束后清理现场。
  4. 并行执行与效率:当测试用例成百上千时,串行执行耗时太长。
    • 策略:利用Pytest的分布式执行插件(如pytest-xdist)在CI的多个节点或同一节点的多个进程中并行运行测试。需要确保测试用例之间没有依赖,并且能够处理并行访问可能带来的资源冲突(如使用独立的用户会话)。

3. 实战:构建基于Pytest和Page Object的Selenium测试框架

光有思路不够,我们直接进入实战环节。我将以一个假设的SenseVoice-small WebUI为例,展示如何搭建一个结构清晰、易于维护的测试框架。

3.1 项目目录结构

一个良好的目录结构是维护性的基础。建议如下:

sensevoice_ui_auto/ ├── conftest.py # Pytest全局配置、Fixture定义 ├── requirements.txt # Python依赖包列表 ├── run_tests.py # 本地执行测试的入口脚本(可选) ├── config/ │ ├── __init__.py │ ├── settings.py # 全局配置(URL、超时时间、浏览器类型等) │ └── test_data.yaml # 测试数据 ├── pages/ # 页面对象模型(POM) │ ├── __init__.py │ ├── base_page.py # 所有页面的基类 │ ├── login_page.py # 登录页面 │ └── main_page.py # 主功能页面(上传、识别等) ├── tests/ # 测试用例 │ ├── __init__.py │ ├── test_login.py # 登录相关测试 │ └── test_recognition.py # 语音识别功能测试 ├── utils/ # 工具函数 │ ├── __init__.py │ ├── driver_manager.py # 浏览器驱动管理 │ └── report_helper.py # 报告生成辅助 └── logs/ # 日志目录(.gitignore) └── reports/ # 测试报告目录(.gitignore)

3.2 核心组件详解

1. 配置管理 (config/settings.py)这里集中管理所有可配置项,避免硬编码。

# config/settings.py import os from selenium.webdriver.common.by import By class Settings: # 应用配置 BASE_URL = os.getenv("TEST_BASE_URL", "http://localhost:8080") # 从环境变量读取,便于CI配置 DEFAULT_TIMEOUT = 10 # 默认显式等待超时时间(秒) # 浏览器配置 BROWSER = os.getenv("TEST_BROWSER", "chrome").lower() # chrome, firefox, edge HEADLESS = os.getenv("HEADLESS", "true").lower() == "true" # 是否无头模式,CI环境通常为true # 元素定位方式映射(可选,方便统一管理) LOCATOR_MAPPING = { "id": By.ID, "xpath": By.XPATH, "css": By.CSS_SELECTOR, "name": By.NAME, "class": By.CLASS_NAME, "link_text": By.LINK_TEXT, "partial_link_text": By.PARTIAL_LINK_TEXT, "tag": By.TAG_NAME } # 测试数据文件路径 TEST_DATA_PATH = os.path.join(os.path.dirname(__file__), "test_data.yaml")

2. 页面对象模型 (pages/)POM模式是UI自动化的最佳实践之一。它将页面元素定位和操作封装成类,使测试脚本更清晰,元素变更只需修改一处。

# pages/base_page.py from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from config.settings import Settings class BasePage: def __init__(self, driver): self.driver = driver self.wait = WebDriverWait(driver, Settings.DEFAULT_TIMEOUT) self.base_url = Settings.BASE_URL def open(self, url=""): """打开页面""" self.driver.get(self.base_url + url) def find_element(self, locator_type, locator_value): """查找单个元素(使用显式等待)""" by = Settings.LOCATOR_MAPPING.get(locator_type, locator_type) # 支持字符串或By对象 return self.wait.until(EC.presence_of_element_located((by, locator_value))) def find_element_clickable(self, locator_type, locator_value): """查找可点击元素""" by = Settings.LOCATOR_MAPPING.get(locator_type, locator_type) return self.wait.until(EC.element_to_be_clickable((by, locator_value))) # 可以封装更多通用操作,如截图、滚动等
# pages/main_page.py from pages.base_page import BasePage from selenium.webdriver.common.by import By class MainPage(BasePage): # 元素定位器(关键!) UPLOAD_INPUT = (By.ID, "audio-upload-input") # 上传文件输入框 MODEL_SELECT_DROPDOWN = (By.CSS_SELECTOR, ".model-select .ant-select-selector") MODEL_OPTION = (By.XPATH, "//div[contains(@class, 'ant-select-item-option') and text()='SenseVoice-small']") START_RECOGNITION_BTN = (By.XPATH, "//button[span[text()='开始识别']]") RESULT_TEXT_AREA = (By.ID, "recognition-result-text") LOADING_SPINNER = (By.CLASS_NAME, "ant-spin-dot-spin") def upload_audio_file(self, file_path): """上传音频文件""" upload_elem = self.find_element(*self.UPLOAD_INPUT) # 注意:对于input[type='file'],直接send_keys文件路径即可 upload_elem.send_keys(file_path) return self def select_model(self, model_name="SenseVoice-small"): """选择识别模型""" self.find_element_clickable(*self.MODEL_SELECT_DROPDOWN).click() # 等待选项出现并点击 option_locator = (self.MODEL_OPTION[0], self.MODEL_OPTION[1].replace('SenseVoice-small', model_name)) self.find_element_clickable(*option_locator).click() return self def click_start_recognition(self): """点击开始识别按钮""" self.find_element_clickable(*self.START_RECOGNITION_BTN).click() # 等待加载完成 self.wait.until(EC.invisibility_of_element_located(self.LOADING_SPINNER)) return self def get_recognition_result(self): """获取识别结果文本""" result_elem = self.find_element(*self.RESULT_TEXT_AREA) return result_elem.text

实操心得:元素定位这是UI自动化最核心也最易变的部分。优先使用ID,因为它是唯一的。其次是CSS Selector,性能好且可读性不错。XPath功能强大但性能稍差,且容易因页面结构微调而失效,谨慎使用。对于动态生成ID或Class的现代前端框架(如React, Vue),可以请前端开发同学为关键测试元素添加固定的># tests/test_recognition.py import pytest import os from pages.login_page import LoginPage from pages.main_page import MainPage from config.settings import Settings class TestRecognition: """语音识别功能测试集""" @pytest.fixture(autouse=True) def setup(self, driver, login): # 使用conftest中定义的driver和login fixture """每个测试用例前的准备工作""" self.main_page = MainPage(driver) # 假设login fixture已经让我们处于登录状态并跳转到主页面 # 如果需要,可以在这里额外导航到特定页面 # self.main_page.open("/main") def test_basic_audio_recognition(self, test_audio_file): """测试基础音频识别功能""" # 1. 上传测试音频 self.main_page.upload_audio_file(test_audio_file) # 2. 选择模型(可选,如果默认就是SenseVoice-small) self.main_page.select_model("SenseVoice-small") # 3. 开始识别 self.main_page.click_start_recognition() # 4. 断言识别结果 result = self.main_page.get_recognition_result() assert result is not None and len(result.strip()) > 0, "识别结果不应为空" # 更复杂的断言:可以对比预期文本(如果已知) # expected_text = "你好,世界" # assert expected_text in result @pytest.mark.parametrize("audio_file, expected_keyword", [ ("test_audio_1.wav", "北京"), ("test_audio_2.mp3", "上海"), ("test_audio_empty.wav", ""), # 测试空音频或无效音频 ]) def test_recognition_with_different_audio(self, audio_file, expected_keyword, audio_file_resolver): """参数化测试:使用不同的音频文件""" full_path = audio_file_resolver(audio_file) # 一个fixture,用于解析文件路径 self.main_page.upload_audio_file(full_path) self.main_page.click_start_recognition() result = self.main_page.get_recognition_result() if expected_keyword: assert expected_keyword in result, f"识别结果中应包含关键词'{expected_keyword}'" else: assert result == "" or "错误" in result or "失败" in result, "无效音频应处理失败"

4. 核心Fixture与驱动管理 (conftest.py)这是Pytest的“魔法”所在,用于设置和清理测试环境。

# conftest.py import pytest from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.firefox.options import Options as FirefoxOptions from webdriver_manager.chrome import ChromeDriverManager from webdriver_manager.firefox import GeckoDriverManager from webdriver_manager.microsoft import EdgeChromiumDriverManager from config.settings import Settings import logging def setup_driver(browser_name, headless): """根据配置创建并返回WebDriver实例""" if browser_name == "chrome": options = Options() if headless: options.add_argument("--headless=new") # Chrome较新版本的无头模式 options.add_argument("--no-sandbox") # CI环境常见参数 options.add_argument("--disable-dev-shm-usage") # 解决共享内存问题 options.add_argument("--disable-gpu") # 可选,某些环境需要 options.add_argument("--window-size=1920,1080") driver = webdriver.Chrome(service=webdriver.ChromeService(ChromeDriverManager().install()), options=options) elif browser_name == "firefox": options = FirefoxOptions() if headless: options.add_argument("--headless") driver = webdriver.Firefox(service=webdriver.FirefoxService(GeckoDriverManager().install()), options=options) elif browser_name == "edge": # Edge类似,使用EdgeChromiumDriverManager pass else: raise ValueError(f"不支持的浏览器: {browser_name}") driver.implicitly_wait(0) # 禁用隐式等待,强制使用显式等待 return driver @pytest.fixture(scope="session") def driver(): """会话级别的driver fixture,所有测试用例共享一个浏览器实例(提高速度)""" logging.info(f"启动浏览器: {Settings.BROWSER}, 无头模式: {Settings.HEADLESS}") _driver = setup_driver(Settings.BROWSER, Settings.HEADLESS) yield _driver # 测试会话结束后清理 logging.info("关闭浏览器") _driver.quit() @pytest.fixture def login(driver): """登录fixture,使测试用例处于已登录状态""" login_page = LoginPage(driver) login_page.open() login_page.login("test_user", "test_password") # 使用测试账号 # 验证登录成功,可以跳转到主页或等待某个登录后元素出现 # 返回主页对象或True yield # 如果需要,可以在这里登出(但通常测试环境无需每次登出) @pytest.fixture def test_audio_file(): """提供测试音频文件路径""" import os file_path = os.path.join(os.path.dirname(__file__), "test_data", "sample.wav") if not os.path.exists(file_path): pytest.skip(f"测试音频文件不存在: {file_path}") return file_path @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): """Hook函数,用于在测试失败时自动截图""" outcome = yield report = outcome.get_result() if report.when == "call" and report.failed: # 获取driver fixture for fixture_name in item.fixturenames: if "driver" in fixture_name: driver = item.funcargs[fixture_name] break else: return # 截图并保存 screenshot_dir = "reports/screenshots" os.makedirs(screenshot_dir, exist_ok=True) screenshot_path = os.path.join(screenshot_dir, f"{item.name}_{report.when}.png") driver.save_screenshot(screenshot_path) report.extra = [pytest_html.extras.image(screenshot_path, 'Failure Screenshot')] # 如果使用pytest-html logging.error(f"测试失败,截图已保存至: {screenshot_path}")

3.3 本地执行与报告生成

在本地开发调试时,你可以这样运行测试:

  1. 安装依赖:pip install -r requirements.txt(requirements.txt包含:selenium>=4.0, pytest, pytest-html, allure-pytest, webdriver-manager, PyYAML等)
  2. 运行测试:
    • 运行所有测试:pytest -v
    • 运行特定标记的测试:pytest -m “smoke”(需要先在测试用例上用@pytest.mark.smoke装饰)
    • 生成HTML报告:pytest —html=reports/report.html —self-contained-html
    • 生成Allure报告(更强大):pytest —alluredir=reports/allure-results,然后allure serve reports/allure-results查看。

4. 集成到CI/CD流水线:以Jenkins为例

本地框架稳定后,就可以将其推送到Git仓库,并配置CI/CD流水线了。这里以最经典的Jenkins为例。

4.1 创建Jenkins Pipeline项目

  1. 在Jenkins中新建一个“流水线”(Pipeline)项目。
  2. 在“流水线”配置部分,选择“Pipeline script from SCM”,并配置你的Git仓库地址和凭据。
  3. 指定脚本路径,通常为项目根目录下的Jenkinsfile。

4.2 编写Jenkinsfile

Jenkinsfile是流水线的蓝图,使用Groovy语法。它定义了构建、测试、部署的各个阶段。

// Jenkinsfile pipeline { agent { docker { image ‘python:3.10-slim’ // 使用Python官方镜像作为构建环境 args ‘-v /dev/shm:/dev/shm’ // 解决Chrome无头模式可能的内存问题 } } environment { // 定义环境变量,会覆盖代码中settings.py的默认值 TEST_BASE_URL = ‘http://your-test-env-sensevoice.com’ HEADLESS = ‘true’ TEST_BROWSER = ‘chrome’ // 如果需要Allure报告 ALLURE_RESULTS = ‘reports/allure-results’ } stages { stage(‘Checkout’) { steps { checkout scm // 拉取代码 } } stage(‘Install Dependencies’) { steps { sh ‘pip install -r requirements.txt’ // 如果需要,可以在这里安装系统依赖,如Chrome sh ‘apt-get update && apt-get install -y wget gnupg unzip’ sh ‘wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -’ sh ‘echo “deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main” >> /etc/apt/sources.list.d/google.list’ sh ‘apt-get update && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf —no-install-recommends’ } } stage(‘Run UI Tests’) { steps { script { // 并行运行不同测试集(可选) parallel( “Smoke Tests”: { sh ‘pytest tests/ -m smoke —alluredir=${ALLURE_RESULTS}’ }, “Regression Tests”: { sh ‘pytest tests/ -m “not smoke” —alluredir=${ALLURE_RESULTS}’ } ) } } post { always { // 无论成功失败,都归档测试结果和截图 archiveArtifacts artifacts: ‘reports/**, logs/**’, allowEmptyArchive: true // 如果使用了pytest-html publishHTML(target: [ reportName: ‘Pytest HTML Report’, reportDir: ‘reports’, reportFiles: ‘report.html’, keepAll: true ]) } } } stage(‘Generate Allure Report’) { steps { script { // 安装Allure命令行工具并生成报告 sh ‘curl -o allure-2.13.8.tgz -sL https://github.com/allure-framework/allure2/releases/download/2.13.8/allure-2.13.8.tgz’ sh ‘tar -zxvf allure-2.13.8.tgz -C /opt/’ sh ‘/opt/allure-2.13.8/bin/allure generate ${ALLURE_RESULTS} -o reports/allure-report —clean’ } } post { always { // 发布Allure报告 allure([ reportBuildPolicy: ‘ALWAYS’, results: [[path: ‘${ALLURE_RESULTS}’]], reportPath: ‘reports/allure-report’ ]) } } } } post { always { // 清理工作,例如发送通知 echo ‘Pipeline finished.’ // 可以根据构建状态发送邮件或Slack通知 // emailext subject: “构建结果: ${currentBuild.fullDisplayName}”, // body: “${currentBuild.result}: Job ${env.JOB_NAME} build ${env.BUILD_NUMBER}\n更多细节: ${env.BUILD_URL}”, // to: ‘team@example.com’ } failure { echo ‘Pipeline failed. Check the logs and reports.’ } success { echo ‘Pipeline succeeded!’ } } }

4.3 关键配置与优化点

  1. 使用Docker Agent:如上例所示,使用Docker镜像能保证每次构建环境绝对干净、一致。镜像中预装了Python和必要的系统库。
  2. 安装浏览器:在Docker容器中,需要安装浏览器本身(如Chrome)和字体,以确保页面渲染正常。webdriver-manager只管理驱动,不管理浏览器本体。
  3. 并行执行:利用Jenkins Pipeline的parallel步骤,可以同时运行多组测试,大幅缩短反馈时间。前提是测试用例设计良好,没有相互依赖。
  4. 报告集成:将Allure或HTML报告发布到Jenkins,并提供历史趋势图,是质量可视化的重要一环。
  5. 失败重试与不稳定测试处理:可以在pytest命令中加入—reruns 2来对失败用例自动重试2次,减少偶发性失败的影响。对于长期不稳定的测试(Flaky Tests),应该及时排查原因并修复,或将其标记为不稳定测试单独处理。

5. 常见问题排查与实战技巧

在实际落地过程中,你肯定会遇到各种问题。这里记录一些典型的“坑”和解决方法。

5.1 元素定位失败

这是最常见的问题。

  • 现象:NoSuchElementException,ElementNotInteractableException。
  • 排查:
    1. 确认页面已加载:在操作前,使用显式等待等待某个“锚点”元素出现(如页面标题、某个固定区域)。
    2. 检查定位器:使用浏览器的开发者工具(F12)的Console,输入$$(“你的CSS选择器”)或$x(“你的XPath”)来验证定位器是否能找到元素。
    3. 是否存在iframe:如果元素在iframe内,必须先使用driver.switch_to.frame(frame_element)切换到对应的iframe中。
    4. 是否为动态元素:现代前端框架(React, Vue, Angular)会生成动态ID或Class。优先使用>import allure class MainPage(BasePage): @allure.step(“上传音频文件: {file_path}”) def upload_audio_file(self, file_path): # ... 实现代码
    5. 自动附加截图和日志:像之前conftest.py中的Hook一样,在测试失败时自动截图。也可以配置日志系统,将Selenium和应用的日志输出到文件,并附加到报告中。

5.5 维护成本随产品迭代变高

  • 应对策略:
    1. 坚持Page Object Model (POM):这是降低维护成本最有效的方法。所有元素定位器和页面操作都封装在Page类中,前端页面变更时,通常只需修改对应的Page类。
    2. 使用组件化思维:对于Header、Sidebar、Modal等通用组件,可以抽象出独立的Component类,在多个Page中复用。
    3. 定期重构和评审:随着功能增加,定期回顾测试代码结构,合并重复逻辑,抽象通用操作。
    4. 与开发团队协作:推动开发同学为关键UI元素添加稳定的测试属性(如>

相关新闻

  • Python 3数据类型全景解析:从内置类型到类型提示实战
  • 抖音视频怎么无水印保存?2026最新年抖音无水印保存视频最新方法全测 - 爱上科技热点
  • 深入解析NXP LS1046A SEC硬件安全协处理器作业终止状态与错误码

最新新闻

  • 武汉离婚律师推荐排行榜TOP8:覆盖70%高净值人群婚变痛点,专业婚姻家事律师团队护航您的权益 - 资讯速览
  • MC56F8013无传感器BLDC电机控制:参数调优与FreeMASTER实战指南
  • 唐山正宗炭火烧烤怎么烤才好吃?20年老店主理人干货分享 - 资讯速览
  • Java中String与XML Document互转的生产级实践指南
  • 东莞智能家居推荐排行:2026消费者口碑实力榜单,全屋智能方案这样选不踩坑 - 资讯快报
  • 智能合约安全自动化审计:从静态分析到模糊测试的工程实践

日新闻

  • 2026速览惠州叛逆青少年学校前十大排名名单出炉 - 武汉中职最新信息发布
  • 2026上饶白蚁消杀哪家好?15年本土2大权威白蚁防治公司推荐(金盾虫控/青蚁卫士) - 我叫一
  • 天龙八部单机版终极数据管理工具:5个技巧快速掌握游戏数据编辑

周新闻

  • Visual C++运行库修复终极指南:5分钟快速解决Windows软件启动错误
  • 手把手教你构建统计局地区经济数据爬虫:从环境搭建到数据持久化全指南
  • 2026多Agent深度解析:用AI团队替代单一模型,四种架构实战落地

月新闻

  • 【总结】入门篇:50句话让你记住架构核心概念
  • WeChatMsg技术方案解析:实现Mac微信数据自主管理的完整解决方案
  • WeChatMsg:革新性微信数据备份方案,打造你的专属数字记忆库

关于尧图

  • 公司简介
  • 团队介绍
  • 企业文化
  • 荣誉资质

服务项目

  • 定制开发
  • 电商建站
  • UI 设计
  • 运维服务

快速链接

  • 案例展示
  • 建站流程
  • 常见问题
  • 资讯中心

联系方式

  • 📍北京市朝阳区互联网产业园 A 座 10 层
  • 📞400-888-8888
  • ✉️contact@rkmt.cn
  • 🕐周一至周日 9:00-21:00

© 2024 北京尧图网络科技有限公司 版权所有 | 京 ICP 备 XXXXXXXX 号