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

BeautifulSoup 踩坑笔记:SVG 显示异常的真正原因

  • “这图是不是糊了?”
  • 以为是样式缺了?试试手动复制
  • 差异在哪?想用对比工具一探究竟……
  • 简单到不能再简单的代码,有问题吗?
  • 最后的真相:viewBox vs viewbox,preserveAspectRatio vs preserveaspectratio
  • 别急,问题其实出在 parser 上
  • 正确做法:用 xml parser!

我有几个网页需要处理,想从中提取出 SVG 图单独保存。操作也很简单,网页保存为 .html 后,用 Python + BeautifulSoup 提取 <svg> 标签,保存为 .svg 文件。

一切看起来都很顺利,代码跑起来没报错,文件也生成了。但打开 SVG 一看,总感觉哪儿不太对劲

“这图是不是糊了?”

那是一种怎么形容呢……“有点糊”的感觉。轮廓线条模糊了,缩放好像不太灵,反正就不像原网页中那么清晰了。

svg compare

图中左侧是 BeautifulSoup 提取的结果,右侧是网页中原始的显示效果,看着还是非常明显。

以为是样式缺了?试试手动复制

起初我以为可能是 SVG 引用了网页外部的样式表,所以通过代码提取出来后,没法正确渲染。

那我就直接从 HTML 源码里把 <svg> 标签复制出来,保存成 .svg 文件。结果一打开:显示完全正常!

这说明:SVG 并没有依赖外部样式,问题出在提取方式上。

差异在哪?想用对比工具一探究竟……

想到这里,我打算用 Beyond Compare 这种工具来看看手动提取和代码提取的 SVG 文件有啥不同。

结果发现:属性的顺序被 BeautifulSoup 改了个遍,标签缩进也被重新排过了。

这下比对也不好看了,完全对不上。搞得我直接放弃用工具对比,只能开始回头怀疑自己的代码:

简单到不能再简单的代码,有问题吗?

下面是我最开始的代码,提取 SVG 并保存:

from bs4 import BeautifulSoup

with open('42e1.html', 'r', encoding='utf-8') as file:
    html_content = file.read()

soup = BeautifulSoup(html_content)
svg = soup.find('svg')

if svg:
    svg_string = svg.prettify()
    with open('extracted_42e1.svg', 'w', encoding='utf-8') as f:
        f.write(svg_string)

代码非常简单,难道是 .prettify() 的锅?它会不会在格式化的时候,修改了什么属性?

我试了几个 formatter 参数,也没解决问题,结果还是老样子。

最后的真相:viewBox vs viewbox,preserveAspectRatio vs preserveaspectratio

没辙了,我只能回到老老实实肉眼对比。

我皱着眉头盯着 Beyond Compare,看着它标红的地方……一开始我还没看出来。

结果,居然只是属性名变成了小写:

  • viewBoxviewbox
  • preserveAspectRatiopreserveaspectratio

嘴里飙出了一句国粹之后,我第一反应是直接暴力补丁:

svg_content = svg_content.replace("viewbox", "viewBox")
svg_content = svg_content.replace("preserveaspectratio", "preserveAspectRatio")

还一度想给 BeautifulSoup 提个 issue:你咋连大小写都搞不清?

别急,问题其实出在 parser 上

冷静之后,我想:不应该啊,BeautifulSoup 这么成熟的库,不可能犯这种低级错误。

于是去查了查文档——果然问题不在 BeautifulSoup 本身,而在于我用的解析器。

默认的 html.parser 是按照 HTML 规范设计的,它会把标签名和属性名全部转换为小写,这是符合 HTML 标准的。

但问题来了,SVG 是 XML 子集,属性名是区分大小写的

换句话说,我在解析 XML 的时候用了 HTML 的工具,所以出问题了

正确做法:用 xml parser!

所以解决方法其实很简单,只需要:

soup = BeautifulSoup(html_content, "xml")

这样,viewBoxpreserveAspectRatio 就能原封不动地保留下来,SVG 也就恢复正常了。结局也算是皆大欢喜了。

补一句

  • 如果专门要处理 SVG、MathML、RSS 等 XML 内容,请用 xmllxml-xml

  • 如果要处理 HTML 页面,继续用 html.parser 是对的,因为使用 xml 解析可能会造成 html 部分的混乱。

以此留念,拒绝踩坑。

相关文章:

  • unity曲线射击
  • Vuex 源码
  • 13. Git 远程仓库配置
  • rocketmq 5 TopicMessageType validate failed
  • 反垄断合规时代来临:企业如何抢占合规管理先机?
  • 谷歌最近放出大招——推出全新“Agent Development Kit(简称ADK)
  • YOLO学习笔记 | 一文详解YOLOv11核心创新与实践方法
  • 管理、切换多个 hosts工具之SwitchHosts
  • csdn的文章一键迁移搬家到博客园
  • centos-LLM-生物信息-BioGPT-使用1
  • VLC快速制作rtsp流媒体服务器
  • 数字人:打破次元壁,从娱乐舞台迈向教育新课堂(4/10)
  • Python实现批量插入PostgreSQL数据库的脚本分享
  • JAVA入门-Collection单列集合体系
  • Java学习手册:面向对象编程核心概念
  • TypeScript对不同种变量怎么声明不同类型
  • mongodb--用户管理
  • swift菜鸟教程13(函数)
  • Wincc脚本全部不运行
  • MySQL死锁问题深度剖析与Java解决方案
  • 福州网站建设费用/正规网络推广服务
  • 网站一般用什么语言写/seo网络营销推广公司深圳
  • 电视直播网站建设/长沙互联网推广公司
  • 如何做阿语垂直网站/静态网站开发
  • 成都十大监理公司排名/网站seo
  • 苏州pc网站开发/网站运营及推广方案