2013-05-30 11 views
19

staram się wydobyć „To jest mój tekst” z następującego kodu HTML:Python BeautifulSoup tekst ekstrakt pomiędzy elementem

<html> 
<body> 
<table> 
    <td class="MYCLASS"> 
     <!-- a comment --> 
     <a hef="xy">Text</a> 
     <p>something</p> 
     THIS IS MY TEXT 
     <p>something else</p> 
     </br> 
    </td> 
</table> 
</body> 
</html> 

Próbowałem to w ten sposób:

soup = BeautifulSoup(html) 

for hit in soup.findAll(attrs={'class' : 'MYCLASS'}): 
    print hit.text 

Ale mam cały tekst pomiędzy wszystkimi zagnieżdżonymi tagami oraz komentarzem.

Czy ktoś może mi pomóc, aby uzyskać z tego "TAK MÓJ TEKST"?

Odpowiedz

9

Zastosowanie .children zamiast:

from bs4 import NavigableString, Comment 
print ''.join(unicode(child) for child in hit.children 
    if isinstance(child, NavigableString) and not isinstance(child, Comment)) 

Tak, to jest trochę tańca.

wyjściowa:

>>> for hit in soup.findAll(attrs={'class' : 'MYCLASS'}): 
...  print ''.join(unicode(child) for child in hit.children 
...   if isinstance(child, NavigableString) and not isinstance(child, Comment)) 
... 




     THIS IS MY TEXT 
+0

To by zwróciło "u" \ n komentarz \ nTekst \ nCoś coś \ n TO JEST MÓJ TEKST \ n coś innego \ n'' lub 'u'a commentTextsomethingTHIS IS IS MOJE TEKSTY else else'' które mają więcej tekstu niż wymagane. –

+0

@CristianCiupitu: Oczywiście, masz rację, nie zwracając uwagi tutaj. Aktualizacja. –

+0

To jest jedyne rozwiązanie, które nie zależy od tego, czy tekst jest w sekwencji lub relacji pozycyjnej do konkretnego innego, ale raczej wyciąga cały tekst z określonego znacznika/elementu podczas ignorowania tekstu (lub innej zawartości) znaczników/elementów podrzędnych. Dzięki! To jest niezręczne, ale działa i rozwiązuje mój problem (nie jestem OP, ale miałem podobną potrzebę). – geewiz

11

Można użyć .contents:

>>> for hit in soup.findAll(attrs={'class' : 'MYCLASS'}): 
...  print hit.contents[6].strip() 
... 
THIS IS MY TEXT 
+3

Dzięki, ale tekst nie zawsze jest w tym samym miejscu. Czy to i tak zadziała? –

+0

@ ɥɔǝnqɹǝƃloɥ Niestety nie. Być może używaj odpowiedzi innych osób. – TerryA

+0

Co oznacza liczba '6'? – User

24

Dowiedz się więcej o tym, jak poruszać through the parse tree in BeautifulSoup. Drzewo analizy ma wartości tags i NavigableStrings (ponieważ TO JEST TEKST). Przykładem

from BeautifulSoup import BeautifulSoup 
doc = ['<html><head><title>Page title</title></head>', 
     '<body><p id="firstpara" align="center">This is paragraph <b>one</b>.', 
     '<p id="secondpara" align="blah">This is paragraph <b>two</b>.', 
     '</html>'] 
soup = BeautifulSoup(''.join(doc)) 

print soup.prettify() 
# <html> 
# <head> 
# <title> 
# Page title 
# </title> 
# </head> 
# <body> 
# <p id="firstpara" align="center"> 
# This is paragraph 
# <b> 
#  one 
# </b> 
# . 
# </p> 
# <p id="secondpara" align="blah"> 
# This is paragraph 
# <b> 
#  two 
# </b> 
# . 
# </p> 
# </body> 
# </html> 

Aby przesunąć w dół drzewa parsującej masz contents i string.

  • zawartość jest uporządkowana lista Tag i NavigableString obiektów zawarty w elemencie strony

  • jeśli znacznik ma tylko jeden węzeł podrzędny, a węzeł dziecko jest string, węzeł podrzędny jest dostępny jako tag.string, a także tag.contents [0]

Dla powyższego, to znaczy można uzyskać

soup.b.string 
# u'one' 
soup.b.contents[0] 
# u'one' 

Dla wielu dzieci węzłów, można mieć na przykład

pTag = soup.p 
pTag.contents 
# [u'This is paragraph ', <b>one</b>, u'.'] 

