Frage

Ich bin mit Schöner Suppe zu extrahieren ‚Inhalt‘ von Web-Seiten. Ich kenne einige Leute diese Frage gestellt haben vor und sie waren alle spitze auf schöne Suppe und das ist, wie ich damit angefangen hat.

Ich konnte erfolgreich die meisten Inhalte bekommen, aber ich laufe in einige Herausforderungen mit Tags, die einen Teil des Inhalts sind. (Ich beginne mit einer grundlegenden Strategie weg von: wenn es mehr als x-Zeichen in einem Knoten sind, dann ist es Inhalt). Nehmen wir den HTML-Code unten als Beispiel:

<div id="abc">
    some long text goes <a href="/"> here </a> and hopefully it 
    will get picked up by the parser as content
</div>

results = soup.findAll(text=lambda(x): len(x) > 20)

Wenn ich den obigen Code verwenden, um den Langtext zu bekommen, bricht sie (der identifizierten Text aus starten ‚und hoffentlich ..‘) an dem Tags. Also habe ich versucht, den Tag mit Klartext zu ersetzen, wie folgt:

anchors = soup.findAll('a')

for a in anchors:
  a.replaceWith('plain text')

Das oben nicht funktioniert, weil schöne Suppe die Zeichenfolge als NavigableString einfügt und das verursacht das gleiche Problem, wenn ich findAll mit der len (x) verwenden> 20. Ich reguläre Ausdrücke verwenden, können Sie die HTML als Klartext zu analysieren zuerst, lösche alle unerwünschten Tags und dann schöne Suppe nennen. Aber ich mag zweimal verarbeiten den gleichen Inhalt vermeiden - ich versuche, diese Seiten zu analysieren, damit ich einen Schnipsel von Inhalt für einen bestimmten Link zeigen (sehr ähnlich wie Facebook) - und wenn alles mit Schöner Suppe getan, ich vermute, es wird schneller sein.

Also meine Frage: Gibt es einen Weg, um ‚klaren Tags‘ und ersetzen Sie sie mit ‚Klartext‘ mit Schöner Suppe. Wenn nicht, was bester Weg, dies zu tun?

Vielen Dank für Ihre Anregungen!

Update: Alex Code funktionierte sehr gut für die Probe Beispiel. Ich habe auch verschiedene Grenzfälle, und sie alle haben gut funktioniert (mit der Modifikation unten) versucht. Also gab ich ihm einen Schuss auf einer realen Leben Website und ich laufe in Fragen, die Rätsel mir.

import urllib
from BeautifulSoup import BeautifulSoup

page = urllib.urlopen('http://www.engadget.com/2010/01/12/kingston-ssdnow-v-dips-to-30gb-size-lower-price/')

anchors = soup.findAll('a')
i = 0
for a in anchors:
    print str(i) + ":" + str(a)
    for a in anchors:
        if (a.string is None): a.string = ''
        if (a.previousSibling is None and a.nextSibling is None):
            a.previousSibling = a.string
        elif (a.previousSibling is None and a.nextSibling is not None):
            a.nextSibling.replaceWith(a.string + a.nextSibling)
        elif (a.previousSibling is not None and a.nextSibling is None):
            a.previousSibling.replaceWith(a.previousSibling + a.string)
        else:
            a.previousSibling.replaceWith(a.previousSibling + a.string + a.nextSibling)
            a.nextSibling.extract()
    i = i+1

Wenn ich den obigen Code ausführen, ich die folgende Fehlermeldung erhalten:

0:<a href="http://www.switched.com/category/ces-2010">Stay up to date with 
Switched's CES 2010 coverage</a>
Traceback (most recent call last):
  File "parselink.py", line 44, in <module>
  a.previousSibling.replaceWith(a.previousSibling + a.string + a.nextSibling)
 TypeError: unsupported operand type(s) for +: 'Tag' and 'NavigableString'

Wenn ich den HTML-Code aussehen ‚, zu dem neuesten Stand bleiben ..“ hat keine vorherigen Geschwister (ich habe nicht, wie vorherigen Geschwister gearbeitet, bis ich Alex Code sah und auf der Grundlage meiner Prüfung sieht es aus wie es sucht . ‚text‘ vor dem Tag) Also, wenn es keine vorherige Geschwister ist, bin ich überrascht, dass es nicht geht, durch die, wenn Logik der a.previousSibling ist None und a;. nextSibling ist keine

Könnten Sie bitte lassen Sie mich wissen, was ich falsch mache?

-ecognium

War es hilfreich?

Lösung

Ein Ansatz, dass die Arbeiten für Ihr spezielles Beispiel ist:

from BeautifulSoup import BeautifulSoup

ht = '''
<div id="abc">
    some long text goes <a href="/"> here </a> and hopefully it 
    will get picked up by the parser as content
</div>
'''
soup = BeautifulSoup(ht)

anchors = soup.findAll('a')
for a in anchors:
  a.previousSibling.replaceWith(a.previousSibling + a.string)

results = soup.findAll(text=lambda(x): len(x) > 20)

print results

welche aussendet

$ python bs.py
[u'\n    some long text goes  here ', u' and hopefully it \n    will get picked up by the parser as content\n']

Natürlich, werden Sie wahrscheinlich ein bisschen mehr darauf achten müssen, das heißt, was ist, wenn es gibt keine a.string, oder wenn a.previousSibling None ist - Sie werden geeignete if Aussagen müssen kümmern solche Sonderfälle. Aber ich hoffe, dass diese allgemeine Idee kann Ihnen helfen. (In der Tat können Sie auf auch verschmelzen die nächsten Geschwister, wenn es eine Zeichenfolge ist - nicht sicher, wie das spielt mit Heuristiken len(x) > 20, aber zum Beispiel sagen, dass Sie zwei 9-Zeichenkette mit einem <a> einer 5-Zeichenkette in der Mitte enthält, vielleicht werden Sie das Los als „23-Zeichen-String“ holen? ich kann nicht sagen, weil ich nicht verstehen, die Motivation für Ihre Heuristik).

Ich stelle mir vor, dass neben <a> Tags Sie wollen auch andere entfernen, wie <b> oder <strong>, vielleicht <p> und / oder <br>, etc ...? Ich denke, auch dies hängt davon ab, was die eigentliche Idee hinter der Heuristik ist!

Andere Tipps

Als ich versuchte, Flatten -Tags im Dokument, auf diese Weise, die gesamte Inhalt Tags würde zu seinem übergeordneten Knoten an Ort und Stelle hochgezogen werden (Ich wollte den Inhalt eines reduzieren p -Tag mit allen Unter Absätze, Listen, div und Spanne , etc. im Inneren aber loszuwerden, die Stil und < strong> Schrift Tags und einige schreckliche Wort-to-hTML-Generator Reste), fand ich es eher mit BeautifulSoup selbst zu tun kompliziert, da extract () auch den Inhalt entfernt und replaceWith () akzeptiert unfortunatetly nicht keine als Argument. Nach einigen wilden Rekursion Experimenten, entschied ich mich schließlich entweder reguläre Ausdrücke verwendet vor oder nach der Verarbeitung des Dokuments mit BeautifulSoup mit folgenden Methode:

import re
def flatten_tags(s, tags):
   pattern = re.compile(r"<(( )*|/?)(%s)(([^<>]*=\\\".*\\\")*|[^<>]*)/?>"%(isinstance(tags, basestring) and tags or "|".join(tags)))
   return pattern.sub("", s)

Die -Tags Argument wird entweder ein einzelner Tag oder eine Liste von Tags abgeflacht werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top