82754


HTML形式のテキストからテキストのみの文字位置とそれに付随するタグをpythonで抽出したいです。  
文字位置はHTMLタグを抜いた文字数での抽出がしたいです。

例

[code]

    <a>テキスト1</a><h1>テキスト2</h1><h2>テキスト3<a>テキスト4</a></h2>
    
[/code]

取得したい値

[code]

    [{'tag':a,'text':テキスト1,'start_index':0,end_index:4},{'tag':h1,'text':テキスト2,'start_index':5,end_index:9},{'tag':h2,'text':テキスト3テキスト4,'start_index':10,end_index:19},{'tag':a,'text':テキスト4,'start_index':15,end_index:19}]
    
[/code]

上記のように抽出する方法はないでしょうか。  
よろしくお願いいたします。


CC BY-SA 4.0
2021-09-29T07:54:16.720
82752
2021-09-29T20:20:01.387
42340
question
python
HTML形式のテキストからテキストのみの文字位置とそれに付随するタグをpythonで抽出したい。


テキストの重複に対応してみました。

[code]

    from bs4 import BeautifulSoup
    
    def extract_html_text_with_index(html):
      soup = BeautifulSoup(html, 'html.parser')
    
      result, start, end, cur, tstart, prev_len = [], 0, 0, 0, 0, 0
      for i in soup.findAll():
        if start <= i.sourcepos < end:
          tstart += i.sourcepos - start - prev_len
          prev_len = len(i.name) + 3 # 3 == len('</>')
        else:
          if soup.index(i) == 0:
            cur = len(i.text) - 1
          else:
            tstart, cur = cur + 1, cur + len(i.text)
          end, prev_len = i.sourcepos + len(str(i)) - 1, 0
        start = i.sourcepos + len(i.name) + 2 # 2 == len('<>')
    
        result.append({
          'tag': i.name, 'text': i.text,
          'start_index': tstart, 'end_index': tstart+len(i.text)-1
        })
    
      return result
    
    if __name__ == '__main__':
      from pprint import pprint
    
      html = [
        (
          '<a>テキスト1</a>' +
          '<h1>テキスト2</h1>' +
          '<h2>テキスト1<a>テキスト2</a></h2>'
        ),
        (
          '<h2>テキスト1<a>テキスト1</a>テキスト1<a>テキスト1</a></h2>'
        ),
        (
          '<a>テキスト1</a>' +
          '<h1>テキスト2</h1>' +
          '<h2><div>テキスト3</div>テキスト4<span>テキスト5</span></h2>' +
          '<h3>テキスト4<p>テキスト3</p></h3>' +
          '<h4>テキスト2</h4>'
        ),
      ]
    
      for h in html:
        result = extract_html_text_with_index(h)
        pprint(result, sort_dicts=False)
    
    # 実行結果
    [{'tag': 'a', 'text': 'テキスト1', 'start_index': 0, 'end_index': 4},
     {'tag': 'h1', 'text': 'テキスト2', 'start_index': 5, 'end_index': 9},
     {'tag': 'h2', 'text': 'テキスト1テキスト2', 'start_index': 10, 'end_index': 19},
     {'tag': 'a', 'text': 'テキスト2', 'start_index': 15, 'end_index': 19}]
    
    [{'tag': 'h2',
      'text': 'テキスト1テキスト1テキスト1テキスト1',
      'start_index': 0,
      'end_index': 19},
     {'tag': 'a', 'text': 'テキスト1', 'start_index': 5, 'end_index': 9},
     {'tag': 'a', 'text': 'テキスト1', 'start_index': 15, 'end_index': 19}]
    
    [{'tag': 'a', 'text': 'テキスト1', 'start_index': 0, 'end_index': 4},
     {'tag': 'h1', 'text': 'テキスト2', 'start_index': 5, 'end_index': 9},
     {'tag': 'h2', 'text': 'テキスト3テキスト4テキスト5', 'start_index': 10, 'end_index': 24},
     {'tag': 'div', 'text': 'テキスト3', 'start_index': 10, 'end_index': 14},
     {'tag': 'span', 'text': 'テキスト5', 'start_index': 20, 'end_index': 24},
     {'tag': 'h3', 'text': 'テキスト4テキスト3', 'start_index': 25, 'end_index': 34},
     {'tag': 'p', 'text': 'テキスト3', 'start_index': 30, 'end_index': 34},
     {'tag': 'h4', 'text': 'テキスト2', 'start_index': 35, 'end_index': 39}]
    
[/code]


CC BY-SA 4.0
2021-09-29T09:02:32.180
82754
2021-09-29T20:20:01.387
2021-09-29T20:20:01.387
47127
47127
82752
answer