więc tutaj można grać z contents i uzyskać zawartość w pożądanym indeksie.

Możesz także powtórzyć tag, jest to skrót. Na przykład,

for i in soup.body: 
    print i 
# <p id="firstpara" align="center">This is paragraph <b>one</b>.</p> 
# <p id="secondpara" align="blah">This is paragraph <b>two</b>.</p> 
+0

' hit.string' to 'Brak' i' hit.contents [0] 'to' u '\ n'', więc proszę podać odpowiedź na przykład z pytania. –

+0

, więc możesz grać z zawartością i uzyskać zawartość w wybranym indeksie. – octoback

+0

jest odpowiedzią na pytanie – octoback

0

BeautifulSoup documentation stanowi przykład o usuwanie przedmiotów z dokumentu przy użyciu metody usuwania.W poniższym przykładzie celem jest usunąć wszystkie komentarze z dokumentu:

usuwanie elementów

Gdy masz odniesienie do elementu, można zgrać go z drzewa z ekstraktem metoda. Ten kod usuwa wszystkie komentarze z dokumentu:

from BeautifulSoup import BeautifulSoup, Comment 
soup = BeautifulSoup("""1<!--The loneliest number--> 
        <a>2<!--Can be as bad as one--><b>3""") 
comments = soup.findAll(text=lambda text:isinstance(text, Comment)) 
[comment.extract() for comment in comments] 
print soup 
# 1 
# <a>2<b>3</b></a> 
6

Krótka odpowiedź: soup.findAll('p')[0].next

realna odpowiedź: Potrzebny jest niezmienny punkt odniesienia, z którego można dostać się do celu.

Wspominasz w swoim komentarzu do odpowiedzi Haidro, że tekst, który chcesz, nie zawsze jest w tym samym miejscu. Znajdź sens, w którym znajduje się w tym samym miejscu w stosunku do jakiegoś elementu. Następnie wymyśl sposób, w jaki BeautifulSoup będzie nawigował po drzewie analizy po tej niezmiennej ścieżce.

Na przykład w kodzie HTML podanym w oryginalnym wpisie tekst docelowy pojawia się bezpośrednio po elemencie pierwszego akapitu, a ten akapit nie jest pusty. Od findAll('p') znajdzie elementy akapitu, soup.find('p')[0] będzie pierwszym elementem akapitu.

Można w tym przypadku użyć soup.find('p'), ale soup.findAll('p')[n] jest bardziej ogólny, ponieważ być może twój rzeczywisty scenariusz wymaga piątego akapitu lub czegoś podobnego.

Atrybut pola będzie następnym parsowanym elementem drzewa, w tym dziećmi. Tak więc soup.findAll('p')[0].next zawiera tekst akapitu, a soup.findAll('p')[0].next.next zwróci twój cel w podanym kodzie HTML.

9

z własnego obiektu zupy:

soup.p.next_sibling.strip() 
  1. chwycić <str> bezpośrednio soup.p * (to zależy od tego, że był pierwszym <p> w drzewie parsowania)
  2. następnie użyj next_sibling na obiekcie znacznika zwracanym przez soup.p, ponieważ pożądany tekst jest zagnieżdżony na tym samym poziomie drzewa analizy, co <p>
  3. .strip() jest tylko metoda Python Str usunąć początkowe i końcowe białe znaki

* inaczej tylko find element za pomocą wyboru filter (ów)

w tłumacza wygląda to mniej więcej tak:

In [4]: soup.p 
Out[4]: <p>something</p> 

In [5]: type(soup.p) 
Out[5]: bs4.element.Tag 

In [6]: soup.p.next_sibling 
Out[6]: u'\n  THIS IS MY TEXT\n  ' 

In [7]: type(soup.p.next_sibling) 
Out[7]: bs4.element.NavigableString 

In [8]: soup.p.next_sibling.strip() 
Out[8]: u'THIS IS MY TEXT' 

In [9]: type(soup.p.next_sibling.strip()) 
Out[9]: unicode 
+0

Czy możesz dodać nieco bardziej wyjaśniający tekst o tym, jak odpowiada na to pytanie? –

+0

zadowolony! (patrz wyżej) –

0
soup = BeautifulSoup(html) 
for hit in soup.findAll(attrs={'class' : 'MYCLASS'}): 
    hit = hit.text.strip() 
    print hit 

to drukowanie: to jest mój tekst Spróbuj tego ..