質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

タグ

特殊な記法により文書に埋め込む形で記述される付加情報をタグと呼びます。文書構造や書式、文字飾りなどを指示したり、画像や他の文書へのリンクを埋め込むことができる。

Q&A

解決済

1回答

369閲覧

BS4を用いてHTMLタグの種類によってテキスト部分を抽出・編集したい(入れ子の場合の処理の仕方について)

tyobit

総合スコア17

スクレイピング

スクレイピングとは、公開されているWebサイトからページ内の情報を抽出する技術です。

HTML5

HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

タグ

特殊な記法により文書に埋め込む形で記述される付加情報をタグと呼びます。文書構造や書式、文字飾りなどを指示したり、画像や他の文書へのリンクを埋め込むことができる。

0グッド

0クリップ

投稿2019/09/08 13:31

編集2019/09/08 19:45

現在、HTMLタグを種類毎にスコアを決め、そのスコアの合計に応じて異なる処理をしようとしています。

例えば、<b>が2点で<i>が1点の場合…

html

1<b>あいうえお</b><i>かきくけこ<b>さしすせそ</b></i>

という状態から

text

1[2]あいうえお[/2][1]かきくけこ[3]さしすせそ[/3][/1]

のような文字列を生成したいと思っています。

"あいうえお"は<b>のみなので2点
"かきくけこ"は<i>のみなので1点
"さしすせそ"は<b><i>の両方なので1+2=3点
となります。

以前は、

python

1find = soup.find_all(tag) 2 for text in find: 3 text.replace_with(start + text.string + end) 4 #startとendはタグの種類によって変わる

のようにスコアの対象となるタグに関して上記を実行していました。
しかし、上記の場合、タグの入れ子の順番や変換するタグの順番で結果が変わってしまいます。

例えば、

html

1<b><i>あいうえお</i></b>

これに対し変換を行うと

text

1<b>→<i>の場合 2[2]あいうえお[/2] 3<i>→<b>の場合 4[2][1]あいうえお[/1][/2]

現在、解決方法を探し始めた状態での質問になります。
新しい方法が見つかり次第、質問内容を更新していきます。
アドバイスのほどよろしくお願いします。

追記--

python

1find = soup.find_all(tag) 2 for text in find: 3 text.string = start + text.string + end 4 #startとendはタグの種類によって変わる

としてみたが結果は同じだった

追記2--

python

1def list_check(f,L,tag): #listでなかったら関数に投げる 2 if isinstance(L,list): 3 if L == []: 4 return [] 5 else: 6 return [list_check(f,L[0],tag)] + list_check(f,L[1:],tag) 7 else: 8 return f(L,tag) 9 10def contents_check(contents,tag): # 11 for contents_list in contents.find_all(tag): #スコア対象のタグ一覧から該当するものを探す 12 tag_num=0 13 for content in contents_list.contents: #子の要素にタグがあるか確認 14 if content.name != None: 15 tag_num = 1 16 if tag_num == 0: #子にタグがなかったら(入れ子の一番内側) 17 """ 18 タグごとのスコア決めは省略 19 """ 20 contents_list.replace_with(start + contents_list.string + end) #点数で挟む[1]~~~[/1]など 21 else: 22 list_check(contents_check,contents_list.contents,tag) #子の要素にタグがある場合、もう一周

この場合、2周目のcontentsのクラスがbs4.element.Tagのためfind_allが使えなかった
また、find_allだと"<b><i>あいうえお</i></b>"に対して、[<b><i>あいうえお</i></b>,<i>あいうえお</i>]と同一のテキストを複数回抽出してしまう

追記3--

python

1while 1: #子要素がなくなるまでひたすら繰り返す 2 j=0 #ループ抜け用 3 for tag in tag_list: #スコア対象のタグについて一つずつ確認 4 for contents in soup.find_all(tag): 5 i=0 #子要素があるか確認 6 for content in contents.contents: 7 if content.name != None: 8 i+=1 9 j+=1 10 if i==0: #子要素がなかったら該当スコアをタグ形式で付与 11           #タグごとのスコア決めは省略 12 contents.string = start + contents.string + end 13 contents.unwrap() #スコアを付与したらタグを外す 14 if j==0: break

これによって"<b><i>あいうえお</i></b>"に対して"[2][1]あいうえお[/1][/2]"と出力できるようになった
次は"[2][1]あいうえお[/1][/2]"を"[3]あいうえお[/3]"とまとめたい

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

回答

HTML は木構造になっているので、深さ優先探索を行う際に、タグ名が "b"、"i" のノードが見つかった場合は重みを加算を行うことで、階層構造を考慮することができます。

コード

python

1from bs4 import BeautifulSoup 2 3html = "<b>あいうえお</b><i>かきくけこ<b>さしすせそ</b></i>" 4soup = BeautifulSoup(html) 5 6def traverse(node, weight): 7 # b タグまたは i タグが見つかった場合、重みを加算して、 8 # 名前を現在の重みで置き換える。 9 if node.name == "b": 10 weight += 2 11 node.name = str(weight) 12 elif node.name == "i": 13 weight += 1 14 node.name = str(weight) 15 16 # ノードが子を持つ場合 17 if hasattr(node, "children"): 18 for child in node.children: 19 traverse(child, weight) 20 21 22traverse(soup, 0) 23print(soup) 24# <2>あいうえお</2><1>かきくけこ<3>さしすせそ</3></1> 25# もし、<> を [] にしたい場合、正規表現による置換などの後処理を行ってください。

投稿2019/09/09 07:08

編集2019/09/09 07:15
tiitoi

総合スコア21956

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tyobit

2019/09/09 07:12

ありがとうございます。 こんなにもシンプルにできるのですね… 帰宅し次第確認してみます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問