根据文本beautifulsoup包装新标签中的html

时间:2018-05-03 20:34:38

标签: python html beautifulsoup

我想在一个html块周围包装一个新的<tr>,但是html没有任何我可能用来区分标签开头和结尾的唯一标签。我是使用BeautifulSoup的新手,一般来说,当我操纵汤对象时,它会操纵整个标签。我之所以发现这很难,那么就可以在多个标签上工作,这些标签除了文本之外不是唯一标识的。 html看起来像

<td>
  <th>Id</th>
  <td>1234</td>
  <th>something</th>
  <td>some text</td>
  <th>Id</th>
  <td>2345</td>
  <th>anything</th>
  <td>other text</td>
</td>

我希望每当我在<th>Id</th>标记中看到<tr>时,就会将其包裹起来:

<td>
  <tr>
    <th>Id</th>
    <td>1234</td>
    <th>something</th>
    <td>some text</td>
  </tr>
  <tr>
    <th>Id</th>
    <td>2345</td>
    <th>anything</th>
    <td>other text</td>
  </tr>
</td>

我也一直在尝试使用正则表达式,但由于Id是唯一一致的表格标题,而所有其他标题也是由<th>标记设置的,我还没有得到正确的组合。

2 个答案:

答案 0 :(得分:1)

<强>步骤:

  • 对所有<th><td>标记进行迭代。
  • 如果tag.text'Id',请使用wrap()new_tag()将该标记与新的<tr>标记包装在一起。
    • 使用.parent
    • 将新创建的<tr>标记保存在变量中
  • 否则,使用extract()提取标记,然后使用append()将其附加到之前创建的<tr>标记内容。

<强>代码:

html = '''
<td>
  <th>Id</th>
  <td>1234</td>
  <th>something</th>
  <td>some text</td>
  <th>Id</th>
  <td>2345</td>
  <th>anything</th>
  <td>other text</td>
</td>'''

soup = BeautifulSoup(html, 'html.parser')

curr_tag = ''
for tag in soup.td.find_all(['td', 'th']):
    if tag.text == 'Id':
        tag.wrap(soup.new_tag('tr'))
        curr_tag = tag.parent
    else:
        curr_tag.append(tag.extract())

print(soup)

<强>输出:

<td>
  <tr>
    <th>Id</th>
    <td>1234</td>
    <th>something</th>
    <td>some text</td>
  </tr>
  <tr>
    <th>Id</th>
    <td>2345</td>
    <th>anything</th>
    <td>other text</td>
  </tr>
</td>

答案 1 :(得分:0)

您可以使用itertools.groupby

import itertools, re
s = """
<td>
<th>Id</th>
<td>1234</td>
 <th>something</th>
 <td>some text</td>
 <th>Id</th>
 <td>2345</td>
 <th>anything</th>
<td>other text</td>
<td>
"""
[_, top], *main = [[a, list(b)] for a, b in itertools.groupby(filter(None, s.split('\n')), key=lambda x:bool(re.findall('\<th\>Id\<', x)))]
new_main = ['<tr>\n{}'.format('\n'.join(b)) if a else '{}\n</tr>'.format('\n'.join(b)) if i < len(main)-1 else '{}\n</tr>\n{}'.format('\n'.join(b[:-1]), b[-1]) for i, [a, b] in enumerate(main)]
final_result = '{}\n{}'.format('\n'.join(top), '\n'.join(new_main))

输出:

<td>
 <tr>
 <th>Id</th>
 <td>1234</td>
 <th>something</th>
 <td>some text</td>
 </tr>
<tr>
 <th>Id</th>
 <td>2345</td>
 <th>anything</th>
 <td>other text</td>
 </tr>
<td>