Web 项目 UI 自动化测试实战:从零搭建博客系统框架
基于 Python 和 Selenium 框架,演示如何从零搭建博客系统的 UI 自动化测试方案。涵盖环境配置、公共工具封装、核心模块(登录、列表、详情、编辑)用例开发、统一执行入口及测试报告生成。通过实战代码展示自动化测试全流程,帮助开发者实现回归测试自动化,提升测试效率与质量。

基于 Python 和 Selenium 框架,演示如何从零搭建博客系统的 UI 自动化测试方案。涵盖环境配置、公共工具封装、核心模块(登录、列表、详情、编辑)用例开发、统一执行入口及测试报告生成。通过实战代码展示自动化测试全流程,帮助开发者实现回归测试自动化,提升测试效率与质量。


在如今的软件开发流程中,测试不再是测试工程师的专属工作。尤其是对于 Web 项目开发,重复的手动测试不仅耗时耗力,还容易出现遗漏和误判。而自动化测试的出现,正是为了解决这个痛点 —— 它就像一个不知疲倦的测试助手,能自动执行预设用例、精准捕获异常、生成测试报告,让开发者把更多精力放在核心功能开发上。本文将以经典的博客系统为案例,手把手教你用 Python 搭建一套完整的 UI 自动化测试框架,从用例设计到脚本开发,再到测试报告落地,全程实战、代码可直接复用。
本次实战的被测对象是一个基于 Web 的博客系统(后端 C++ 开发),核心功能模块包括:登录模块、博主信息模块、博客列表模块、博客编辑模块、博客详情模块。系统支持用户登录后查看、编辑、提交博客,未登录用户访问受限功能时会触发登录弹窗提示。

验证博客系统核心功能的稳定性和正确性;实现关键流程的自动化执行,减少手动测试成本;快速定位迭代过程中引入的回归 bug;输出清晰、规范的测试报告,支撑项目上线决策。
自动化测试并非面面俱到,而是聚焦核心流程和高频场景。结合系统功能,我们设计了以下测试用例(覆盖正常场景与异常场景):

