Как получить текст в теге HTML, не получая дополнительный встроенный текст тега? - PullRequest
2 голосов
/ 29 декабря 2011

Я пытаюсь использовать BeautifulSoup для анализа списка адресов на странице.Когда я получаю тег с текстом и встроенными тегами, как мне только захватить текст из тега, не получая текста в любом дополнительном (более низком уровне) встроенном тексте?

Я используюpTag для перехода от местоположения к местоположению на странице .html, и вот код, с которым я имею дело:

Python, командная строка, я набираю: >>> pTag.address

и получаю следующую часть кода страницы:

<address>
                Some street address<br />City, State and ZIP<br />
<div class="phone">
                    (123) 456-7890
                </div>
</address>

Итак, чтобы схватить телефон, я набираю pTag.address.div.text и могу легко его получить.Я хотел бы получить адресный текст, который не вложен в другой тег.Я мог бы сделать re.compile с крайними случаями в случае, если нет информации о телефоне, но я надеялся на что-то более элегантное.

По сути, это то, что я хочу, даже лучше без использования тегов br:

Some street address<br />City, State and ZIP<br />

Ответы [ 5 ]

1 голос
/ 30 декабря 2011

Такое чувство, что это должно быть легче сделать, но лучшее, что я мог придумать, было:

>>> from BeautifulSoup import BeautifulSoup, NavigableString
>>> html = """
... <html><head></head><body>
... <address>
...                 Some street address<br />City, State and ZIP<br />
... <div class="phone">
...                     (123) 456-7890
...                 </div>
... </address>
... </body></html>
... """
>>> soup = BeautifulSoup(html)
>>> tag = soup.find('address')
>>> ' '.join(item for item in tag.contents
...          if isinstance(item, NavigableString)).strip()
u'Some street address City, State and ZIP'

EDIT

Вот альтернативное решение, использующее lxml :

>>> from lxml import etree
>>> tree = etree.HTML(html)
>>> tag = tree.xpath('//address')[0]
>>> ' '.join(tag.xpath('./text()')).strip()
'Some street address City, State and ZIP'
1 голос
/ 29 декабря 2011

Можно удалить элементы , используя метод extract:

>>> from BeautifulSoup import BeautifulSoup
>>> s = '<html><address>Some street address<br />City, State and ZIP<br /><div class="phone">(123) 456-7890</div></address></html>'
>>> soup = BeautifulSoup(s)
>>> soup.address.div.extract()
<div class="phone">(123) 456-7890</div>
>>> [e.extract() for e in soup.address.findAll('br')]
[<br />, <br />]
>>> soup.address.text
u'Some street addressCity, State and ZIP'
0 голосов
/ 29 декабря 2011

С помощью регулярного выражения это быстро, и полное извлечение возможно с легкостью:

import re

ss = '''a line
another line
<address>
    Some street address<br />City, State and ZIP<br />
    <div class="phone">
        (123) 456-7890
    </div>
    <glomo>
        Hello glomo
    </glomo>
</address>
end of text'''


def analyze(ss,tag,regx = re.compile('<([^ ]+)([^>]*)>(.*?)</\\1>',re.DOTALL)):
    extract = re.search('<(%s)[^>]*>(.*?)</\\1>' % tag,ss,re.DOTALL).group(2)
    li = []
    def trt(m):
        li.append((m.group(1),m.group(2),m.group(3).strip(' \t\r\n')))
    li.append(('','',regx.sub(trt,extract).strip('\r\n\t ')))
    return li

resu = analyze(ss,'address')
for el in  resu:
    print el

print
print resu[-1][2]

результат

('div', ' class="phone"', '(123) 456-7890')
('glomo', '', 'Hello glomo')
('', '', 'Some street address<br />City, State and ZIP<br />')

Some street address<br />City, State and ZIP<br />

Или помещение результатов в словарь:

def analyze(ss,tag,regx = re.compile('<([^ ]+)([^>]*)>(.*?)</\\1>',re.DOTALL)):
    extract = re.search('<(%s)[^>]*>(.*?)</\\1>' % tag,ss,re.DOTALL).group(2)
    di = {}
    def trt(m):
        di[m.group(1)] = (m.group(2),m.group(3).strip(' \t\r\n'))
    di[''] = ('',regx.sub(trt,extract).strip('\r\n\t '))
    return di

disu = analyze(ss,'address')
print "disu[''] ==",disu['']
print "disu['div'] ==",disu['div']
print (disu[x][1] for x in disu if 'phone' in disu[x][0]).next()

result

disu[''] == ('', 'Some street address<br />City, State and ZIP<br />')
disu['div'] == (' class="phone"', '(123) 456-7890')
(123) 456-7890

Функции ничего не возвращают (или, скорее, он возвращает None), тогда regx.sub(trt,extract) заменяет основатели тегов в extract на "", остается только текст в проверенном теге.

0 голосов
/ 29 декабря 2011

Если вы хотите попробовать PyQuery, вот еще один способ сделать это:

from pyquery import PyQuery
s = '<html><address>Some street address<br />City, State and ZIP<br /><div class="phone">(123) 456-7890</div></address></html>'
d = pyquery.PyQuery(s)
print d('address').text()
# 'Some street address City, State and ZIP (123) 456-7890'
print d('address').remove('*').text()
# 'Some street address City, State and ZIP'

Это удаляет все дочерние элементы из адреса перед извлечением текстового содержимого.

0 голосов
/ 29 декабря 2011

Я не думаю, что это возможно с только BeautifulSoup, скорее, вы можете удалить нежелательный текст (содержимое тега div class = "phone") из всего текста.Это может быть легко достигнуто через -

s = '<html><address>Some street address<br />City, State and ZIP<br /><div class="phone">(123) 456-7890</div></address></html>'
soup = BeautifulSoup(s)
s1 = soup.address.text                 // whole text
s2 = soup.address.div.text             // unwanted text
pos = string.find(s1, s2)
s1 = s1[:pos]                          // removing unwanted text
print s1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...