3 个不稳定版本
0.2.1 | 2022年2月26日 |
---|---|
0.2.0 | 2022年2月25日 |
0.1.0 | 2022年2月25日 |
#1405 in 解析器实现
475KB
262 代码行
webarchive
webarchive 是 Rust 工具,用于处理由 Safari 2 或更高版本在 macOS 上,Safari 4 或更高版本在 Windows 上,或 Safari 13 或更高版本在 iOS 和 iPadOS 上生成的苹果 Web Archive 文件格式。
为什么是 Web Archive?
Web Archive 文件自 2005 年以来一直存在,是一种将整个网页及其所有相关资源作为单个文件保存的方法,该文件可以保存到磁盘上,无论服务器状态如何,都可以进行审查或共享。
虽然 Web Archive 在苹果平台之外没有得到很好的支持,并且在 iOS 中直到 2019 年的 iOS 13 才得到支持,但 Web Archive 是为数不多的为用户设计,只需打开一个页面即可期望它像原始页面一样工作的格式之一。其中最接近的是 MHTML,在 Microsoft Internet Explorer 的旧版本中得到支持,并且与 Web Archive 有相似的方法,代表整个网页。
针对专业或半专业归档工作设计的替代方案,如 WARC,则代表整个浏览会话及其相关子资源,但需要专门的软件来查看,并且没有“主要”页面或资源的概念。相比之下,Web Archives 在普通网络浏览器中打开,并且不需要用户知道要选择哪个 URL。
好吧,那么目标是什么?
我希望这是一个用于读取、创建和转换 Web Archive 文件的舒适 API,并扩展包含的命令行工具,以允许在常见格式和 Web Archive 之间进行双向转换。
使用方法
命令行使用
提供了一个命令行工具,可以通过运行以下命令安装:
cargo install webarchive
此工具可以提取或检查 webarchive 文件的内容。
使用 inspect
列出内容
$ webarchive inspect fixtures/psxdatacenter.webarchive
WebArchive of "http://psxdatacenter.com/ntsc-j_list.html": 0 subresource(s)
WebArchive of "http://psxdatacenter.com/banner.html": 2 subresource(s)
- "http://psxdatacenter.com/images/texgrey.jpg"
- "http://psxdatacenter.com/images/logo.jpg"
WebArchive of "http://psxdatacenter.com/nav.html": 16 subresource(s)
- "http://psxdatacenter.com/images/texgrey.jpg"
- "http://psxdatacenter.com/buttons/news1.gif"
- "http://psxdatacenter.com/buttons/inf1.gif"
- "http://psxdatacenter.com/buttons/emul1.gif"
...
或使用 extract
将其提取到磁盘
$ webarchive extract fixtures/psxdatacenter.webarchive
Saving main resource...
Writing file "fixtures/psxdatacenter.com/ntsc-j_list.html"...
Saving subframe archives...
Saving main resource...
Writing file "fixtures/psxdatacenter.com/banner.html"...
Saving subresources...
Writing file "fixtures/psxdatacenter.com/images/texgrey.jpg"...
Writing file "fixtures/psxdatacenter.com/images/logo.jpg"...
...
读取 webarchive
use webarchive::WebArchive;
let archive: WebArchive = webarchive::from_file("fixtures/psxdatacenter.webarchive")?;
/// main_resource is the resource which is opened by default
assert_eq!(
archive.main_resource.url,
"http://psxdatacenter.com/ntsc-j_list.html"
);
assert_eq!(archive.main_resource.mime_type, "text/html");
assert_eq!(
archive.main_resource.text_encoding_name,
Some("UTF-8".to_string())
);
assert_eq!(archive.main_resource.data.len(), 2171);
assert!(archive.subresources.is_none());
/// subframe_archives contains additional WebArchives for frames
assert!(archive.subframe_archives.is_some());
let subframe_archives = archive.subframe_archives.unwrap();
assert_eq!(subframe_archives.len(), 4);
assert_eq!(
subframe_archives[0].main_resource.url,
"http://psxdatacenter.com/banner.html"
);
assert_eq!(subframe_archives[0].main_resource.mime_type, "text/html");
assert_eq!(
subframe_archives[0].main_resource.text_encoding_name,
Some("UTF-8".to_string())
);
assert_eq!(subframe_archives[0].main_resource.data.len(), 782);
/// subresources are the files referenced by a given frame
assert!(subframe_archives[0].subresources.is_some());
let subresources = subframe_archives[0].subresources.as_ref().unwrap();
assert_eq!(subresources.len(), 2);
assert_eq!(
subresources[0].url,
"http://psxdatacenter.com/images/texgrey.jpg"
);
assert_eq!(subresources[0].mime_type, "image/jpeg");
assert!(subresources[0].text_encoding_name.is_none());
assert_eq!(subresources[0].data.len(), 107128);
创建 webarchive
use webarchive::{WebArchive, WebResource};
let resource = WebResource {
url: "about:hello".to_string(),
data: "hello world".as_bytes().to_vec(),
mime_type: "text/plain".to_string(),
text_encoding_name: Some("utf-8".to_string()),
frame_name: None,
response: None,
};
let archive = WebArchive {
main_resource: resource,
subresources: None,
subframe_archives: None,
};
let mut buf: Vec<u8> = Vec::new();
webarchive::to_writer_xml(&mut buf, &archive)?;
assert_eq!(
String::from_utf8(buf)?,
r#"<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>WebMainResource</key>
<dict>
<key>WebResourceData</key>
<data>
aGVsbG8gd29ybGQ=
</data>
<key>WebResourceURL</key>
<string>about:hello</string>
<key>WebResourceMIMEType</key>
<string>text/plain</string>
<key>WebResourceTextEncodingName</key>
<string>utf-8</string>
</dict>
</dict>
</plist>"#
);
依赖关系
~10MB
~212K SLoC