2011-01-08 2 views
0

Я совершенно новый для Python. У меня есть следующий код:SGML Parser в Python

class ExtractTitle(sgmllib.SGMLParser): 

def __init__(self, verbose=0): 

    sgmllib.SGMLParser.__init__(self, verbose) 

    self.title = self.data = None 

def handle_data(self, data): 

    if self.data is not None: 
    self.data.append(data) 

def start_title(self, attrs): 
self.data = [] 

def end_title(self): 

    self.title = string.join(self.data, "") 

raise FoundTitle # abort parsing! 

, который извлекает элемент заголовка из SGML, однако он работает только для одного заголовка. Я знаю, что мне нужно перегрузить unknown_starttag и unknown_endtag, чтобы получить все заголовки, но я все время ошибаюсь. Помоги мне, пожалуйста!!!

+0

что вы хотите сделать? проанализировать файл html? – virhilo

+0

У меня есть большой текстовый файл с SGML, где у меня есть теги формата <идентификатор сообщения = «100»> новый титул

новый текст

. Я хочу, чтобы мой код мог дать мне этот результат в другом файле: новый текст afg102

ответ

1

использование LXML вместо SGMLParser:

>>> posts = """ 
... <post id='100'> <title> xxxx </title> <text> <p> yyyyy </p> </text> </post> 
... <post id='101'> <title> new title1 </title> <text> <p> new text1 </p> </text> </post> 
... <post id='102'> <title> new title2 </title> <text> <p> new text2 </p> </text> </post> 
... """ 
>>> from lxml import html 
>>> parsed = html.fromstring(posts) 
>>> new_file = html.Element('div') 
>>> for post in parsed: 
...  post_id = post.attrib['id'] 
...  post_text = post.find('text').text_content() 
...  new_post = html.Element('post', id=post_id) 
...  new_post.text = post_text 
...  new_file.append(new_post) 
... 
>>> html.tostring(new_file) 
'<div><post id="100"> yyyyy </post><post id="101"> new text1 </post><post id="102"> new text2 </post></div>' 
>>> 
+0

благодарит за ваш ответ. Я пытаюсь извлечь из файла, поэтому я сделал: filexy = open (fileurl) и posts = filexy.read(), а затем ваш код. Однако по какой-то причине он показывает только один и тот же текст (т. Е. Он не перебирает все теги). У вас есть идея?Спасибо – afg102

+0

вы можете вставить какой-то пример документа? – virhilo

+0

ОК, я сделал это сейчас! спасибо за помощь ребятам :) – afg102

4

Beautiful Soup это один из способов можно разобрать это красиво (и это так, я бы всегда сделать это, если не было какой-то очень хорошая причина, чтобы не делать это так, я сам). Это намного проще и понятнее, чем использование SGMLParser.

>>> from BeautifulSoup import BeautifulSoup 
>>> soup = BeautifulSoup('''<post id='100'> <title> new title </title> <text> <p> new text </p> </text> </post>''') 
>>> soup('post') # soup.findAll('post') is equivalent 
[<post id="100"> <title> new title </title> <text> <p> new text </p> </text> </post>] 
>>> for post in soup('post'): 
...  print post.findChild('text') 
... 
<text> <p> new text </p> </text> 

Как только вы получите его на этом этапе, вы можете делать с ним разные вещи, в зависимости от того, как вы этого хотите.

>>> post = soup.find('post') 
>>> post 
<post id="100"> <title> new title </title> <text> <p> new text </p> </text> </post> 
>>> post_text = post.findChild('text') 
>>> post_text 
<text> <p> new text </p> </text> 

Возможно, вам захочется вычеркнуть HTML.

>>> post_text.text 
u'new text' 

Или, возможно, взглянуть на содержимое ...

>>> post_text.renderContents() 
' <p> new text </p> '] 
>>> post_text.contents 
[u' ', <p> new text </p>, u' '] 

