当前位置:首页>python>用 JustHTML 在 Python 中重获对 HTML 的完全掌控

用 JustHTML 在 Python 中重获对 HTML 的完全掌控

  • 2026-09-02 18:56:18
用 JustHTML 在 Python 中重获对 HTML 的完全掌控

一、JustHTML 是什么?—— 一次“氛围工程”的完美实践

JustHTML 由瑞典开发者 Emil Stenström 创建,它是一个用纯 Python 编写的 HTML5 解析库,其核心代码仅有约 3,000 行。它最大的特点是 “零依赖”——无需编译 C 扩展,无需安装任何系统库,可以无缝运行在 PyPy、Pyodide 等任何 Python 环境中。

JustHTML 源自 Mozilla Servo 浏览器引擎的 Rust 解析器 html5ever,经过完全重写为 Python 代码。它 100% 通过了由浏览器厂商维护的官方 html5lib-tests 测试套件(超过 9,200 个测试用例)。这意味着,它的解析结果与主流浏览器高度一致,能够完美处理各种“非标准”的 HTML 输入。

请在微信客户端打开

著名开发者 Simon Willison 将 JustHTML 的开发过程称为 “氛围工程”(Vibe Engineering) 的典范——Emil 在数月的业余时间中,利用 GitHub Copilot 等 AI 编码助手,完成了一个完整、健壮的 HTML5 解析器。随后,Simon 仅用 4.5 小时就利用 AI 工具将其完整移植到了 JavaScript,可见其设计的清晰与高效。

二、安装与基础解析:开箱即用

2.1 安装

JustHTML 的安装极其简单,只需一行命令:

pip install justhtml

2.2 基础解析示例

JustHTML 最基本的功能是解析 HTML 字符串并生成 DOM 树。通过 .to_html() 方法即可将其转换回字符串。

from justhtml import JustHTML# 1. 解析一个完整的 HTML 片段html_snippet = '<p>Hello, <b>world</b>!</p>'doc = JustHTML(html_snippet, fragment=True)print(doc.to_html())# 输出: <p>Hello, <b>world</b>!</p># 2. 解析不完整/错误的标签 (JustHTML 会像浏览器一样自动修复)# 例如,缺少闭合标签的 <i>malformed_html = '<p><b>Hi<i>there</b>!'doc_fixed = JustHTML(malformed_html, fragment=True)print(doc_fixed.to_html())# 输出: <p><b>Hi<i>there</i></b><i>!</i></p>

注意 fragment=True 参数:它告诉解析器输入是 HTML 片段而非完整文档,因此不会自动添加 <html> 和 <body> 标签,这在处理用户输入时非常有用。

三、安全清洗:默认安全的 HTML 处理

JustHTML 内置了类似 Bleach 的白名单清洗功能。默认情况下,它会自动移除 <script> 等潜在危险的标签和属性,从源头防止 XSS 攻击。

from justhtml import JustHTML# 默认的安全清洗 (移除了 <script> 和危险的 href)dangerous_html = '''<p>Hello<script>alert(1)</script><ahref="javascript:alert(1)">bad</a><ahref="https://example.com">ok</a></p>'''safe_doc = JustHTML(dangerous_html, fragment=True)print(safe_doc.to_html())# 输出: <p>Hello<a>bad</a><ahref="https://example.com">ok</a></p>

3.1 自定义清洗规则

如果你需要更精细的控制,可以通过 Sanitizer 类自定义白名单规则:

from justhtml import JustHTML, Sanitizercustom_sanitizer = Sanitizer()custom_sanitizer.allow_tag("b")custom_sanitizer.allow_tag("i")custom_sanitizer.allow_attr("class")  # 允许 class 属性html = '<pclass="intro">Hello <b>world</b>!</p>'doc = JustHTML(html, fragment=True, sanitizer=custom_sanitizer)print(doc.to_html())# 输出: <pclass="intro">Hello <b>world</b>!</p>

3.2 禁用清洗

如果你信任输入的 HTML 并且不需要安全清洗,可以通过 sanitize=False 禁用:

doc = JustHTML(trusted_html, fragment=True, sanitize=False)

四、CSS 选择器查询:类 jQuery 的查找体验

JustHTML 提供了 query() 和 query_one() 两个方法,让你可以使用标准的 CSS 选择器来快速定位元素。这比传统的 DOM 遍历要高效得多。

from justhtml import JustHTMLhtml_content = """<main>  <article class="post">    <h2>文章标题</h2>    <p>这是一段 <em>重要的</em> 内容。</p>    <p class="summary">这是文章摘要。</p>  </article>  <div class="sidebar">    <p>边栏内容</p>  </div></main>"""# 解析文档doc = JustHTML(html_content, fragment=True)# 查询所有段落all_paragraphs = doc.query("p")print(f"找到 {len(all_paragraphs)} 个段落。")  # 输出: 找到 3 个段落。# 查询类为 "summary" 的段落summary_paragraph = doc.query_one("p.summary")print(f"摘要内容: {summary_paragraph.to_html()}")# 输出: 摘要内容: <p class="summary">这是文章摘要。</p># 使用复杂的选择器: 查找 <article> 内部的所有 <p> 元素article_paragraphs = doc.query("article p")for p in article_paragraphs:    print(p.to_html())# 输出:# <p>这是一段 <em>重要的</em> 内容。</p># <p class="summary">这是文章摘要。</p>

4.1 支持的选择器语法

JustHTML 支持丰富的 CSS 选择器语法,包括:

