跳转至

4. 文献内容提取与结构化处理

在上一个阶段,我们获取了文献的元数据+文本内容: - 对于 pubmed文献:我们获取了元数据,并通过PMC下载了全文文本内容(如果有的话), 然后解析输出为 markdown 和 json 格式 - 对于非 pubmed 文献:我们通过 doi(对于预印本则是通过相应*-fetch模块) 获取了 pdf 文件,使用 mineru 解析引擎将其解析,输出格式也是统一到 markdown 和 json 格式

这两者输出的 markdown 文件都可以作为全文文本内容替代,可以作为文献本体阅读使用,但是难以进行章节提取和规范化处理。

而json 文件则是包含复杂结构的原始解析结果,包含了丰富的文本内容和位置信息,但不够规范化,难以直接使用。

我们这一步从 json 文件出发,将原始 json 文件依据语段内容解析与分类,划分整理为规范化的/章节化的 json 文件,

即尽可能按照下列文献经典章节进行划分提取(具体章节划分配置上会有些差异):

metadata(title,year,authors)
abstract
introduction
results
discussion
methods
conclusion
supplementary
availability
funding
acknowledgements
author contributions
references
other

我们的目的就是能够依据不同文献本身章节划分的标准规范,考虑到科研人员下游阅读解析文献的核心需求,从目的论上将文献根本性地划分为固定的 section,让科研人员在固定的思考框架下去巡视/使用文献知识。

其中,对于 pubmed 文献,因为我们的文本数据是从 PMC 数据库获取的,所以我们解析的出发点是PMC 解析响应之后的 json 文件,

为了后续数据资料的完整性(因为有些pubmed 文献没有 pmc 全文),我们设计了两个模块来结构化提取和表征一篇 pubmed 文献。

首先是合并元数据和文本数据(如果有 pmc 的话),生成一个包含完整信息的 json 文件:

pubmed-merge-json 模块可帮助你将指定文件夹下所有 pubmed 文献的元数据和文本内容进行合并,生成一个包含同一topic完整信息的 json/jsonl 文件。

 paperflow pubmed-merge-json --help

 Usage: paperflow pubmed-merge-json [OPTIONS]                                                                       

 Create a merged JSON (or JSONL) file from PubMed paper directories.                                                

 This produces a canonical merged JSON representation per paper and is                                              
 intended as the first stage in a two-stage pipeline (merge-json -> export-md).                                     


 Example usage:                                                                                                     
 - 1. Merge JSON files for all papers in a directory:                                                               
   paperflow pubmed-merge-json --input ./MyPapers --output ./MyPapers                                               
 - 2. Merge JSON files for PMIDs listed in a file:                                                                  
   paperflow pubmed-merge-json --input ./MyPapers --output ./MyPapers --pmid-file ./pmid_list.txt --jsonl           
 --stats-path ./MyPapers/stats                                                                                      

╭─ Options ────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 *  --input       -i      TEXT  Directory containing paper data                                                   
                                ({INPUT_PAPER_DIR_HERE}/pubmed/year/pmid/structure).                              
                                [required]                                                                        
 *  --output      -o      TEXT  Output directory or file path. If a directory or path without extension is given, 
                                the merged file is auto-named as                                                  
                                <input-directory-base-name>_<datetime>.json/.jsonl.                               
                                [required]                                                                        
    --pmid-file   -p      TEXT  File containing PMIDs to merge (one per line).                                    
    --jsonl                     Write output as JSONL, one JSON per line.                                         
    --stats-path  -s      TEXT  Optional path to save merge statistics file, defaults to current directory.       
                                [default: .]                                                                      
    --help                      Show this message and exit.                                                       
╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

因为我们结构化文献的目的是为了能够从统一章节设置中进行批量内容提取,所以我们的上述模块设计优先应用于批量文献场景,当然你可以通过文件指定某一篇文献进行单独处理。

我们默认会对你所提供的输入文件夹下的所有 pubmed 文献进行独立的文献合并,并汇总你所指定清单范围内的 json 文件,进行二次合并为 1 个汇总的 json 文件(这通常发生在你希望将同一个研究主题的文献进行汇总/构造初步文献知识库的情况下)。