Есть все виды вещей, которые вы могли бы хотеть сделать. Если вы более конкретны - особенно, предоставляя реальные данные - это помогает.

Когда дело доходит до манипулирования деревом, вы тоже можете это сделать.

>>> post 
<post id="100"> <title> new title </title> <text> <p> new text </p> </text> </post> 
>>> post.title # Just as good as post.findChild('title') 
<title> new title </title> 
>>> post.title.extract() # Throws it out of the tree and returns it but we have no need for it 
<title> new title </title> 
>>> post # title is gone! 
<post id="100"> <text> <p> new text </p> </text> </post> 
>>> post.findChild('text').replaceWithChildren() # Thrown away the <text> wrapping 
>>> post 
<post id="100"> <p> new text </p> </post> 

И так, в конце концов, вы бы что-то вроде этого:

>>> from BeautifulSoup import BeautifulSoup 
>>> soup = BeautifulSoup(''' 
... <post id='100'> <title> new title 100 </title> <text> <p> new text 100 </p> </text> </post> 
... <post id='101'> <title> new title 101 </title> <text> <p> new text 101 </p> </text> </post> 
... <post id='102'> <title> new title 102 </title> <text> <p> new text 102 </p> </text> </post> 
... ''') 
>>> for post in soup('post'): 
...  post.title.extract() 
...  post.findChild('text').replaceWithChildren() 
... 
<title> new title 100 </title> 
<title> new title 101 </title> 
<title> new title 102 </title> 
>>> soup 

<post id="100"> <p> new text 100 </p> </post> 
<post id="101"> <p> new text 101 </p> </post> 
<post id="102"> <p> new text 102 </p> </post> 
+0

Красивый суп медленно и мертв;) – virhilo

+0

@virhilo: «slow»? Возможно, в но во время разработки он имеет тенденцию быть блестяще быстрым, и это вообще важно сейчас. И «мертвый»? У него практически все, что нужно, нет ничего лишнего, чтобы это сделать. не имеет никакого активного развития (которое я вам даю) не беспокоит меня вообще. –

+0

Спасибо, ребята, он работает сейчас :) любые идеи о том, как писать результаты во внешний файл pls? – afg102

2

Ваш код сбрасывает "название" атрибут каждый раз, когда end_title() называется. Таким образом, название, в котором вы попадаете, является последним заголовком в документе.

Что вам нужно сделать, это сохранить список всех названий, которые вы найдете. В дальнейшем я также сбрасываю данные в None (так что вы не собираете текстовые данные за пределами элементов заголовка), и я использовал «» .join вместо string.join, потому что ваше использование последнего считается старомодным

class ExtractTitle(sgmllib.SGMLParser): 
    def __init__(self, verbose=0): 
    sgmllib.SGMLParser.__init__(self, verbose) 
    self.titles = [] 
    self.data = None 

    def handle_data(self, data): 
    if self.data is not None: 
     self.data.append(data) 

    def start_title(self, attrs): 
    self.data = [] 

    def end_title(self): 
    self.titles.append("".join(self.data)) 
    self.data = None 

и здесь он используется:

>>> parser = ExtractTitle() 
>>> parser.feed("<doc><rec><title>Spam and Eggs</title></rec>" + 
...    "<rec><title>Return of Spam and Eggs</title></rec></doc>") 
>>> parser.close() 
>>> parser.titles 
['Spam and Eggs', 'Return of Spam and Eggs'] 
>>> 
+0

он не работал таким образом: s ничего был сохранен – afg102

+0

Как это не сработало? Каков ваш тестовый пример и как он провалился? Я добавил пример, чтобы показать, что он работает для меня. –

+0

ok great: D У меня была небольшая ошибка в моем коде. Большое спасибо! Есть ли у вас какие-либо идеи по поводу другого вопроса, который я опубликовал? http://stackoverflow.com/questions/4634787/freqdist-with-nltk – afg102