Verwenden von BeautifulSoup, um ein HTML-Tag zu finden, das bestimmten Text enthält

69

Ich versuche, die Elemente in einem HTML-Dokument abzurufen, die das folgende Textmuster enthalten: # \ S {11}

<h2> this is cool #12345678901 </h2>

Das vorherige würde also übereinstimmen, indem es Folgendes verwendet:

soup('h2',text=re.compile(r' #\S{11}'))

Und die Ergebnisse wären ungefähr so:

[u'blahblah #223409823523', u'thisisinteresting #293845023984']

Ich kann den gesamten passenden Text abrufen (siehe Zeile oben). Ich möchte jedoch, dass das übergeordnete Element des Textes übereinstimmt, damit ich es als Ausgangspunkt für das Durchlaufen des Dokumentbaums verwenden kann. In diesem Fall möchte ich, dass alle h2-Elemente zurückgegeben werden und nicht der Text übereinstimmt.

Ideen?

Sotangochips
quelle
3
Tatsächlich wird die h2-Einschränkung gemäß der BeautifulSoup-Dokumentation ignoriert: "Wenn Sie Text verwenden, werden alle Werte, die Sie für den Namen und die Schlüsselwortargumente angeben, ignoriert."
Rabarberski
@ Rabarberski Ich bin mir nicht sicher, wie die Situation im Jahr 2010 war, aber bis 2012 stellt ich fest, dass die Verwendung text(oder stringdie sie ersetzt) ​​keine anderen Einschränkungen ignoriert
TC Proctor

Antworten:

81
from BeautifulSoup import BeautifulSoup
import re

html_text = """
<h2>this is cool #12345678901</h2>
<h2>this is nothing</h2>
<h1>foo #126666678901</h1>
<h2>this is interesting #126666678901</h2>
<h2>this is blah #124445678901</h2>
"""

soup = BeautifulSoup(html_text)


for elem in soup(text=re.compile(r' #\S{11}')):
    print elem.parent

Drucke:

<h2>this is cool #12345678901</h2>
<h2>this is interesting #126666678901</h2>
<h2>this is blah #124445678901</h2>
nosklo
quelle
Vielen Dank! Es ist verwirrend, dass es eine Liste von Unicode-Zeichenfolgen zurückgegeben hat. Ich schätze die Hilfe.
Sotangochips
2
.parentwar großartig! Ich habe niemals darüber nachgedacht. Danke @nosklo. +1
Md. Mohsin
Wenn Sie die Ausgabe der Suche sofort wiederholen möchten, ist for perfekt. Sonst wie wäre es mit einem Listenverständnis als solchem: [elem.parent für Element in Suppe (text = re.compile (r '# \ S {11}'))]
peterb
@sotangochips Ja, auf den ersten Blick sieht es so aus, als würde eine einfache Unicode-Zeichenfolge zurückgegeben, aber es ist tatsächlich ein NavigableString mit einem .parent. Musste PyCharms Debugger verwenden, um zu erkennen, dass es sich nicht um eine einfache Zeichenfolge handelt.
José Tomás Tocino
21

BeautifulSoup-Suchvorgänge liefern [eine Liste von] BeautifulSoup.NavigableStringObjekten, wenn text=sie als Kriterium verwendet werden, im Gegensatz zu BeautifulSoup.Taganderen Fällen. Überprüfen Sie die Objekte __dict__, um die Ihnen zur Verfügung gestellten Attribute anzuzeigen. Von diesen Attributen parentwird previousaufgrund von Änderungen in BS4 bevorzugt .

from BeautifulSoup import BeautifulSoup
from pprint import pprint
import re

html_text = """
<h2>this is cool #12345678901</h2>
<h2>this is nothing</h2>
<h2>this is interesting #126666678901</h2>
<h2>this is blah #124445678901</h2>
"""

soup = BeautifulSoup(html_text)

# Even though the OP was not looking for 'cool', it's more understandable to work with item zero.
pattern = re.compile(r'cool')

pprint(soup.find(text=pattern).__dict__)
#>> {'next': u'\n',
#>>  'nextSibling': None,
#>>  'parent': <h2>this is cool #12345678901</h2>,
#>>  'previous': <h2>this is cool #12345678901</h2>,
#>>  'previousSibling': None}

print soup.find('h2')
#>> <h2>this is cool #12345678901</h2>
print soup.find('h2', text=pattern)
#>> this is cool #12345678901
print soup.find('h2', text=pattern).parent
#>> <h2>this is cool #12345678901</h2>
print soup.find('h2', text=pattern) == soup.find('h2')
#>> False
print soup.find('h2', text=pattern) == soup.find('h2').text
#>> True
print soup.find('h2', text=pattern).parent == soup.find('h2')
#>> True
Bruno Bronosky
quelle
Für mich soup.find('h2', text=pattern)gibt das Tag direkt, keine Notwendigkeit anzurufen .parent. In der Dokumentation heißt es auch, dass Sie den Parameter string( textin früheren Versionen) mit Argumenten kombinieren können, die Tags finden. In diesem Fall wird BeautifulSoup das Tag
Raffaem
4

Mit bs4 (Beautiful Soup 4) funktioniert der Versuch des OP genau wie erwartet:

from bs4 import BeautifulSoup
soup = BeautifulSoup("<h2> this is cool #12345678901 </h2>")
soup('h2',text=re.compile(r' #\S{11}'))

kehrt zurück [<h2> this is cool #12345678901 </h2>].

TC Proctor
quelle