而这个汇总的 json 文件,是我们下一步进行结构化归类提取的起点:

pubmed-export-md 模块可帮助你将指定的汇总 json 文件,依据章节提取配置文件,批量导出并合并为一个规范化的 markdown 文件。

 paperflow pubmed-export-md --help

 Usage: paperflow pubmed-export-md [OPTIONS]                                                     

 Export a single Markdown view from a merged JSON file using optional YAML config.               


 Notes:                                                                                          
 - 1, The input merged JSON/JSONL should be produced by the pubmed-merge-json command, which     
 creates a canonical representation of paper metadata and content.                               
 - 2, The optional YAML config can specify which metadata fields and content sections to include 
 in the Markdown output. If not provided, it defaults to including basic metadata and the FULL   
 content.                                                                                        


 Example usage:                                                                                  
 - 1. Export Markdown for all papers in a merged JSON:                                           
 paperflow pubmed-export-md --input ./MyPapers/merged.jsonl --output ./MyPapers/exported.md      
 --config ./config.yaml                                                                          
 - 2. Export Markdown for PMIDs listed in a file:                                                
 paperflow pubmed-export-md --input ./MyPapers/merged.jsonl --output ./MyPapers/exported.md      
 --config ./config.yaml --pmid-file ./pmid_list.txt                                              

╭─ Options ─────────────────────────────────────────────────────────────────────────────────────╮
 *  --input      -i      TEXT  Path to merged JSON or JSONL produced by pubmed-merge-json.     
                               [required]                                                      
 *  --output     -o      TEXT  Output Markdown file path. [required]                           
    --config     -c      TEXT  YAML config file specifying metadata_fields and                 
                               content_sections. If not provided, defaults to basic metadata   
                               and FULL content.                                               
    --pmid-file  -p      TEXT  Optional PMID file to filter exported papers.                   
    --help                     Show this message and exit.                                     
╰───────────────────────────────────────────────────────────────────────────────────────────────╯

对于每一篇文献,其元数据的键值对是固定的:

content
    abstract  # abstract text, 🌟 important
    keywords  # keywords, 🌟 important
    mesh_terms  # mesh terms, 🌟 important
    pub_types # article or review, can be used for filtering, 🌟 important
contributors
    medline # contributors parsed from medline format, MIXED PERSONS PER DICT, LESS DETAILED
        affiliations # affiliations of contributors
        auids # ORCID 
        full_names # full names of contributors
        short_names # short names of contributors, 🌟 important for citation
    xml  # contributors parsed from xml format, ONE PERSON PER DICT, MORE DETAILED
        affiliations # same as above
        full_name
        identifiers
        short_name
identity
    doi # DOI of the paper, 🌟 important, can be used for DOI-based fetching module
    pmid # PubMed ID, 🌟 important
    title # title of the paper, 🌟 important
links
    cites # cite this paper, 🌟 important
    entrez # other entrez links
    external # other external database links, ONE LINK PER DICT, MORE DETAILED (⚠️ there may be Full text source)
        attribute
        category
        linkname
        provider
        url # URL of the external database link, 🌟 important
    pmc # PMC ID used to download full text, 🌟 important
    refs # (pmid) cited by this paper, 🌟 important
    review # (pmid) All review articles highly relevant to the theme of this paper , 🌟 important
    similar # (pmid) topic-similar papers, 🌟 important
    text_mined # links mined from PMC full text(if available), 🌟 important (there may be github links or other sources)
metadata
    entrez_date # date when the paper was added to PubMed
    fetched_at # date when the paper was fetched by our tool
source
    journal_abbrev # abbreviation abbreviation of the journal
    journal_title # full name of the journal
    pub_date # publication date
    pub_types # publication types, similar to pub_types in content above 
    pub_year # publication year, 🌟 important for citation

需要进行语义分类划分处理的是其文本数据。

我们在批量文献导出模块pubmed-export-md中为-c参数提供了章节提取yaml配置文件pubmed export yaml,可以依据配置文件中的设置批量提取对应文献的指定章节内容,比如说批量提取引言作为背景调研。

