首页 > 解决方案 > 如何从包含“p”标签和内部文本混合的 HTML 元素中提取文本?

问题描述

我正在使用名为Reaver的 jsoup 周围的 Clojure 包装器来抓取一个包含一些结构不佳的 HTML 的网站。以下是一些 HTML 结构的示例:

<div id="article">
  <aside>unwanted text</aside>
  <p>Some text</p>
  <nav><ol><li><h2>unwanted text</h2></li></ol></nav>
  <p>More text</p>
  <h2>A headline</h2>
  <figure><figcaption>unwanted text</figcaption></figure>
  <p>More text</p>
  Here is a paragraph made of some raw text directly in the div
  <p>Another paragraph of text</p>
  More raw text and this one has an <a>anchor tag</a> inside
  <dl>
    <dd>unwanted text</dd>
  </dl>
  <p>Etc etc</p>
</div>

div代表 wiki 上的一篇文章。我想从中提取文本,但如您所见,有些段落在p标签中,有些则直接包含在 div 中。我还需要标题和锚标记文本。

我知道如何从所有 、 和 标签中解析和提取文本pah可以选择div并从中提取内部文本,但问题是我最终选择了两个需要合并的文本不知何故。

如何从此 div 中提取文本,以便按顺序提取p, a,h标签中的所有文本以及 上的内部文本?div结果应该是与 HTML 中的顺序相同的文本段落。

这是我目前用来提取的内容,但div结果中缺少内部文本:

(defn get-texts [url]
  (:paragraphs (extract (parse (slurp url))
                        [:paragraphs]
                        "#article > *:not(aside, nav, table, figure, dl)" text)))

另请注意,其他不需要的元素出现在 this 中div,例如 ,asidefigure。这些元素包含文本,以及带有文本的嵌套元素,不应包含在结果中。

标签: htmlclojurejsoup

解决方案


您可以将整篇文章提取为 JSoup 对象(可能是Element),然后使用reaver/to-edn. 然后你遍历:content那个并处理字符串(s 的结果)和你感兴趣TextNode的元素。:tag

(由 vaer-k 编写)

(defn get-article [url]
  (:article (extract (parse (slurp url))
                     [:article]
                     "#article"
                     edn)))

(defn text-elem?
  [element]
  (or (string? element)
      (contains? #{:p :a :b :i} (:tag element))))

(defn extract-text
  [{content :content}]
  (let [text-children (filter text-elem? content)]
    (reduce #(if (string? %2)
               (str %1 %2)
               (str %1 (extract-text %2)))
            ""
            text-children)))

(defn extract-article [url]
  (-> url
      get-article
      extract-text))

推荐阅读