链接读取的 output 到底是什么格式:Markdown 结构拆解与二次处理
# 链接读取的 output 到底是什么格式:Markdown 结构拆解与二次处理
接口:链接读取(apiCode=3262)· 接入点:获取网页正文(3262-1)· 计费:50 厘/次 · 适用人群:要拿正文做下游处理的开发者 · 阅读时间:约 10 分钟 · 最后实测核对:2026-09-15
## 核心要点
- 文档把 `output` 写成 `String`,实测它返回的是 **Markdown**:标题、列表、表格、图片、链接都带结构。
- 图片的 `alt` 是一串哈希,链接有时指向栏目页而不是图片文件,直接拿去做图集会出错。
- 正文里混着导航和页脚,入库前必须清洗,否则检索结果会被垃圾文本污染。
## 拿到的是一份带结构的正文
第一次看到 `output` 的人通常会愣一下。文档写的是 `String`,你以为是一段纯文本,实际拿到的是这样(站点与页面正文已隐去,只保留结构):
```markdown
# 页面主标题
导航项
导航项
导航项
榜单名
条目一 条目二 条目三 条目四 条目五
功能入口
更多
```
再看另一个站点首页返回的片段(同样只保留结构):
```markdown
### 栏目下的一条标题
摘要文字……
## <br> 栏目名

- 条目名
- 条目名
```
这两段放一起看,能看出这个接口做的事:把页面 DOM 里的文本层级翻译成 Markdown 语法。转得挺合理,但也留下了原页面的痕迹。
## `output` 里实际出现的六类结构
| 结构 | 语法形态 | 实测例子(内容已隐去) | 备注 |
|------|---------|---------------------|------|
| ATX 标题 | `#` / `##` / `###` | `# 页面主标题`、`### 栏目下的一条标题` | 层级来自原页面的 h1/h2/h3 |
| 无序列表 | `- ` | `- 条目名` | 导航、栏目名大量使用 |
| 有序列表 | `1. ` | `1. 栏目名`、`1. 榜单名` | 综合门户首页实测出现 |
| 管道表格 | `\| --- \| --- \|` | 新闻站点首页的频道表 | 表格被完整转成 Markdown 表格 |
| 图片 | `` | ` ` | alt 是哈希串,不是描述文字 |
| 链接 | `[text](url)` | `[联系邮箱: xxx@example.com](mailto:xxx@example.com)` | 会出现 `mailto:` 等协议 |
另外还有加粗 `**加粗文字**`、以及**残留的原始 HTML 标签**——上面那段里就有 `## <br> 栏目名`,`<br>` 没被清掉。
## 几种需要二次处理的写法
**图片的 `alt` 是哈希,不是图片说明。** `![6f2a1c8b9d4e0f37-8b2f5a1c9e4d7a03]` 这串东西对读者和模型都没意义。要用图片,得自己生成描述,或者干脆放弃 `alt`。
**图片链接有时指向公开网页,不是图片文件。** 实测里有条图片语法的 URL 实际是一个视频栏目的页面地址,不是图片文件。照着 `output` 里的图片地址去下载文件,会拿到一堆 HTML。判断办法是看扩展名和 `Content-Type`,不能只看 `![]()` 这个语法。
**导航和页脚混在正文里。** 实测某个垂直站点的首页只返回 850 字符,其中大半是"查公司 / 查老板 / 快捷功能 / 关于我们"这类导航项。这不是接口侧的问题,而是首页本身就以导航为主。做检索之前需要把这类短行切掉。
**段落被拆得很碎。** 原文里一个换行,`output` 里往往变成 `\n\n`,于是每个短句都成了一个独立段落。直接按段落切块,会切出一堆长度只有十几个字的碎片。
## 四种后处理写法
### 转 HTML 直接渲染
```python
# pip install markdown
import markdown
html_body = markdown.markdown(output, extensions=["tables", "fenced_code"])
html = f"<!doctype html><html><head><meta charset='utf-8'></head><body>{html_body}</body></html>"
```
`tables` 扩展必须开,否则管道表格会渲染成一堆竖线。
### 转纯文本
```python
# pip install markdown-it-py
from markdown_it import MarkdownIt
import re
def to_plain_text(md: str) -> str:
tokens = MarkdownIt("commonmark").parse(md)
parts = []
for t in tokens:
if t.type == "inline" and t.content:
parts.append(t.content)
elif t.type in ("fence", "code_block"):
parts.append(t.content)
text = "\n".join(parts)
text = re.sub(r"!\[[^\]]*\]\([^)]*\)", "", text) # 去图片
text = re.sub(r"\[([^\]]*)\]\([^)]*\)", r"\1", text) # 链接保留文字
return text
```
### 抽图片地址
```python
import re
IMG_RE = re.compile(r"!\[([^\]]*)\]\(([^)\s]+)")
def extract_images(md: str):
"""返回 [(alt, url)]。注意 url 可能指向页面而非图片文件,需下游校验。"""
return IMG_RE.findall(md)
```
拿到列表后别急着下载,先按扩展名过滤一遍,`Content-Type` 也要查。
### 按标题切分块
```python
import re
def chunk_by_heading(md: str, min_len: int = 120):
"""按 Markdown 标题切块;过短的块与下一块合并,避免碎片。"""
lines = md.splitlines()
chunks, cur_title, cur_buf = [], "(无标题)", []
def flush(title, buf):
text = "\n".join(buf).strip()
if not text:
return
if chunks and len(text) < min_len:
chunks[-1]["text"] += "\n" + text # 太短就并进上一块
else:
chunks.append({"title": title, "text": text})
for ln in lines:
m = re.match(r"^(#{1,6})\s+(.*)$", ln)
if m:
flush(cur_title, cur_buf)
cur_title, cur_buf = m.group(2).strip(), []
else:
cur_buf.append(ln)
flush(cur_title, cur_buf)
return chunks
```
`min_len` 设 120 左右,是为了对付上面说的"段落被拆碎"问题。实测下来,不合并的话,门户首页能切出上百个只有十几个字的块,检索命中率会很难看。
## 清洗规则建议
放到向量库之前,这几条按顺序过一遍:
- 删掉长度小于 6 个字且不含标点的行——导航项基本都是这个形状
- 删掉连续重复的行(页面轮播、榜单常有重复)
- 合并连续空行,把 3 个以上 `\n` 压成 2 个
- 去掉独立的 `[...](...)` 行——纯链接行对检索没帮助
- 保留标题,它是切块时唯一可用的层级信息
要不要在这一步做正文提取(也就是从整页里挑出主体段落),取决于你的数据源。新闻详情页本身干净,门户首页就得靠上面的规则削。
## FAQ
**Q1:`output` 是 JSON 还是 Markdown?**
是 Markdown 文本,装在 `showapi_res_body.output` 这个字符串字段里。外层是 JSON,正文本身是 Markdown。
**Q2:为什么图片的 `alt` 是一串乱码?**
那不是乱码,是原页面图片节点的标识符,接口原样保留了下来。它不含语义信息,做展示或检索时建议忽略,或者自己根据上下文补描述。
**Q3:表格能保留吗?**
能。实测某个新闻站点首页返回的频道表被完整转成了 Markdown 管道表格,用 `markdown` 库渲染时带上 `tables` 扩展就能正确显示成表格。
**Q4:`output` 里有 HTML 标签,正常吗?**
正常。实测出现过 `## <br> 锋面` 这种,`<br>` 是原页面的换行标签,没有被清理。入库前顺手过滤一遍 `<[^>]+>` 就行。
**Q5:正文里的导航怎么去掉?**
没有通用的一刀切办法。可行的做法是结合长度和标点做启发式过滤:导航项通常很短、不含句末标点、且成组出现。上面的清洗规则里第 1 条就是干这个的。
## 下一步阅读
- 把这些块喂进向量库的完整管道 → [把链接读取接进 RAG 管道](https://www.showapi.com/guides/link-read-rag-pipeline-3262)
- `output` 的取值与结果判断 → [链接读取返回结构说明与结果判断](https://www.showapi.com/guides/link-read-empty-output-3262)
- 第一次调用还没跑通 → [链接读取:用 Python 读取任意公开网页的正文](https://www.showapi.com/guides/link-read-quickstart-3262)
- **本系列共 6 篇**:查看[链接读取指南总目录](https://www.showapi.com/guides/link-read-guides-3262)