⚠️ 这个yaml配置文件的键值是固定的,你只能注释掉部分键值以获取指定章节,或者默认全部章节提取

metadata_fields:
  - identity.title
  - identity.pmid
  - identity.doi
  - content.keywords
  - content.mesh_terms
  - content.pub_types
  - content.abstract # abstract in metadata first, fall back in content sections(deprecated)
  - contributors.medline
  - contributors.xml
  - links.cites
  - links.entrez
  - links.external
  - links.pmc
  - links.refs
  - links.review
  - links.similar
  - links.text_mined
  - metadata.entrez_date
  - metadata.fetched_at
  - source.journal_abbrev
  - source.journal_title
  - source.pub_date
  - source.pub_types
  - source.pub_year

content_sections:
  - abstract
  - introduction
  - methods
  - results
  - discussion
  - conclusion
  - supplementary
  - availability
  - funding
  - acknowledgements
  - author_contributions

具体解析逻辑如下

flowchart TD
    A[开始导出 Markdown] --> B{是否提供 YAML?}

    B -- 是 --> C[读取 yaml_cfg]
    C --> D[加载 metadata_fields / content_sections]
    D --> E[写入文献级标题与元信息]
    E --> F[提取 content.body 章节树]
    F --> G[_extract_section_records: 原始章节 -> record]
    G --> H[_normalize_section_title: 映射为 canonical_type]
    H --> I[_order_section_records: 按 content_sections 排序]
    I --> J[_aggregate_section_records: 合并同 canonical_type]
    J --> K{canonical_type 是否在 content_sections?}
    K -- 否 --> L[跳过]
    K -- 是 --> M[_render_section_records: 渲染为 Markdown 标题]
    M --> N[输出文献间分隔符]
    L --> N

    B -- 否 --> O[不做章节映射]
    O --> P[写入文献级标题与元信息]
    P --> Q{该文献是否有 content.body?}
    Q -- 有 --> R[按原始树递归展开]
    R --> S[render_raw_content_tree: 直接输出 title/content/subsections]
    Q -- 无 --> T[从 meta 中补 abstract]
    T --> U[输出 meta 字段 + abstract]
    S --> N
    U --> N

    N --> V[下一篇文献]
    V --> W[结束] 

