WorksApplications/uzushio

段落のHTMLパスの保存仕様

Closed this issue · 4 comments

com.worksap.nlp.uzushio.lib.html.ParagraphExtractorにて、

  • 一つのstackを作って、今まで見てきたパスを保存する
  • startElementで新しいタグをpush、endElementでpop
  • ほしい内容が来たら、stackをstringに変換し、17.toChar (ASCII 17番)と一緒に内容の先頭に入れる
class ParagraphExtractor(
    val paragraphs: ArrayBuffer[String]
) extends DefaultHandler {

  private var tag_path = mutable.Stack[String]()

  override def startElement(
      uri: String,
      localName: String,
      qName: String,
      atts: Attributes
  ): Unit = {
    ...
    tag_path.push(q)
    ...
    if (blockTags.contains(q)) {
      pushParagraph(tag_path.reverse.mkString("/"))
    }
    ...
  }

  override def endElement(uri: String, localName: String, qName: String): Unit = {
    ...
    tag_path.pop()
    ...
  }

  private def pushParagraph(tag_path_str: String): Unit = {
    ...
    if (str.nonEmpty) {
      paragraphs += tag_path_str + 17.toChar + str
    }
    ...
  }

効果(17.toCharはプリントされない):

>>> import pandas as pd
>>> df = pd.read_parquet("part-00000-87230b3f-eba4-48e6-89b7-a241d4a175db.c000.zstd.parquet")
>>> print(df["text"][0])
body/table/tr/td/ul「九条の会・わかやま」 340号を発行(2018年01月14日付)
340号が1月14日付で発行されました。1面は、9条改憲 「必要ない」53%...

body/table/tr/td/p――――――――――――――――――――――――――――――
[本文から]

body/table/tr/td/ul9条改憲、「必要ない」53%
本社加盟の日本世論調査会が先月9、10両日に実施した憲法に関する世論調査によると...

body/table/tr/td/p------------------------------------------------------------------------------

body/table/tr/td/ul北朝鮮問題に憲法9条改正で対応できるのか
【井上正信弁護士のQ&Aより抜粋】
憲法9条改正と北朝鮮問題との関連は
北朝鮮問題は憲法9条改正と常に結びつけられてきましたが、80年代の有事法制研究は...

OKですがidとclassの情報も保存もらえますか?
<div id="foo" class="bar bag"> -> div.bar.bag#foo みたいな感じです
あとはセパレーターとして > を使ったほうがいいです。タグ、クラス、idの名前で使えない文字ですので

@eiennohito 遅くなりました。

  • idとclassの保存を追加しました。
  • 上記のコードでは、block tagとparagraphが一つずれてしまいます。pushParagraphをstartElementからendElementに移って解決しました。

フルコード:

class ParagraphExtractor(
    val paragraphs: ArrayBuffer[String]
) extends DefaultHandler {
  ...
  private var tag_path = mutable.Stack[String]()
  ...

  override def startElement(
      uri: String,
      localName: String,
      qName: String,
      atts: Attributes
  ): Unit = {
    val q = qName.toLowerCase(Locale.ROOT)
    val id = atts.getValue("id")
    val classes = atts.getValue("class")

    var tag_path_str = s"${q}"
    if (classes != null) {
      tag_path_str += s".${classes.split(" ").mkString(".")}"
    }
    if (id != null) {
      tag_path_str += s"#${id}"
    }
    tag_path.push(tag_path_str)

    if (ignoreTags.contains(q)) {
      ignoreLevel += 1
    }

    if ("br" == q) {
      writer.append("\n")
    }
  }

  override def endElement(uri: String, localName: String, qName: String): Unit = {
    val q = qName.toLowerCase(Locale.ROOT)
    if (blockTags.contains(q)) {
      pushParagraph(tag_path.reverse.mkString(">"))
    }
    tag_path.pop()

    if (ignoreTags.contains(q)) {
      ignoreLevel -= 1
    }
  }

  override def endDocument(): Unit = {
    pushParagraph("")
  }

  private def pushParagraph(tag_path_str: String): Unit = {
    val str = cleanString(writer.result())
    if (str.nonEmpty) {
      paragraphs += tag_path_str + 17.toChar + str
    }
    writer.clear()
  }

  ...
}

こちらのWebページをparseした結果:

body#event>div.body_wrapper>div.header-logo-menu>div#nav-drawer>div#nav-content>ulマイページはこちら
はじめての方へ
ファンドレイザーを目指す方へ
私たちについて
事業紹介
参加する
ファンドレイジング・ジャーナル
NEWS
講師派遣、取材のご依頼
よくあるご質問
書籍購入
お問い合わせ
アクセス
サイトマップ
English
メルマガ

body#event>div.body_wrapper>div.header1>div.inr>ul.nav1NEWS
講師派遣、取材のご依頼
よくあるご質問
書籍購入
お問い合わせ
アクセス
English

body#event>div.body_wrapper>div.header1>div.inr>ul.nav2マイページ
メルマガ
facebook
Twitter

body#event>div.body_wrapper>div.header2>div.inr>h1日本ファンドレイジング協会

...

MRをお願いします!