在开始编码前,我们需要先完成环境配置。请确保你的电脑已安装 Python 环境(3.8 及以上版本),然后按照以下步骤操作:
打开命令行终端,执行以下命令安装所需库:
# 安装 Selenium(UI 自动化核心库)
pip install selenium==4.10.0
# 安装 webdriver-manager(自动管理浏览器驱动)
pip install webdriver-manager==4.0.0
本文以 Chrome 浏览器为例(推荐版本 110+),无需手动下载 ChromeDriver:webdriver-manager 会自动检测浏览器版本并下载对应驱动,彻底解决驱动版本不匹配的问题。
如果需要使用 Firefox 或 Edge 浏览器,只需修改后续代码中的浏览器配置(下文会详细说明)。
一个清晰的目录结构是自动化框架可维护的关键。我们采用以下目录结构组织项目:
blog_auto_test/
├── common/ # 公共工具模块
│ └── Utils.py # 驱动管理、截图等公共功能
├── cases/ # 测试用例模块
│ ├── BlogLogin.py # 登录模块测试用例
│ ├── BlogList.py # 博客列表模块测试用例
│ ├── BlogEdit.py # 博客编辑模块测试用例
│ └── BlogDetail.py # 博客详情模块测试用例
├── images/ # 截图存储目录(自动生成)
│ └── 2024-05-20/ # 按日期分类的截图文件夹
├── reports/ # 测试报告目录
│ └── test_report.md # 测试报告文件
└── RunCases.py # 测试用例执行入口
在编写具体测试用例前,我们先封装公共工具类 —— 这能避免重复编码,让后续用例开发更高效。核心公共功能包括:驱动对象创建、自动截图、异常处理等。
import datetime
import os.path
import sys
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from selenium.common.exceptions import WebDriverException
class Driver:
"""驱动管理类:创建浏览器驱动、截图、关闭驱动等功能封装"""
driver = None # 类属性,全局共享驱动对象
def __init__(self):
"""初始化驱动对象,配置 Chrome 浏览器选项"""
try:
# 创建 Chrome 浏览器选项对象
options = webdriver.ChromeOptions()
# 可选配置:无头模式(无界面运行,适合服务器环境)
# options.add_argument('--headless=new')
# 可选配置:忽略证书错误
options.add_argument('--ignore-certificate-errors')
# 可选配置:禁用 GPU 加速(避免部分环境报错)
options.add_argument('--disable-gpu')
# 可选配置:设置窗口大小
options.add_argument('window-size=1920,1080')
# 自动安装匹配的 ChromeDriver 并创建驱动对象
self.driver = webdriver.Chrome(
service=Service(ChromeDriverManager().install()),
options=options
)
# 设置页面加载超时时间(10 秒)
self.driver.set_page_load_timeout(10)
# 设置隐式等待时间(5 秒,等待元素加载)
self.driver.implicitly_wait(5)
print(f"驱动初始化成功!ChromeDriver 版本:{self.driver.capabilities[][]}")
WebDriverException e:
()
Exception e:
()
():
:
dirname = datetime.datetime.now().strftime()
screenshot_dir =
os.path.exists(screenshot_dir):
os.makedirs(screenshot_dir)
()
case_name = sys._getframe().f_back.f_code.co_name
filename =
screenshot_path = os.path.join(screenshot_dir, filename)
.driver.save_screenshot(screenshot_path)
()
screenshot_path
Exception e:
()
():
.driver:
.driver.quit()
()
blog_driver = Driver()
驱动全局共享:通过类属性
driver和全局实例blog_driver,确保所有测试用例使用同一个浏览器实例,避免重复打开浏览器,提高执行效率; 异常处理:捕获WebDriverException等常见异常,并打印详细日志,方便问题定位; 灵活配置:预留了无头模式、窗口大小等可选配置,可根据实际测试环境调整; 截图优化:按日期分类存储截图,文件名包含用例名和时间戳,便于追溯测试场景。
接下来,我们按照测试规划,逐个模块编写测试用例。每个用例都遵循 前置条件→操作步骤→断言验证 的逻辑,确保测试结果的准确性。
登录模块是系统的入口,也是自动化测试的核心场景。我们需要覆盖正常登录和多种异常登录场景:
import time
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
from common.Utils import blog_driver
class BlogLogin:
"""登录模块测试用例"""
def __init__(self):
"""初始化:设置登录页面 URL,打开登录页"""
self.login_url = "http://192.168.47.135:8653/blog_system/blog_login.html"
self.driver = blog_driver.driver
self.driver.get(self.login_url)
print(f"打开登录页面:{self.login_url}")
def clear_input(self):
"""清空账号和密码输入框(复用方法)"""
username_input = self.driver.find_element(By.CSS_SELECTOR, "#username")
password_input = self.driver.find_element(By.CSS_SELECTOR, "#password")
username_input.clear()
password_input.clear()
print("清空账号密码输入框")
def login_suc_test(self, username="admin", password="123"):
"""正常登录测试用例"""
try:
print(f"\n===== 执行正常登录测试(账号:{username},密码:{password})=====")
self.clear_input()
self.driver.find_element(By.CSS_SELECTOR, "#username").send_keys(username)
.driver.find_element(By.CSS_SELECTOR, ).send_keys(password)
()
.driver.find_element(By.CSS_SELECTOR, ).click()
()
time.sleep()
:
avatar_element = .driver.find_element(By.CSS_SELECTOR, )
avatar_element.is_displayed()
()
blog_driver.get_screen_shot()
.driver.back()
time.sleep()
NoSuchElementException:
()
blog_driver.get_screen_shot()
AssertionError:
()
blog_driver.get_screen_shot()
Exception e:
()
blog_driver.get_screen_shot()
():
:
()
.clear_input()
.driver.find_element(By.CSS_SELECTOR, ).send_keys(username)
.driver.find_element(By.CSS_SELECTOR, ).send_keys(password)
()
.driver.find_element(By.CSS_SELECTOR, ).click()
()
time.sleep()
actual_msg = .driver.find_element(By.CSS_SELECTOR, ).text
()
()
expect_msg actual_msg,
()
blog_driver.get_screen_shot()
.driver.back()
time.sleep()
NoSuchElementException:
()
blog_driver.get_screen_shot()
AssertionError e:
()
blog_driver.get_screen_shot()
Exception e:
()
blog_driver.get_screen_shot()
():
()
.clear_input()
.driver.find_element(By.CSS_SELECTOR, ).send_keys()
()
.driver.find_element(By.CSS_SELECTOR, ).click()
time.sleep()
.driver.current_url == .login_url,
()
blog_driver.get_screen_shot()
():
()
.clear_input()
.driver.find_element(By.CSS_SELECTOR, ).send_keys()
()
.driver.find_element(By.CSS_SELECTOR, ).click()
time.sleep()
.driver.current_url == .login_url,
()
blog_driver.get_screen_shot()
__name__ == :
login_test = BlogLogin()
login_test.login_suc_test(, )
login_test.login_suc_test(, )
login_test.login_fail_test(, , )
login_test.login_empty_username_test()
login_test.login_empty_password_test()
blog_driver.quit_driver()
博客列表模块的核心测试点是 登录状态下正常访问 和 未登录状态下跳转登录页,同时需要验证博客数量和跳转功能:
import time
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
from common.Utils import blog_driver, Driver
from cases.BlogLogin import BlogLogin
class BlogList:
"""博客列表模块测试用例"""
def __init__(self):
self.list_url = "http://192.168.47.135:8653/blog_system/blog_list.html"
self.driver = blog_driver.driver
print(f"博客列表页 URL:{self.list_url}")
def list_login_status_test(self):
"""登录状态下访问博客列表页测试"""
try:
print(f"\n===== 执行登录状态下博客列表测试 =====")
login_test = BlogLogin()
login_test.login_suc_test("admin", "123")
self.driver.get(self.list_url)
print(f"已登录,访问列表页:{self.list_url}")
time.sleep(2)
avatar_element = self.driver.find_element(By.CSS_SELECTOR, "body > div.container > div.left > div > img")
assert avatar_element.is_displayed(), "博主头像未显示,登录状态可能失效"
print("断言通过:博主头像正常显示")
first_blog = self.driver.find_element(By.CSS_SELECTOR, "body > div.container > div.right > div:nth-child(1) > a")
first_blog.is_displayed(),
()
all_blogs = .driver.find_elements(By.CSS_SELECTOR, )
blog_count = (all_blogs)
()
blog_count > ,
()
first_blog.click()
time.sleep()
.driver.title == ,
()
blog_driver.get_screen_shot()
()
NoSuchElementException e:
()
blog_driver.get_screen_shot()
AssertionError e:
()
blog_driver.get_screen_shot()
Exception e:
()
blog_driver.get_screen_shot()
():
:
()
blog_driver.quit_driver()
new_driver = Driver()
.driver = new_driver.driver
.driver.get(.list_url)
()
time.sleep()
.driver.current_url == , \
()
new_driver.get_screen_shot()
new_driver.quit_driver()
()
AssertionError e:
()
new_driver.get_screen_shot()
Exception e:
()
new_driver.get_screen_shot()
__name__ == :
list_test = BlogList()
list_test.list_login_status_test()
list_test.list_unlogin_status_test()
博客详情模块依赖博客列表模块的跳转,核心测试点是页面元素完整性和未登录访问限制:
import time
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
from common.Utils import blog_driver, Driver
from cases.BlogLogin import BlogLogin
from cases.BlogList import BlogList
class BlogDetail:
"""博客详情模块测试用例"""
def __init__(self, blog_id=15):
self.detail_url = f"http://192.168.47.135:8653/blog_system/blog_detail.html?blogId={blog_id}"
self.driver = blog_driver.driver
self.blog_id = blog_id
print(f"博客详情页 URL(ID:{blog_id}):{self.detail_url}")
def detail_login_status_test(self):
"""登录状态下访问博客详情页测试"""
try:
print(f"\n===== 执行登录状态下博客详情测试(ID:{self.blog_id})=====")
login_test = BlogLogin()
login_test.login_suc_test("admin", "123")
list_test = BlogList()
list_test.driver.get(list_test.list_url)
time.sleep(2)
first_blog = list_test.driver.find_element(By.CSS_SELECTOR, "body > div.container > div.right > div:nth-child(1) > a")
first_blog.click()
time.sleep(2)
assert self.driver.title == "博客详情页",
()
blog_title = .driver.find_element(By.CSS_SELECTOR, )
blog_title.is_displayed(),
()
publish_date = .driver.find_element(By.CSS_SELECTOR, )
publish_date.is_displayed(),
()
blog_content = .driver.find_element(By.CSS_SELECTOR, )
blog_content.is_displayed(),
()
blog_driver.get_screen_shot()
()
NoSuchElementException e:
()
blog_driver.get_screen_shot()
AssertionError e:
()
blog_driver.get_screen_shot()
Exception e:
()
blog_driver.get_screen_shot()
():
:
()
blog_driver.quit_driver()
new_driver = Driver()
.driver = new_driver.driver
.driver.get(.detail_url)
()
time.sleep()
.driver.current_url == , \
()
new_driver.get_screen_shot()
new_driver.quit_driver()
()
AssertionError e:
()
new_driver.get_screen_shot()
Exception e:
()
new_driver.get_screen_shot()
__name__ == :
detail_test = BlogDetail(blog_id=)
detail_test.detail_login_status_test()
detail_test.detail_unlogin_status_test()
博客编辑模块是核心功能之一,需要覆盖正常提交和异常提交(无标题、无内容)场景:
import time
from datetime import datetime
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
from common.Utils import blog_driver, Driver
from cases.BlogLogin import BlogLogin
class BlogEdit:
"""博客编辑模块测试用例"""
def __init__(self):
self.edit_url = "http://192.168.47.135:8653/blog_system/blog_edit.html"
self.driver = blog_driver.driver
print(f"博客编辑页 URL:{self.edit_url}")
def edit_login_normal_submit_test(self):
"""登录状态下正常提交博客测试"""
try:
print(f"\n===== 执行登录状态下正常提交博客测试 =====")
login_test = BlogLogin()
login_test.login_suc_test("admin", "123")
self.driver.get(self.edit_url)
time.sleep(2)
print(f"已登录,访问编辑页:{self.edit_url}")
title_input = self.driver.find_element(By.CSS_SELECTOR, "#title")
content_input = self.driver.find_element(By.CSS_SELECTOR, "#content")
submit_btn = self.driver.find_element(By.CSS_SELECTOR, "#submit")
blog_title =
blog_content =
title_input.clear()
title_input.send_keys(blog_title)
content_input.clear()
content_input.send_keys(blog_content)
()
()
submit_btn.click()
time.sleep()
()
.driver.title == ,
()
all_blogs = .driver.find_elements(By.CSS_SELECTOR, )
blog_titles = [blog.text blog all_blogs]
blog_title blog_titles,
()
blog_driver.get_screen_shot()
()
NoSuchElementException e:
()
blog_driver.get_screen_shot()
AssertionError e:
()
blog_driver.get_screen_shot()
Exception e:
()
blog_driver.get_screen_shot()
():
:
()
login_test = BlogLogin()
login_test.login_suc_test(, )
.driver.get(.edit_url)
time.sleep()
content_input = .driver.find_element(By.CSS_SELECTOR, )
submit_btn = .driver.find_element(By.CSS_SELECTOR, )
blog_content =
content_input.clear()
content_input.send_keys(blog_content)
()
submit_btn.click()
time.sleep()
()
.driver.current_url == .edit_url,
()
:
error_msg = .driver.find_element(By.CSS_SELECTOR, ).text
error_msg,
()
NoSuchElementException:
()
blog_driver.get_screen_shot()
()
AssertionError e:
()
blog_driver.get_screen_shot()
Exception e:
()
blog_driver.get_screen_shot()
():
:
()
login_test = BlogLogin()
login_test.login_suc_test(, )
.driver.get(.edit_url)
time.sleep()
title_input = .driver.find_element(By.CSS_SELECTOR, )
submit_btn = .driver.find_element(By.CSS_SELECTOR, )
blog_title =
title_input.clear()
title_input.send_keys(blog_title)
()
submit_btn.click()
time.sleep()
()
.driver.current_url == .edit_url,
()
:
error_msg = .driver.find_element(By.CSS_SELECTOR, ).text
error_msg,
()
NoSuchElementException:
()
blog_driver.get_screen_shot()
()
AssertionError e:
()
blog_driver.get_screen_shot()
Exception e:
()
blog_driver.get_screen_shot()
():
:
()
blog_driver.quit_driver()
new_driver = Driver()
.driver = new_driver.driver
.driver.get(.edit_url)
time.sleep()
()
title_input = .driver.find_element(By.CSS_SELECTOR, )
content_input = .driver.find_element(By.CSS_SELECTOR, )
submit_btn = .driver.find_element(By.CSS_SELECTOR, )
title_input.send_keys()
content_input.send_keys()
()
submit_btn.click()
time.sleep()
()
.driver.current_url == , \
()
new_driver.get_screen_shot()
new_driver.quit_driver()
()
AssertionError e:
()
new_driver.get_screen_shot()
Exception e:
()
new_driver.get_screen_shot()
__name__ == :
edit_test = BlogEdit()
edit_test.edit_login_normal_submit_test()
edit_test.edit_login_no_title_submit_test()
edit_test.edit_login_no_content_submit_test()
edit_test.edit_unlogin_submit_test()
为了方便执行所有测试用例,我们创建一个统一的执行入口文件,按模块顺序执行测试:
import sys
import time
from common.Utils import blog_driver
from cases.BlogLogin import BlogLogin
from cases.BlogList import BlogList
from cases.BlogDetail import BlogDetail
from cases.BlogEdit import BlogEdit
def run_all_cases():
"""执行所有自动化测试用例"""
print("="*50)
print("开始执行博客系统自动化测试用例")
print(f"执行时间:{time.strftime('%Y-%m-%d %H:%M:%S')}")
print("="*50)
test_results = {
"passed": 0,
"failed": 0,
"total": 0
}
try:
print("\n" + "="*30)
print("开始执行登录模块测试")
print("="*30)
login_test = BlogLogin()
login_test.login_suc_test("admin", "123")
test_results["passed"] += 1
login_test.login_suc_test("lisi", "123")
test_results["passed"] += 1
login_test.login_fail_test(, , )
test_results[] +=
login_test.login_empty_username_test()
test_results[] +=
login_test.login_empty_password_test()
test_results[] +=
( + *)
()
(*)
list_test = BlogList()
list_test.list_login_status_test()
test_results[] +=
list_test.list_unlogin_status_test()
test_results[] +=
( + *)
()
(*)
detail_test = BlogDetail(blog_id=)
detail_test.detail_login_status_test()
test_results[] +=
detail_test.detail_unlogin_status_test()
test_results[] +=
( + *)
()
(*)
edit_test = BlogEdit()
edit_test.edit_login_normal_submit_test()
test_results[] +=
edit_test.edit_login_no_title_submit_test()
test_results[] +=
edit_test.edit_login_no_content_submit_test()
test_results[] +=
edit_test.edit_unlogin_submit_test()
test_results[] +=
Exception e:
()
test_results[] +=
:
test_results[] = test_results[] + test_results[]
blog_driver.quit_driver()
( + *)
()
(*)
()
()
()
pass_rate = (test_results[] / test_results[]) * test_results[] >
()
(*)
test_results[] > :
sys.exit()
:
sys.exit()
__name__ == :
run_all_cases()
测试执行完成后,需要生成一份规范的测试报告,用于向团队展示测试结果、进度和问题。以下为大家提供基于本次实战的测试报告模板(可根据实际项目调整):
| 项目名称 | 博客系统(C++ 后端 Web 项目) | 版本号 | V1.0 |
|---|---|---|---|
| 发布类型 | 分级发布 | 测试负责人 | 测试负责人 |
| 测试完成日期 | 2026-1-14 | 联系方式 | (根据实际填写) |
| 评审人 | 评审人 | 批准人 | 李产品 |
| 评审日期 | 2026-1-14 | 批准日期 | 2026-1-14 |
测试目标:验证博客系统核心功能(登录、列表、详情、编辑)的正确性和稳定性,实现关键流程自动化,减少手动测试成本,支撑项目上线; 测试任务:设计并执行 14 条 UI 自动化测试用例,覆盖正常场景与异常场景,生成测试报告并跟踪问题修复。
被测系统:博客系统(Web 端); 系统地址:http://xxxxxxxxxxxxxxxxxxxxxx; 代码包及文档:diff 链接(根据实际填写)、接口文档(根据实际填写)、《测试计划》; 依赖环境:Chrome 浏览器 110+、Python 3.8+、Selenium 4.10.0。
《博客系统需求文档》; 《博客系统技术设计文档》; 《博客系统 UI 设计图》。
| 模块 | 子模块 | 前端开发 | 后端开发 | 提测时间 | 测试负责人 | 工时 | 排期 | 进度 | 备注 |
|---|---|---|---|---|---|---|---|---|---|
| 登录模块 | 登录功能 | 前端开发 | 后端开发 | 2024-05-18 | 测试负责人 | 0.5d | 2026-1-10 | 测试完成 | 覆盖正常 / 异常登录 |
| 博客列表模块 | 列表展示、跳转 | 前端开发 | 后端开发 | 2024-05-18 | 测试负责人 | 0.5d | 2026-1-10 | 测试完成 | 登录 / 未登录状态 |
| 博客详情模块 | 详情展示 | 前端开发 | 后端开发 | 2024-05-18 | 测试负责人 | 0.5d | 2026-1-11 | 测试完成 | 登录 / 未登录状态 |
| 博客编辑模块 | 编辑、提交 | 前端开发 | 后端开发 | 2024-05-18 | 测试负责人 | 0.5d | 2026-1-11 | 测试完成 | 正常 / 异常提交 |
| 模块 | 用例总数 | 通过数 | 失败数 | 通过率 |
|---|---|---|---|---|
| 登录模块 | 5 | 5 | 0 | 100.00% |
| 博客列表模块 | 2 | 2 | 0 | 100.00% |
| 博客详情模块 | 2 | 2 | 0 | 100.00% |
| 博客编辑模块 | 5 | 5 | 0 | 100.00% |
| 总计 | 14 | 14 | 0 | 100.00% |
本次自动化测试未发现新增缺陷;历史缺陷修复验证:所有已提交的缺陷均已修复,且在本次自动化测试中无回归。
| 测试场景 | 截图路径 | 说明 |
|---|---|---|
| admin 账号正常登录成功 | images/2026-1-10/loginSucTest-20260110143025.png | 跳转至列表页,显示博主头像 |
| 密码错误异常登录 | images/2026-1-10/loginFailTest-20260110143210.png | 显示 "用户名或密码错误!" |
| 博客列表页正常展示 | images/2026-1-11/listLoginStatusTest-20260111143508.png | 博客数量大于 10 篇 |
| 编辑博客正常提交 | images/2026-1-11/editLoginNormalSubmitTest-20260111144015.png | 新增博客显示在列表页 |
博客系统核心功能(登录、列表、详情、编辑)的 UI 自动化测试已全部完成,14 条用例全部通过,通过率 100%;系统在测试场景下运行稳定,未出现功能异常、崩溃等问题;自动化测试框架运行正常,能够准确执行测试用例、捕获异常并生成截图,可支撑后续迭代的回归测试。
扩展用例覆盖范围:新增博客删除、修改密码、评论等功能的自动化用例; 集成 CI/CD 流程:将自动化测试脚本集成到 Jenkins 等工具,实现每次代码提交后自动执行测试; 优化框架稳定性:增加重试机制(如元素未找到时自动重试)、日志详细程度优化; 定期维护用例:当系统 UI 发生变更时,及时更新用例中的元素选择器,确保自动化用例的有效性。
通过本次博客系统的自动化测试实战,我们从 0 到 1 搭建了一套完整的 UI 自动化测试框架,覆盖了用例设计、脚本开发、执行入口、报告生成等全流程,并且实现了代码复用、异常处理、截图追溯等关键功能。自动化测试是一个实践出真知的领域,只有多动手、多踩坑,才能不断提升自己的技术水平。希望本文的实战案例能为你提供一些帮助。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online