使用BeautifulSoup包装多个标签

时间:2015-08-28 15:07:51

标签: python beautifulsoup

我正在编写一个python脚本,允许将html文档转换为reveal.js幻灯片。为此,我需要在Public String Get_Filed_By_Id(string table_Name,String Field_Name,string PK_val) { string strRes=""; using(mydbcontext db=new mydbcontext()) { var x=db.table_Name.Where(p=>p.Id=PK_val).Select(b=>b.Field_Name).FirstOrDefault(); strRes=Convert.Tostring(x); } return strRes; } 标记内包含多个标记。

使用wrap()方法将单个标签包装在另一个标签内很容易。但是,我无法弄清楚如何包装多个标签。

澄清的一个例子,原始的html:

<section>

我想将html_doc = """ <html> <head> <title>The Dormouse's story</title> </head> <body> <h1 id="first-paragraph">First paragraph</h1> <p>Some text...</p> <p>Another text...</p> <div> <a href="http://link.com">Here's a link</a> </div> <h1 id="second-paragraph">Second paragraph</h1> <p>Some text...</p> <p>Another text...</p> <script src="lib/.js"></script> </body> </html> """ """ 及其下一个标记包含在<h1>标记内,如下所示:

<section>

以下是我如何做出选择:

<html>
<head>
  <title>The Dormouse's story</title>
</head>
<body>

  <section>
    <h1 id="first-paragraph">First paragraph</h1>
    <p>Some text...</p>
    <p>Another text...</p>
    <div>
      <a href="http://link.com">Here's a link</a>
    </div>
  </section>

  <section>
    <h1 id="second-paragraph">Second paragraph</h1>
    <p>Some text...</p>
    <p>Another text...</p>
  </section>

  <script src="lib/.js"></script>
</body>

</html>

输出:

from bs4 import BeautifulSoup
import itertools
soup = BeautifulSoup(html_doc)
h1s = soup.find_all('h1')
for el in h1s:
    els = [i for i in itertools.takewhile(lambda x: x.name not in [el.name, 'script'], el.next_elements)]
    els.insert(0, el)
    print(els)

选择正确但我无法查看如何将每个选项包装在[<h1 id="first-paragraph">First paragraph</h1>, 'First paragraph', '\n ', <p>Some text...</p>, 'Some text...', '\n ', <p>Another text...</p>, 'Another text...', '\n ', <div><a href="http://link.com">Here's a link</a> </div>, '\n ', <a href="http://link.com">Here's a link</a>, "Here's a link", '\n ', '\n\n '] [<h1 id="second-paragraph">Second paragraph</h1>, 'Second paragraph', '\n ', <p>Some text...</p>, 'Some text...', '\n ', <p>Another text...</p>, 'Another text...', '\n\n '] 标记内。

2 个答案:

答案 0 :(得分:4)

最后我发现在这种情况下如何使用wrap方法。我需要了解汤对象的每一个变化都已到位

from bs4 import BeautifulSoup
import itertools
soup = BeautifulSoup(html_doc)

# wrap all h1 and next siblings into sections
h1s = soup.find_all('h1')
for el in h1s:
    els = [i for i in itertools.takewhile(
              lambda x: x.name not in [el.name, 'script'],
              el.next_siblings)]
    section = soup.new_tag('section')
    el.wrap(section)
    for tag in els:
        section.append(tag)

print(soup.prettify())

这给了我想要的输出。希望有所帮助。

答案 1 :(得分:0)

我想我会考虑这个,因为它有点困难和混乱。基本上,使用 BeautifulSoup 的 html_test 字符串,我向树添加一个新 div,将其锚定在 上,然后循环它,包装/附加所有元素,直到它到达 ,包括未标记的字符串。 wrapTag 函数将所有元素添加到 div 中,直到它到达最后一个 p。实现 while 循环的主要事情是附加到 div 移动而不是将 next_sibling 复制进来。所以如果我们使用硬列表和 for 循环,第 i 个位置就会发生变化。希望有帮助。卢卡斯

#!/usr/bin/env python3
#coding: utf-8
from platform import python_version
from bs4 import __version__ as bs_version, Tag, NavigableString, BeautifulSoup

try:
    html_test = '<body><div class="div" id="1">beforePa<p>line 1a</p>betweenPab<p class="x">line 1b<b>bold in 1b</b></p>betweenPbc<p>line 1c</p>betweenPcd<p>line 1d</p>betweenPde<p class="y">line 1e</p>betweenPef<p>line 1f</p>afterPf</div><div class="div" id="2"><p>line 2a</p><p>line 2b</p><p>line 2c</p></div></body>'
    html = BeautifulSoup(html_test, 'lxml')
    print(html.prettify())
    parser = 'lxml'
except:
    parser = 'html.parser'
print('python: "'+python_version()+'", bs4 version: "'+bs_version+'", bs4 parser: "'+parser+'"')

def p(tag, sstr=""):
    print(sstr+".. .")
    print(tag, " ... ", type(tag))
    print("text: ", tag.text, " ... ", type(tag.text))
    print("string: ", tag.string, " ... ", type(tag.string))
    print("contents: ", tag.contents, " ... ", type(tag.contents))
    print()
    return

def newTag(tag, attrs={}, tstr=""):
    n = html.new_tag(tag)
    if (len(attrs) > 0):
        for k, v in attrs.items():
            n[k] = v
    if (len(tstr) > 0):
        n.string = tstr
    return n

def wrapTag(newTag, fromTagInclusive, toTagExclusive):
    fromTagInclusive.wrap(newTag)
    #p(fromTagInclusive.parent, "fromTag.parent")
    n = fromTagInclusive.parent
    c = 0
    while 1:
        c += 1
        x = n.next_sibling
        if (x is None):
            break
        n.append(x)
        #print(c, x, n.next_sibling, isinstance(n.next_sibling, Tag), n.next_sibling.name if isinstance(n.next_sibling, Tag) else "~Tag", n.next_sibling.attrs if isinstance(n.next_sibling, Tag) else "~Tag")
        #if isinstance(n.next_sibling, Tag) and (n.next_sibling.name == 'p') and ('class' in n.next_sibling.attrs) and ('y' in n.next_sibling['class']):
        if (n.next_sibling == toTagExclusive):
            break
    return n, toTagExclusive

n = newTag('div', { 'class':"classx", 'id':"idx" }, 'here we are in classx idx')
p(n, "new div")
n, _ = wrapTag(n, html.find('p', {'class':"x"}), html.find('p', {'class':"y"}))
p(n, "wrapped div")
print(html.prettify())
exit()