
本文介绍如何使用 R 的 stringr 包精准提取 html 字符串中两个指定关键词(如 “Regeste” 和 “Sachverhalt”)之间的完整原始内容(含所有 HTML 标签与空白字符),适用于网页结构化文本抽取任务。
本文介绍如何使用 r 的 stringr 包精准提取 html 字符串中两个指定关键词(如 “regeste” 和 “sachverhalt”)之间的**完整原始内容(含所有 html 标签与空白字符)**,适用于网页结构化文本抽取任务。
在网页数据抓取(如使用 rvest 解析 HTML)后,常需从原始 HTML 字符串中定位并截取特定语义区块——例如瑞士联邦法院判决书中的
与 所标记的“摘要”(Regeste)和“案情”(Sachverhalt)部分。此时,简单使用 str_extract(html, “Regeste.*Sachverhalt”) 会失败:默认点号 . 不匹配换行符,且贪婪匹配易越界;更关键的是,我们往往需要包含起始/结束关键词邻近的 HTML 结构(如
…),而非仅关键词之间的纯文本。
正确做法是采用支持跨行匹配、支持非捕获断言的正则表达式,并借助 stringr::str_extract() 实现精准提取。核心技巧有三:
- 启用跨行匹配:使用 [sS](匹配任意空白或非空白字符)替代 .,确保涵盖换行符 、制表符 等;
- 避免捕获边界词本身:使用正向先行断言 (?
- 兼顾大小写灵活性:通过 Regeste|regeste 和 Sachverhalt|sachverhalt 支持常见大小写变体,提升鲁棒性。
以下是完整可运行示例:
library(dplyr) library(stringr) # 示例 HTML(已简化,保留关键结构) html <- '<a name="idp341456"></a><div class="big bold">Urteilskopf</div> <br>147 IV 65<br><br><br><div class="paraatf">8. Auszug aus dem Urteil der Strafrechtlichen Abteilung i.S. A. gegen Generalstaatsanwaltschaft des Kantons Bern, B. und Verein C. (Beschwerde in Strafsachen)</div> <div class="paraatf">6B_440/2019 vom 18. November 2020</div> <a name="idp342784"></a><br><div id="regeste" lang="de"> <div class="big bold">Regeste</div> <br><div class="paraatf"><span class="artref">Art. 28 Abs. 1 StGB</span>; Strafbarkeit der Medien; keine Anwendbarkeit von <span class="artref">Art. 28 Abs. 1 StGB</span> beim "Teilen" und Kommentieren eines fremden Beitrags auf Facebook. <div class="paratf">Grundsatz der exklusiven Strafbarkeit des Autors bei Mediendelikten (E. 5.1-5.3). Der in <span class="artref">Art. 28 Abs. 1 StGB</span> verankerte Begriff des "Mediums" umfasst nicht nur sämtliche Kommunikationsträger, sondern auch Kommunikationsmittel (E. 5.4.1-5.4.3). </div> <div class="paratf">Die Anwendbarkeit von <span class="artref">Art. 28 Abs. 1 StGB</span> erfordert zunächst, dass das Medienerzeugnis der Öffentlichkeit zugänglich gemacht wird. Das gilt grundsätzlich für Beiträge auf Social Media-Plattformen, soweit sie nicht durch persönliche Einstellungen nur für einen beschränkten Personenkreis verfügbar sind (E. 5.4.4). </div> <div class="paratf">Die Anwendbarkeit von <span class="artref">Art. 28 Abs. 1 StGB</span> bedingt zusätzlich, dass sich die strafbare Handlung in der Veröffentlichung erschöpft. <span class="artref">Art. 28 Abs. 1 StGB</span> privilegiert dabei alle innerhalb der für das Medium typischen Herstellungs- und Verbreitungskette tätigen Personen. Der weite Medienbegriff setzt voraus, dass im Einzelfall geprüft werden muss, wer Teil der medientypischen Kette ist. Vorliegend verneint beim "Teilen" und Kommentieren eines fremden bereits veröffentlichten Beitrags auf Facebook (E. 5.5 und 5.6). </div> </div> </div> <a name="idp232400"></a> <a name="idp246448"></a> <br><div> <a name="idp404656"></a><span class="big bold" id="sachverhalt">Sachverhalt</span> <span class="small">ab Seite 66</span> </div> <br><div class="paraatf">' df <- data.frame(html = html, stringsAsFactors = FALSE) # ✅ 正确提取:Regeste 与 Sachverhalt 之间的全部内容(含标签、换行、空格) df <- df %>% mutate( regeste_block = str_extract( html, "(?<=Regeste|regeste)[sS]*(?=Sachverhalt|sachverhalt)" ) ) # 查看提取结果长度与前100字符验证 cat("提取内容长度:", nchar(df$regeste_block), " ") cat("前100字符预览: ", substr(df$regeste_block, 1, 100), "... ")
⚠️ 注意事项:
立即学习“前端免费学习笔记(深入)”;
- 勿用 .* 替代 [sS]*:. 默认不匹配换行符,会导致跨多行的 HTML 内容截断;
- 避免贪婪陷阱:若 HTML 中多次出现 “Sachverhalt”,[sS]* 会匹配到最后一个出现位置。如需最短匹配(即首次闭合),可改用 [sS]*?(非贪婪模式),但需确保上下文唯一性;
- HTML 解析优先于正则:对复杂、嵌套深或格式不规范的 HTML,建议优先使用 rvest::html_nodes() 配合 CSS/XPath 定位(如 html_node(“#regeste”)),正则提取应作为轻量级、结构稳定场景的补充方案;
- 编码与转义:确保输入字符串为 UTF-8 编码;若 HTML 含实体(如 &),提取后需用 xml2::xml_text() 或 stringi::stri_unescape_html() 进一步处理。