我是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中提取title元素,但它仅适用于单个标题。我知道我必须重载unknown_starttag和unknown_endtag以获得所有标题,但我一直都弄错了。请帮帮我!!!
答案 0 :(得分: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>
答案 1 :(得分:2)
每次调用end_title()时,您的代码都会重置“title”属性。因此,您最终得到的标题是文档中的最后一个标题。
您需要做的是存储您找到的所有标题的列表。在下面,我还将数据重置为无(所以你不收集标题元素之外的文本数据)我用“”.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']
>>>
答案 2 :(得分: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>'
>>>