- 后端
- AI 应用
- NLP
【免费下载链接】xberg
Polyglot document intelligence with a Rust core: extract text, metadata, images, tables, and structured data from 106 formats across 140 file extensions, plus code intelligence for 371 languages. Fifteen bindings, with CLI, REST API, and MCP server.
本文基于 Xberg 的 C# 绑定,讲解如何通过XbergConverter.ExtractAsync从 HTTP 服务器返回的 gzip 压缩文档中透明提取文本内容。你将掌握 URL 提取模式(UrlExtractionMode)的用法、ExtractionConfig的配置方式,以及仓库中 mock 服务器、e2e 测试与 gzip 解压实现背后的完整技术链路。文中的代码与配置均来自当前仓库的真实生成片段和测试用例,可直接复制运行。
一、应用场景:为什么需要处理 gzip 编码的远程文档
在真实网络中,HTTP 服务器为降低带宽消耗,常常对响应体启用Content-Encoding: gzip(或 deflate、br)压缩。这意味着客户端通过 URL 抓取到的原始字节并非可直接解析的文档内容,而是压缩流。若提取管线不透明处理传输编码,轻则解析失败,重则把压缩字节误判为二进制文件。
Xberg 的 URL 抓取链路在设计上把"抓取 + 传输编码解码"与"文档格式解析"分离:抓取层负责跟随 URI 拿到响应并还原出原始文档字节,提取层再按 MIME 类型走对应的格式解析器。因此用户无需关心远端是否压缩,只需在调用时指定 URL 提取模式即可。仓库中的 e2e 场景extract: remote document served gzip-encoded正是对这一行为的直接验证。
二、完整可运行示例:C# 提取 gzip 远程文档
原文档 url_gzip_encoded_document.md 给出了一个 typecheck 级别的 C# 代码片段,核心调用如下:
using System; using System.Text.Json; using Xberg; var ConfigOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; var result = await XbergConverter.ExtractAsync( new ExtractInput { Kind = JsonSerializer.Deserialize<ExtractInputKind>("\"uri\"", ConfigOptions)!, Uri = "https://example.com" }, new ExtractionConfig { Url = new UrlExtractionConfig { Mode = JsonSerializer.Deserialize<UrlExtractionMode>("\"document\"", ConfigOptions)! } }); Console.WriteLine(result.Results[0].Content); Console.WriteLine(result.Summary.RemoteUrls);拆解这段代码,可以看到四个关键点:
- 输入类型:
ExtractInput的Kind被显式反序列化为"uri",配合Uri字段,声明这是一个"按 URL 抓取"的输入,而非"bytes"或"file"输入。 - 大小写不敏感反序列化:
JsonSerializerOptions { PropertyNameCaseInsensitive = true }允许 JSON 字段名与 C# 属性名宽松匹配,这也是生成片段里统一使用的配置风格。 - 模式选择:
UrlExtractionConfig.Mode设置为"document",明确告诉引擎"把该 URI 当作单个远程文档处理",而不是去抓取页面里的链接。 - 结果读取:提取文本位于
result.Results[0].Content;result.Summary.RemoteUrls则统计本次调用实际抓取到的远程 URL 数量。
值得说明的是,Mode用字符串反序列化是为了与各语言绑定保持一致的 JSON 契约——在 e2e 测试中同样如此。完整的可运行版本见 UrlTests.cs:
[Fact] public async Task Test_UrlGzipEncodedDocument() { // extract: remote document served gzip-encoded var Input_MockBaseUrl = Environment.GetEnvironmentVariable("MOCK_SERVER_URL_GZIP_ENCODED_DOCUMENT") ?? Environment.GetEnvironmentVariable("MOCK_SERVER_URL") + "/fixtures/url_gzip_encoded_document"; var Input_Json = "{\"kind\":\"uri\",\"uri\":\"$mock_url\"}".Replace("$mock_url", Input_MockBaseUrl); var result = await XbergConverter.ExtractAsync( ExtractInput.FromJson(Input_Json), ExtractionConfig.FromJson("{\"url\":{\"mode\":\"document\"}}")); Assert.Contains("Remote document hello", result.Results[0].Content.ToString()); Assert.True(result.Summary.RemoteUrls == 1); }该测试与生成片段等价,区别在于它面向真实 mock 服务器:MOCK_SERVER_URL指向测试环境,$mock_url会被替换为fixtures/url_gzip_encoded_document路径,从而拿到一个真正以 gzip 传输编码返回的远程文档。
三、配置解析:UrlExtractionConfig 与 UrlExtractionMode
URL 提取的配置结构定义在 types.rs,核心字段如下:
| 字段 | 类型 | 默认值 | 作用 |
|---|---|---|---|
mode | UrlExtractionMode | auto | URL 提取模式 |
crawl | CrawlConfig | 见下文默认策略 | 抓取行为控制(深度、页数、并发等) |
document_url_pattern | Option<String> | None | 文档模式下对发现 URL 的正则过滤 |
max_document_urls_per_result | Option<u32> | 100 | 每个提取结果最多跟随的 URL 数 |
max_total_urls | Option<u32> | 1000 | 单次提取调用全程最多跟随的 URL 总数 |
allow_local_file_inputs | bool | true | 是否允许裸本地文件系统路径输入 |
allow_file_uris | bool | true | 是否允许本地file://URI 输入 |
其中UrlExtractionMode是枚举类型,定义了三种模式(源码注释见 types.rs):
auto(默认):抓取后自动对 HTTP(S) 资源做分类,由引擎决定按文档还是按页面处理;document:把 URI 当作单个远程文档/页面处理,最贴合本文的 gzip 文档场景;crawl:以种子 URI 为起点爬取,并提取发现的所有页面/文档。
当mode为crawl时,crawl子配置生效,默认策略(default_xberg_crawl_config,见 types.rs)为:max_depth = 1、max_pages = 100、max_concurrent = 10、respect_robots_txt = true、stay_on_domain = true、allow_subdomains = true、soft_http_errors = true、document_url_depth = 1。
对于 gzip 远程文档场景,最省事的写法是仅设置mode = "document",其余全部走默认值——这正是原文档片段和 e2e 测试的做法。
四、测试验证:mock 服务器与断言设计
该场景对应的契约定义在 url_gzip_encoded_document.json,它同时描述了 mock 服务器行为和验证断言:
Mock 响应(模拟远端服务器):
{ "mock_responses": [ { "path": "/", "method": "GET", "status_code": 200, "headers": { "content-type": "text/plain; charset=utf-8", "content-encoding": "gzip" }, "body_inline": "Remote document hello from Xberg URL e2e. ..." } ] }注意两点设计意图:其一,响应头显式携带content-encoding: gzip,模拟真实压缩传输;其二,正文反复重复同一句话,注释写明"so the response is unambiguously compressed rather than stored"——如果 mock 服务器没有真正压缩,而是按原样存储,重复内容也能保证"压缩与否"可被分辨,避免测试误判。
提取输入与配置:
{ "input": { "extract_input": { "kind": "uri", "uri": "$mock_url" } }, "config": { "url": { "mode": "document" } } }断言(三条):
[ { "type": "not_error" }, { "type": "contains", "field": "results[0].content", "value": "Remote document hello" }, { "type": "equals", "field": "summary.remote_urls", "value": 1 } ]not_error:整个提取过程不得报错,证明 gzip 传输编码被透明处理;contains:Results[0].Content必须包含解压后的明文Remote document hello,证明抓取层成功把 gzip 响应还原成了可解析的文本;equals:Summary.RemoteUrls == 1,证明本次调用只抓取了该文档一个远程 URL。
这三条断言从"无错误、内容正确、URL 统计正确"三个维度锁定了该功能的行为,其他语言的 e2e 测试(Go、Python、Node、Ruby 等)均以同一份 fixture 生成了等价用例。
五、底层原理:gzip 响应如何被还原与防御
在 Xberg 核心实现中,gzip 相关内容分布在两个层面:
1. MIME 类型注册
application/gzip及其别名application/x-gzip在 mime.rs 中被注册为已知 MIME 类型。这意味着若远程文档本身就是.gz文件,也会被识别并进入归档提取路径;而本文讨论的"传输编码"场景则在抓取层完成解压,二者是两条独立的路径。
2. 归档解压与解压炸弹防护
gzip.rs 实现了带上限的 gzip 解压:decompress_gzip_limited(bytes, max_size)以SecurityLimits.max_archive_size为上限,解压结果一旦超限立即报错("Gzip decompressed size exceeds ... byte limit"),从实现层面防止解压炸弹。同时支持单次解压同时产出元数据与文本内容(extract_gzip),避免重复解压的开销。对应测试见 gzip_and_limits.rs:test_decompress_gzip压缩 "test content" 后解压还原,验证了基础解压路径。
3. 抓取层的透明解压
从 fixture 与 e2e 测试可以推断:URL 抓取层在拿到带Content-Encoding: gzip的响应后,会先还原出原始文档字节,再交给后续 MIME 判定与格式解析,因此上层调用者感知不到压缩过程。这种"传输编码透明化"的设计,是 Xberg 能以统一ExtractAsync接口同时处理明文文档、压缩传输文档乃至归档文件的根基。
六、延伸:从单文档到批处理
同一套 URL 配置也适用于批量提取。仓库的 URL 分类下还有url_batch_mixed_inputs场景(url_batch_mixed_inputs.md),演示ExtractBatchAsync在同一输出信封中混合处理字节输入与 URL 输入;若需要抓取站点下的多个页面,则切换mode为crawl并配合max_depth、max_pages等抓取参数。所有场景共享同一份UrlExtractionConfig,这也是该配置被设计为独立结构体、并在ExtractionConfig中以url字段挂载的原因(见 core.rs)。
总而言之:处理 gzip 编码的远程文档时,你只需构造kind = "uri"的输入并设置url.mode = "document",解压与解析交给引擎完成,再通过Results[0].Content与Summary.RemoteUrls校验结果即可——这也是 Xberg 在 C# 及全部语言绑定中统一提供的契约。
- 后端
- AI 应用
- NLP
【免费下载链接】xberg
Polyglot document intelligence with a Rust core: extract text, metadata, images, tables, and structured data from 106 formats across 140 file extensions, plus code intelligence for 371 languages. Fifteen bindings, with CLI, REST API, and MCP server.
相关推荐
Xberg C 绑定实战:通过 FFI 提取 gzip 压缩传输的远程文档
Xberg C 绑定实战:通过 FFI 提取 gzip 压缩传输的远程文档 本文围绕仓库中自动生成的 C 语言示例 url_gzip_encoded_docum
后端AI 应用NLPXberg C FFI 实战:用 xberg_extract 从远程 URL 提取文本文档
Xberg C FFI 实战:用 xberg_extract 从远程 URL 提取文本文档 本文以 Xberg 仓库中自动生成的 C 语言 E2E 片段 url
后端AI 应用NLP用 Xberg C 绑定批量提取远程文档:ExtractBatchAsync 与 extract_batch 契约实战
用 Xberg C 绑定批量提取远程文档:ExtractBatchAsync 与 extract_batch 契约实战 Xberg 是一套以 Rust 为核心的
后端AI 应用NLP
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考