Соскоб с BeautifulSoup и несколькими абзацами - PullRequest
9 голосов
/ 30 ноября 2011

Я пытаюсь вычеркнуть речь с сайта, используя BeautifulSoup.Однако я сталкиваюсь с проблемами, поскольку речь делится на множество разных параграфов.Я чрезвычайно новичок в программировании, и мне сложно понять, как с этим справиться.HTML-код страницы выглядит следующим образом:

<span class="displaytext">Thank you very much. Mr. Speaker, Vice President Cheney, 
Members of Congress, distinguished guests, fellow citizens: As we gather tonight, our Nation is    
at war; our economy is in recession; and the civilized world faces unprecedented dangers. 
Yet, the state of our Union has never been stronger.
<p>We last met in an hour of shock and suffering. In 4 short months, our Nation has comforted the victims, 
begun to rebuild New York and the Pentagon, rallied a great coalition, captured, arrested, and  
rid the world of thousands of terrorists, destroyed Afghanistan's terrorist training camps, 
saved a people from starvation, and freed a country from brutal oppression. 
<p>The American flag flies again over our Embassy in Kabul. Terrorists who once occupied 
Afghanistan now occupy cells at Guantanamo Bay. And terrorist leaders who urged followers to 
sacrifice their lives are running for their own.

Это продолжается некоторое время, с несколькими тегами абзаца.Я пытаюсь извлечь весь текст из диапазона.

Я пробовал несколько разных способов получить текст, но оба не смогли получить нужный мне текст.

Первое, что я попробовал:

import urllib2,sys
from BeautifulSoup import BeautifulSoup, NavigableString

address = 'http://www.presidency.ucsb.edu/ws/index.php?pid=29644&st=&st1=#axzz1fD98kGZW'
html = urllib2.urlopen(address).read()

soup = BeautifulSoup(html)
thespan = soup.find('span', attrs={'class': 'displaytext'})
print thespan.string

, что дает мне:

Мистер.Спикер, вице-президент Чейни, члены Конгресса, уважаемые гости, сограждане: сегодня вечером, когда мы собираемся, наша страна находится в состоянии войны;наша экономика находится в рецессии;и цивилизованный мир сталкивается с беспрецедентными опасностями.Тем не менее, состояние нашего Союза никогда не было сильнее.

Это часть текста до первого тега абзаца.Затем я попытался:

import urllib2,sys
from BeautifulSoup import BeautifulSoup, NavigableString

address = 'http://www.presidency.ucsb.edu/ws/index.php?pid=29644&st=&st1=#axzz1fD98kGZW'
html = urllib2.urlopen(address).read()

soup = BeautifulSoup(html)
thespan = soup.find('span', attrs={'class': 'displaytext'})
for section in thespan:
     paragraph = section.findNext('p')
     if paragraph and paragraph.string:
         print '>', paragraph.string
     else:
         print '>', section.parent.next.next.strip()

Это дало мне текст между тегом первого абзаца и тегом второго абзаца.Итак, я ищу способ получить весь текст, а не только разделы.

Ответы [ 3 ]

8 голосов
/ 30 ноября 2011
import urllib2,sys
from BeautifulSoup import BeautifulSoup

address = 'http://www.presidency.ucsb.edu/ws/index.php?pid=29644&st=&st1=#axzz1fD98kGZW'
soup = BeautifulSoup(urllib2.urlopen(address).read())

span = soup.find("span", {"class":"displaytext"})  # span.string gives you the first bit
paras = [x.contents[0] for x in span.findAllNext("p")]  # this gives you the rest
# use .contents[0] instead of .string to deal with last para that's not well formed

print "%s\n\n%s" % (span.string, "\n\n".join(paras))

Как указано в комментариях, приведенное выше не очень хорошо работает, если теги <p> содержат больше вложенных тегов.Это может быть решено с помощью:

paras = ["".join(x.findAll(text=True)) for x in span.findAllNext("p")]

Однако, это не слишком хорошо работает с последним <p>, у которого нет закрывающего тега.Хакерский обходной путь будет относиться к этому по-другому.Например:

import urllib2,sys
from BeautifulSoup import BeautifulSoup

address = 'http://www.presidency.ucsb.edu/ws/index.php?pid=29644&st=&st1=#axzz1fD98kGZW'
soup = BeautifulSoup(urllib2.urlopen(address).read())
span = soup.find("span", {"class":"displaytext"})  
paras = [x for x in span.findAllNext("p")]

start = span.string
middle = "\n\n".join(["".join(x.findAll(text=True)) for x in paras[:-1]])
last = paras[-1].contents[0]
print "%s\n\n%s\n\n%s" % (start, middle, last)
2 голосов
/ 30 ноября 2011

Вот как это будет сделано с lxml:

import lxml.html as lh

tree = lh.parse('http://www.presidency.ucsb.edu/ws/index.php?pid=29644&st=&st1=#axzz1fD98kGZW')

text = tree.xpath("//span[@class='displaytext']")[0].text_content()

В качестве альтернативы, ответы на этот вопрос посвящены тому, как добиться того же с помощью Beautifulsoup: BeautifulSoup- простой способ получения содержимого без HTML

Вспомогательная функция из принятого ответа:

def textOf(soup):
    return u''.join(soup.findAll(text=True))
0 голосов
/ 30 ноября 2011

Вы должны попробовать:

soup.span.renderContents()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...