【问题标题】:Extracting a chunk of text between <p> tags [duplicate]在 <p> 标签之间提取一段文本[重复]
【发布时间】:2019-09-04 02:41:29
【问题描述】:

我有一些示例 html,我正在尝试从中解析和提取数据。这是数据的样子:

<div class="content">
<h1 class = “heading1”>MOVIE TITLE<h1>
<h2 class="heading2”>Synopsis</h2>
<div>
<p>this text is the synopsis of the movie.</p>
</div>
<h2 class="heading2”>Cast</h2>
<div>
<p>The cast includes</p>
<ol>
<li>Actor</li>
<li>Actor</li>
<li>Actor</li>
<li>Actor</li>
<li>Actor</li>
</ol>
</div>
</div>

<div class="content">
<h1 class = “heading1”>MOVIE TITLE<h1>
<h2 class="heading2”>Synopsis</h2>
<div>
<p>this text is the synopsis of the movie.</p>
</div>
<h2 class="heading2”>Cast</h2>
<div>
<p>The cast includes</p>
<ol>
<li>Actor</li>
<li>Actor</li>
<li>Actor</li>
<li>Actor</li>
<li>Actor</li>
</ol>
</div>
</div>

我想理想地提取四个部分,标题、概要和演员表。至此,解析它并使用美丽的汤提取每个电影实例:

from bs4 import BeautifulSoup

data = open("movies.txt",'r').read()
soup = BeautifulSoup(data, "html.parser")

我已经像这样提取了每部电影:

movies = soup.find_all('div', attrs={'class':'content'})

以及每部电影的片名

movies.find_all('h1', attrs={'class':'heading1'})

相当容易,因为它们具有独特的类属性。

我也想提取概要;只是&lt;p&gt; 标签之间的那一行;和演员名单分开,就像我对标题所做的那样。但是,到目前为止我能够做到

movies.find_all('h2', attrs={'class':'heading2'})

你可以想象,这只是给了我“概要”和“演员表”

【问题讨论】:

  • 您提供的 html 是否正确?我的意思是,它似乎重复了两次。此外,请看第二行。 &lt;h1&gt; 标签未正确关闭。
  • 我将使用 BeautifulSoup 来探索它的 RE 用法。我已经好几年没用过了。任何人这将暂时起作用。 &gt;&gt;&gt; import re ,, &gt;&gt;&gt; re.findall('&gt;Synopsis&lt;/[\S]+?&gt;[\S\s]*?&lt;p&gt;([\S\s]*?)&lt;/p&gt;', string)
  • heading2 的结束引号与它的 开始 引号不匹配。 ord('”') --&gt; 8221; ord('"') --&gt; 34您可能想在做任何其他事情之前批发更换那些。 ...stackoverflow.com/a/37021721/2823755
  • @wwii Whelp,这让我想起了我鄙视 BeautifulSoup 的原因。对我来说,它让一切变得更加复杂,在不同版本中的行为大相径庭,并且使正则表达式的使用变得困难且不一致。我查看并试图从你提到和堵嘴的帖子中得到结果。不知道是不是因为我在 Py2.7 但是,无论如何。 BS4 让我头疼,

标签: python html regex parsing beautifulsoup


【解决方案1】:

您的内容有 Right Double Quotes Marks - 请先替换它们。
替换错误字符;找到概要标题;提取下一个div

# s = your html
trans = str.maketrans({8221:34})    
soup = BeautifulSoup(s.translate(trans),"html.parser")
contents = soup.find_all('div', attrs={'class':'content'})
for content in contents:
    syn = content.find('h2', text='Synopsis')
    print(syn, syn.fetchNextSiblings()[0].text)

【讨论】:

    【解决方案2】:

    这是使用 Beautiful Soup 4.7+。您应该可以使用 CSS 选择器轻松定位 p 元素。

    为了获得概要,我们将使用 4 级选择器功能 :nth-child(an+b of s)。这将允许我们选择与选择器s 匹配的第一个孩子,这将是第一个h2.heading2 标记,然后我们将使用+ div 选择下一个div 兄弟和​​&gt; p 来选择直接pchild。

    from bs4 import BeautifulSoup
    
    html = """
    <div class="content">
    <h1 class="heading1">MOVIE TITLE</h1>
    <h2 class="heading2">Synopsis</h2>
    <div>
    <p>this text is the synopsis of the movie.</p>
    </div>
    <h2 class="heading2">Cast</h2>
    <div>
    <p>The cast includes</p>
    <ol>
    <li>Actor</li>
    <li>Actor</li>
    <li>Actor</li>
    <li>Actor</li>
    <li>Actor</li>
    </ol>
    </div>
    </div>
    
    <div class="content">
    <h1 class="heading1">MOVIE TITLE</h1>
    <h2 class="heading2">Synopsis</h2>
    <div>
    <p>this text is the synopsis of the movie.</p>
    </div>
    <h2 class="heading2">Cast</h2>
    <div>
    <p>The cast includes</p>
    <ol>
    <li>Actor</li>
    <li>Actor</li>
    <li>Actor</li>
    <li>Actor</li>
    <li>Actor</li>
    </ol>
    </div>
    </div>
    """
    
    soup = BeautifulSoup(html, "html.parser")
    
    for movie in soup.select('div.content'):
        print(movie.select_one('h1.heading1').text)
        print(movie.select_one(':nth-child(1 of h2.heading2) + div > p').text)
        for actor in movie.select('ol > li'):
            print(actor.text)
    
    

    输出:

    MOVIE TITLE
    this text is the synopsis of the movie.
    Actor
    Actor
    Actor
    Actor
    Actor
    MOVIE TITLE
    this text is the synopsis of the movie.
    Actor
    Actor
    Actor
    Actor
    Actor
    

    【讨论】:

    • 我确实必须修正开篇文章中提供的原始 HTML 中的一些拼写错误。
    • 请问什么是of s
    • 这是一个新的 4 级功能:drafts.csswg.org/selectors-4/#the-nth-child-pseudo。对于任何选择器,它的行为类似于 :nth-of-type。查看规范以了解更多信息。但我承认规范有时会有点混乱。
    • 我认识到 an+b 刚刚查看了指导,因为我知道它是 1n+1 等。但是 of s 似乎是一个选择器列表。所以这可以使用例如 not:(x,y,z) 来排除? +
    • 所以,正如现在所读的规范,它确实支持选择器列表,我也支持。规范中最近的一个变化是将其限制为第 4 级中的复合选择器,然后是第 5 级中的复杂选择器。我们现在支持第 5 级(第 5 级基本上意味着支持组合器)。
    猜你喜欢
    • 2018-04-24
    • 1970-01-01
    • 1970-01-01
    • 2020-02-24
    • 2016-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多