2011-01-08 9 views
0

Ich bin völlig neu in Python. Ich habe den folgenden Code:SGML Parser in 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! 

die den Titel Element von SGML extrahiert, aber es ist nur für einen einzelnen Titel funktioniert. Ich weiß, ich muss das "unknown_starttag" und das "unknown_endtag" überladen, um alle Titel zu bekommen, aber ich bekomme es immer falsch. Hilf mir bitte!!!

+0

was Sie tun möchten? HTML-Datei analysieren? – virhilo

+0

Ich habe eine große Textdatei mit SGML, wo ich Tags von Format habe neue Titel

neuer Text

. Ich möchte, dass mein Code in der Lage ist, mir dieses Ergebnis in einer anderen Datei zu geben: neuer Text afg102

Antwort

1

Verwendung lxml statt 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

danke für Ihre Antwort. Ich versuche, aus einer Datei zu extrahieren, also tat ich: filexy = open (fileurl) und posts = filexy.read() und dann Ihren Code. Aus irgendeinem Grund zeigt es jedoch nur den gleichen Text (d. H. Es durchläuft nicht alle Tags). Haben Sie eine Idee?Danke – afg102

+0

könnten Sie ein Beispieldokument einfügen? – virhilo

+0

ok ich habe es jetzt gemacht! Danke für die Hilfe Jungs :) – afg102

4

Beautiful Soup ist ein Weg, man konnte es gut analysieren (und es ist so, wie ich würde immer es tun, es sei denn, es einige sehr gute Gründe nicht zu tun es so, selbst). Es ist viel einfacher und lesbarer als mit 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> 

Sobald Sie es in diesem Stadium haben, können Sie verschiedene Dinge damit tun, je nachdem, wie Sie es wollen.

>>> 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> 

Sie könnten HTML strippen wollen.

>>> post_text.text 
u'new text' 

Oder schauen Sie vielleicht auf den Inhalt ...

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

Es gibt alle Arten von Dingen, die Sie tun wollen könnte. Wenn Sie genauer sind - insbesondere, wenn Sie echte Daten bereitstellen -, hilft es.

Wenn es darum geht, den Baum zu manipulieren, können Sie das auch tun.

>>> 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> 

Und so, schließlich, würden Sie so etwas wie dieses:

>>> 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

Schöne Suppe ist langsam und tot;) – virhilo

+0

@virhilo: "langsam"? Vielleicht in Verarbeitung ist es, aber in der Entwicklungszeit neigt es dazu, brillant schnell zu sein. Und das ist im Allgemeinen was jetzt zählt. Und "tot"? Es hat praktisch alles, was gewünscht wird, es gibt nicht viel extra zu tun * dafür * Die Tatsache, dass es Ich habe keine aktive Entwicklung (was ich Ihnen zugestehen werde) stört mich überhaupt nicht. –

+0

Danke Jungs, es funktioniert jetzt :) irgendwelche Ideen, wie Sie die Ergebnisse in eine externe Datei schreiben pls? – afg102

2

Der Code setzt den "Titel" jedes Mal das end_title Attribut() aufgerufen wird. Der Titel, mit dem Sie enden, ist daher der letzte Titel im Dokument.

Was Sie tun müssen, ist eine Liste aller gefundenen Titel zu speichern. Im Folgenden setze ich auch Daten auf None zurück (so dass Sie keine Textdaten außerhalb von Titelelementen sammeln) und ich habe ".join" anstelle von "string.join" verwendet, weil Ihre Verwendung des letzteren als altmodisch gilt

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 

und hier ist es im Einsatz:

>>> 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

es funktioniert nicht so: s nichts wurde gespeichert – afg102

+0

Wie hat es nicht funktioniert? Was ist dein Testfall und wie ist er ausgefallen? Ich habe ein Beispiel hinzugefügt, um zu zeigen, dass es für mich funktioniert. –

+0

ok toll: D Ich hatte einen kleinen Fehler in meinem Code. Danke vielmals! Hast du eine Idee zu einer anderen Frage, die ich geschrieben habe? http://stackoverflow.com/questions/4634787/freqdist-with-nltk – afg102