以上是对pubmed 文献进行的结构化提取操作,但是对于非 pubmed 数据库,我们能够解析的起点是 mineru 解析引擎解析获取的初步 json 文件(content_list_v2.json,参考官方文档-输出格式部分:https://opendatalab.github.io/MinerU/reference/output_files/)。

PDF 经 MinerU 处理后生成的 content_list_v2.json 以页面为单位组织数据——一个外层数组代表所有页面, 每个元素是该页面的渲染块列表。这些块包含论文标题、段落、行间公式、图片/图表、表格、页眉、页脚、脚注等多种类型, 混杂在一起,无法直接用于下游的语义分析或 LLM 输入。

我们的目标就是将这个原始的json转换为统一的、按文献领域规范章节归并的结构化json。

输入的json结构:

[
  [                        // page 0
    {"type": "title",      "content": {"title_content": [...], "level": 1}},
    {"type": "paragraph",  "content": {"paragraph_content": [...]}},
    {"type": "title",      "content": {"title_content": [...], "level": 2}},
    {"type": "paragraph",  "content": {"paragraph_content": [...]}},
    {"type": "page_header", ...},     // 噪声
    {"type": "page_footnote", ...},   // 噪声
    ...
  ],
  [                        // page 1
    ...
  ]
]

常见的块类型(按内容取值归类):

类型 是否正文 文本提取路径
title 是(章节锚点) content.title_content[*].content + level(1=文章标题,2=一级章节)
paragraph 是(主文本) content.paragraph_content[*].content,支持 equation_inline 子项
equation_interline 是(行间公式) content.math_content(LaTeX)
table 部分 content.html(HTML 表格) + content.table_caption
image / chart 否(保留 caption) content.image_caption[*].content / content.chart_caption
page_header / page_footer / page_footnote 噪声(丢弃) 用于元数据扫描(年份/DOI/期刊名)

我们的解析流水线如下:

                   content_list_v2.json
  ───────────────── Step 1: 扁平化 ─────────────────
              _flatten() — 去掉噪声块
             (page_header/footer/footnote)
              保留 title / paragraph / table 等
  ────────────── Step 2: 元数据提取 ────────────────
              ┌─ title    ← 第一个 level=1 的 title 块
              ├─ authors  ← title 后第一个短行(含逗号、<400 字符)
              ├─ year     ← 从 page_footer 中提取 "2025"
              ├─ doi      ← 从 page_footnote 中匹配 "10.1002/..."
              └─ journal  ← 从 page_header 中选取全大写短名称
  ────────────── Step 3: 抽象提取 ──────────────────
             _extract_abstract()
             跳过作者行 → 收集第一个 section 前所有段落
  ─────────┐ Step 4: 章节分割 ─────────────────────
           │  以 title 块为界切分段落:
           │    level=1 → 跳过(论文标题)
           │    level=2 → 新主节
           │    level>=3 或编号 "2.1." → 子节,归入父节
  ─────────┤ Step 5: 标题归一化 ─────────────────────
           │  normalize_section_title()
           │    去除数字前缀 "2.2. IDPFold..." → "IDPFold..."
           │    匹配 CANONICAL_TYPES 表 → "results"
  ─────────┤ Step 6: 节归并 ───────────────────────
           │  _aggregate_sections()
           │    同一 canonical_type 的内容合并
           │    保持 subsections 列表
  ─────────┘ Step 7: 表格提取 ─────────────────────
             _extract_tables()
             收集所有 table 块的 html + caption
                   结构化输出 JSON

总之,这个文件相比 pmc 输出的 json 格式会更加复杂和难以解析。

和 pubmed 文献处理类似,我们同样提供了两个串行的模块合作来处理 json 结构化提取解析工作。

mineru-parse + mineru-export-md 可以看作是复杂版的 pubmed-merge-json + pubmed-export-md 功能组合。

 paperflow mineru-parse --help

 Usage: paperflow mineru-parse [OPTIONS]                                                                              

 Parse mineru output content_list_v2.json into canonical sectioned JSON.                                              

 Extracts metadata (title, authors, year, DOI, journal),                                                              
 and sections normalised to canonical types (abstract, introduction, results,                                         
 discussion, methods, etc.). Tables are preserved as HTML.                                                            


 Notes:                                                                                                               
 - 1, Two backends: 'regex' (pattern + context, no API) and 'ai' (LLM batch classification).                          
 - 2, AI backend supports Anthropic native, OpenAI native, and any OpenAI-compatible                                  
 endpoint via --base-url (DeepSeek, university proxies, self-hosted, etc.).                                           
 - 3, Set the appropriate API key env var (ANTHROPIC_API_KEY, OPENAI_API_KEY,                                         
 DEEPSEEK_API_KEY) or pass --api-key.                                                                                 
 - 4, Configure provider/model via --model, --base-url, or a YAML config file.                                        


 Examples:                                                                                                            
   paperflow mineru-parse -i content_list_v2.json -o paper.json                                                       
   paperflow mineru-parse -i content_list_v2.json -o paper.json --backend ai                                          
   paperflow mineru-parse -i content_list_v2.json -o paper.json --backend ai \                                        
       --base-url https://api.deepseek.com --model deepseek-v4-pro --api-key sk-xxx                                   
   paperflow mineru-parse -i content_list_v2.json -o paper.json --backend ai \                                        
       --base-url https://models.sjtu.edu.cn/api/v1 --model deepseek-chat                                             
   paperflow mineru-parse -i content_list_v2.json -o paper.json --backend regex --config custom.yaml                  

╭─ Options ──────────────────────────────────────────────────────────────────────────────────────────────────────────╮
 *  --input     -i      TEXT  Path to mineru content_list_v2.json. [required]                                       
 *  --output    -o      TEXT  Output path for the structured JSON file. [required]                                  
    --backend   -b      TEXT  Section classification backend: 'regex' (default, no API needed) or 'ai'.             
                              [default: regex]                                                                      
    --config    -c      TEXT  Path to YAML config file for canonical types, aliases, and AI settings.               
    --api-key           TEXT  API key for AI backend. Overrides config file and env var.                            
    --model             TEXT  Override AI model (e.g. 'deepseek-v4-pro', 'claude-haiku-4-5', 'gpt-4o-mini').        
    --base-url          TEXT  Custom API base URL for OpenAI-compatible endpoints (e.g.                             
                              'https://api.deepseek.com').                                                          
    --help                    Show this message and exit.                                                           
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯

mineru-parse 将 MinerU 输出的扁平 JSON 转换为结构化的规范 JSON,每个章节被归类到标准的学术章节类型中,同时提取元数据(标题、作者、年份、DOI、期刊)和图片注释。

在这里我们提供了两种后端用于语段解析,

Two Backends / 两种后端

Backend How it works API needed? Best for
regex (default) Pattern matching: exact string → regex → context keyword. Configurable via YAML. No Common papers, batch processing
ai Sends all section titles + context to an LLM in one batch API call. Yes Non-standard titles, multi-publisher
---

1. Regex matching layers / Regex 匹配层级:

1. strong (exact match)   → "Introduction" == "introduction"  ✓
2. weak (regex search)    → "1. Introduction" matches r"introduction"  ✓
3. context_keywords       → "Overview" → check text for "we used..." → methods
4. fallback               → classify as "other"

系统采用滑动游标追踪文档行文顺序,以降低章节误匹配概率;即前一个章节匹配成功之后,下一个章节不从头开始匹配,而是从前一个章节匹配的位置开始。

2. AI workflow / AI 工作流程:

content_list_v2.json
    → extract all titles + surrounding text (~200 chars)
    → build JSON payload: [{index, title, context_preview}, ...]
    → one API call → AI returns {classifications: [{index, canonical_type}]}
    → merge classifications into structured JSON

⚠️ 目前默认使用正则表达式后端,ai 后端正在维护开发中

🌟 对于当前模块mineru-parse-c参数输入 yaml 配置文件,请参考使用我们提供的模板文件mineru config file,正常使用情况下我们不需要修改配置文件,全部使用默认项即可。这份配置文件就是按照兼容两个后端设计的,regex后端以及 ai后端。相关的说明以及具体修改注意事项都可以在文件中进行查看。

再次强调,所有匹配规则都在上面的mineru_config.yaml中,内置了合理默认值,正常使用不需要提供,仅在需要适配特定期刊时修改。

而修改时你可以全局定制你自己想要的章节模块分类,按照你自己实际文献阅读、下游分析处理的需求去对文章的任意语段内容进行个性化归类。

🌟 所以这意味着我们的章节解析是高度个性化 的,理论上你可以依据你手头上的任意类型的文献定制任意章节类别以及解析逻辑


Config file layout / 配置文件结构:

Section Purpose
ai model, api_key, base_url for AI backend
canonical_order Which types exist + their output order
display_names Human-readable labels (can be Chinese, etc.)
aliases Matching rules: strong (exact), weak (regex), context_keywords

Common customization scenarios / 常见自定义场景:

Scenario Where to edit
Title misclassified as "other" / 标题被归入 other Add to matching type's strong or weak
Need a new section type / 需要新类型 Add to canonical_order + display_names + aliases
Switch AI model / 切换模型 Edit ai.model and ai.base_url
Chinese labels / 中文标签 Edit display_names

比如说输出的 1 个典型的 json 文件如下:

{
  "source": "mineru",
  "file": "paper_content_list_v2.json",
  "backend": "regex",
  "metadata": {
    "title": "Accurate Generation of Conformational Ensembles...",
    "authors": "Junjie Zhu, Zhengxin Li, ...",
    "year": 2025,
    "doi": "10.1002/advs.202511636",
    "journal": "Advanced Science"
  },
  "sections": [
    {
      "canonical_type": "abstract",
      "raw_title": "Abstract",
      "display_title": "Abstract",
      "level": 2,
      "paragraphs": ["In this paper, we..."],
      "subsections": []
    },
    {
      "canonical_type": "introduction",
      "raw_title": "1. Introduction",
      "display_title": "Introduction",
      "paragraphs": ["...", "[Figure: Figure 1. Architecture overview...]"],
      "subsections": []
    },
    {
      "canonical_type": "results",
      "raw_title": "2. Results",
      "display_title": "Results",
      "subsections": [
        {"raw_title": "2.1. Global Features", "paragraphs": ["..."]}
      ]
    }
  ]
}

基本上都是按照我们平时阅读文献的规范章节类型,大约在 15 种左右: abstract introduction results discussion methods conclusion supplementary availability funding acknowledgements author_contributions keywords conflicts references other

在整理输出结构化的 json 文件之后,我们就可以按需求进行批量章节选择并导出了。

可以说,pubmed-export-md 模块对 pubmed 文献做的任务实际上就是 mineru-parse和 mineru-export-md 的组合。

 paperflow mineru-export-md --help

 Usage: paperflow mineru-export-md [OPTIONS]                        

 Export structured mineru JSON to a clean Markdown file for LLM     
 processing.                                                        

 Reads one or more JSON files produced by ``mineru-parse`` and      
 writes a                                                           
 single Markdown file.  Metadata (title, authors, year, DOI,        
 journal) is                                                        
 always included.  Content sections are included based on the       
 optional                                                           
 YAML config.                                                       


 YAML config format:                                                
   content_sections:                                                
     - abstract                                                     
     - introduction                                                 
     - methods                                                      
     - results                                                      
     - discussion                                                   
     - conclusion                                                   


 Examples:                                                          
   paperflow mineru-export-md -i paper.json -o paper.md             
   paperflow mineru-export-md -i paper.json -o paper.md --config    
 extract.yaml                                                       
   paperflow mineru-export-md -i ./parsed_dir -o all_papers.md      

╭─ Options ────────────────────────────────────────────────────────╮
 *  --input   -i      TEXT  Path to structured JSON file (from    
                            mineru-parse), or a directory of such 
                            files.                                
                            [required]                            
 *  --output  -o      TEXT  Output Markdown file path. [required] 
    --config  -c      TEXT  YAML config specifying                
                            content_sections to include. If not   
                            provided, all sections are included.  
    --help                  Show this message and exit.           
╰──────────────────────────────────────────────────────────────────╯

🌟 同样的,mineru-export-md模块也可以指定-c配置文件,请参考使用我们提供的模板文件mineru export config file,按照你需要批量导出的章节进行设置,相关说明以及具体修改注意事项都可以在文件中进行查看。

⚠️ 另外注意,该配置文件中的章节类型必须是在 mineru_config.yaml 的 canonical_order 中定义过的。如果你在解析阶段自定义了新类型(比如 - ethics),在这里才能引用它。换句话说,上游 parse 定义了什么类型,下游 export 才能选择什么。总之mineru export config filemineru config file 得对应。

mineru_config.yaml                mineru_export_config.yaml

┌──────────────────────┐          ┌──────────────────────┐
 canonical_order:                content_sections:    
   - abstract         │── 定义     - abstract         
   - introduction       类型池     - introduction     
   - results                       - results          
   - ...                           - discussion       
   - ethics   自定义              - methods          
└──────────────────────┘             - ethics   引用   
                                   └──────────────────────┘

如果你在 mineru_config.yaml 的 canonical_order 里新增了ethics,并配了 aliases,解析时论文里的"Ethics Statement" 标题就会被归类为 ethics,然后你在导出配置里写 - ethics,就能把它选出来。如果没有在上游定义过,导出阶段就找不到这个类型。

同样的,mineru-export-md功能也是为了批量处理而设计的,批量模式下提供非pubmed文献解析的文件夹,我们会扫描目录下所有.json文件(建议把mineru-parse的输出放单独1个目录,确保没有其他非解析产物的json文件),按文件名排序,每篇论文之间用---分隔,输出为1个合并的Markdown文件