类型选择器: p

类选择器: .highlight

ID 选择器: #main

属性选择器: [href], [href="value"]

后代组合器: div p

子元素组合器: div > p

相邻兄弟组合器: h1 + p

伪类: :first-child, :last-child, :nth-child(n), :contains("text")

五、DOM 转换:链式处理节点

JustHTML 允许你在解析后对 DOM 进行一系列链式修改。这在处理用户生成的内容或对现有 HTML 进行微调时非常有用。

from justhtml import JustHTML, Unwrap, Linkify, SetAttrs, Drophtml_content = '''<p>Visit example.com for more info. <span class="highlight">Important!</span><span class="remove-me">Spam content here.</span></p>'''# 应用多个转换:# 1. Unwrap("span.highlight"): 移除 <span> 标签,但保留其内部文本 ("Important!")# 2. Drop("span.remove-me"): 完全删除指定元素及其内容# 3. Linkify(): 自动将文本中的 URL ("example.com") 转换为可点击的 <a> 标签# 4. SetAttrs("a", rel="nofollow"): 为所有 <a> 标签添加 rel="nofollow" 属性doc_transformed = JustHTML(    html_content,    fragment=True,    sanitize=False,  # 信任输入内容,关闭默认清洗    transforms=[        Unwrap("span.highlight"),        Drop("span.remove-me"),        Linkify(),        SetAttrs("a", rel="nofollow")    ])print(doc_transformed.to_html())# 输出: <p>Visit <a href="http://example.com" rel="nofollow">example.com</a> for more info. Important!</p>

五、从零构建 HTML:编程式生成

如果你需要动态生成 HTML 结构,JustHTML 同样提供了强大的支持。你可以使用 element 函数以编程方式创建元素,这比拼接字符串要安全、清晰得多。

from justhtml import JustHTMLfrom justhtml.builder import element# 构建一个简单的文章结构article_tree = element(    "article",     {"class": "blog-post"},  # 属性字典    element("h2", "我的博客文章"),    element("p", "这是文章的第一段。"),    element("div", {"class": "meta"}, "发布于 2025-12-14"),    element("a", {"href": "/more"}, "阅读更多..."))# 将构建好的树交给 JustHTML 进行标准化处理doc = JustHTML(article_tree, fragment=True, sanitize=False)print(doc.to_html(pretty=True))# 输出:# <article class="blog-post">#   <h2>我的博客文章</h2>#   <p>这是文章的第一段。</p>#   <div class="meta">发布于 2025-12-14</div>#   <a href="/more">阅读更多...</a># </article>

七、实用技巧与最佳实践

7.1 与 BeautifulSoup 集成

JustHTML 可以与 BeautifulSoup 无缝集成。通过实现一个自定义的 JustHTMLTreeBuilder,你可以使用 BeautifulSoup 熟悉的 API(如 find_all())的同时,享受 JustHTML 标准合规的 HTML5 解析能力。

# 概念性示例(需要实现自定义 TreeBuilder)# from bs4 import BeautifulSoup# from justhtml_tree_builder import JustHTMLTreeBuilder# soup = BeautifulSoup(html, "justhtml")

7.2 性能优化建议

批量处理:如果需要解析大量 HTML 片段,使用 fragment=True 可以避免生成不必要的 <html> 和 <body> 标签,减少内存开销。

合理使用清洗:如果输入的 HTML 完全可信,通过 sanitize=False 禁用清洗可以略微提升性能。

使用转换器:尽量使用内置的转换器(如 Drop、Unwrap)进行 DOM 操作,而非手动遍历节点,它们的实现已经过充分优化。

7.3 处理深度嵌套的 HTML

需要注意的是,由于 Python 递归深度的限制(默认 1000),JustHTML 在解析极端深度嵌套的 HTML(如嵌套 1000 层以上的 <div>)时可能会触发 RecursionError。这是 Python 语言本身的限制,而非 JustHTML 的缺陷。如果你的应用需要处理此类输入,可以考虑:

import syssys.setrecursionlimit(5000)  # 提高递归深度限制

或者在应用层面预先检测并拒绝深度异常的输入。

八、JustHTML 的工作流程

以下流程图清晰地展示了 JustHTML 处理 HTML 时的典型流程,帮助你理解各个功能模块是如何协同工作的:

九、总结与展望

JustHTML 不仅仅是一个解析器,它是一个集解析、清洗、查询、转换和构建于一体的瑞士军刀,专为追求简洁、可靠和高效的 Python 开发者设计。

核心优势回顾:

纯 Python,零依赖:无 C 扩展,无系统依赖,可在任何 Python 环境运行

浏览器级正确性:100% 通过 html5lib-tests 测试套件

默认安全:内置白名单清洗,从源头防止 XSS 攻击

CSS 选择器:熟悉的 jQuery 式语法,快速定位元素

链式转换:内置多种 DOM 转换器,可组合使用

代码精简:约 3,000 行核心代码,易于理解和调试

无论你是需要处理不可靠的网络数据、清洗用户提交的富文本,还是需要动态生成 HTML,JustHTML 都能为你提供一个优雅且强大的解决方案。它的纯 Python 特性也使其成为在 Jupyter Notebook、云函数或 Pyodide 等受限环境中的理想选择。

推荐阅读:

JustHTML 官方文档

JustHTML GitHub 仓库

Simon Willison 对 JustHTML 的深度分析

在线试用 JustHTML 的 Playground

编辑:余文彬
审校:余雨馨

最新文章

随机文章