[BeautifulSoup] div.pre.next einen Wert zuweisen:

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
Crazed
User
Beiträge: 171
Registriert: Sonntag 18. Mai 2008, 11:44

Hallo,
Ich kann attributen innerhalb eines div-tags ohne Probleme neue Werte zuweisen.
Also z.b:

Code: Alles auswählen

div['title'] = 'newTitle'
Jetzt wollte ich aber auch den Inhalt des div-tags verändern. Und ich dachte da man ihn so ausgeben kann:

Code: Alles auswählen

print div.pre.next
//Das gibt nur den Inhalt ohne <pre> tags aus

Könnte ich ihn auch so zuweisen:

Code: Alles auswählen

div.pre.next = 'newContent'
Das geht aber anscheinend nicht, es schmeißt zwar keinen Fehler, aber der Inhalt wird nicht wirklich verändert. Weiß jemand mehr als ich?
Ich würde mich sehr freuen.

MfG,
CracKPod
mitsuhiko
User
Beiträge: 1790
Registriert: Donnerstag 28. Oktober 2004, 16:33
Wohnort: Graz, Steiermark - Österreich
Kontaktdaten:

Schnapp dir lieber lxml oder einen anderen ElementTree. Da macht das mehr Spaß.
TUFKAB – the user formerly known as blackbird
Crazed
User
Beiträge: 171
Registriert: Sonntag 18. Mai 2008, 11:44

Ich halte BeautifulSoup ehrlich gesagt für die einfachste Möglichkeit sowas zu realisieren und für html5lib habe ich keine gute Dokumentation gefunden und auch gehört das es
seeeehr langsam wäre.

Welches webscraping modul ist denn das beste von comfort und geschwindigkeit her?
Ideal wäre für mich wenn es BeautifulSoup einigermaßen von der Handhabung ähnelt.

Und bei lxml stört mich ein bisschen das man erstmal 2 zusätzliche packages noch installieren muss bevor man lxml überhaupt erst installieren und dann importieren kann.

Also alles in allem:

+Komfortable (BeautifulSoup ähnlich)
+Einigermaßen schnell (<niedrige Priorität)
+Einfach zu installiren (z.b via easy_install)


MfG,
CracKPod

*Der hofft keinen Rantz geschrieben zu haben*


PS:
Kennst du denn eine Möglichkeit mein Vorhaben zu realisieren.

PPS:
Ich weiß nicht wen ich darauf ansprechen soll, Ich kann aber zurzeit meinen echten nick
"CracKPod" nicht benutzen da ihn bereits ein anderer User belegt hat. Aber dieser scheint schon seit längerer Zeit inaktiv zu sein, wäre es möglich den Account zu löschen so das ich mir einen neuen Account auf meinen richtigen Nicknamen anlegen kann?
BlackJack

@Crazed: Du kannst Das nicht einfach per Zuweisung ändern, weil die Daten ja in den Objektbaum eingefügt werden müssen. Und die Zeichenketten, die man aus dem Baum bekommt, sind auch keine normalen `unicode`-Objekte, sondern welche die auch die ganzen Attribute und Methoden zum Navigieren besitzen.

Die Lösung ist die `repleceWith()`-Methode:

Code: Alles auswählen

In [271]: soup.div.pre.next
Out[271]: u'foo'

In [272]: type(soup.div.pre.next)
Out[272]: <class BeautifulSoup.NavigableString>

In [273]: soup.div.pre.next.replaceWith('bar')

In [274]: soup.div.pre.next
Out[274]: u'bar'
lunar

Welches webscraping modul ist denn das beste von comfort und geschwindigkeit her?
lxml.html

Das ist nicht BeautifulSoup, es ist noch nicht mal ähnlich, aber wenn du BS willst, dann musst du eben auch BS nutzen. Wenn du bereit bist, BS zu vergessen, erhältst du mit lxml ein Modul, welches nicht nur schneller und speicherschonender ist, sondern auch eine angenehmer und verständliche API mit mächtigen Features wie XPATH und CSS Selektoren kombiniert, und Scraping damit um einiges angenehmer macht als BS.
PPS:
Ich weiß nicht wen ich darauf ansprechen soll, Ich kann aber zurzeit meinen echten nick
"CracKPod" nicht benutzen da ihn bereits ein anderer User belegt hat. Aber dieser scheint schon seit längerer Zeit inaktiv zu sein, wäre es möglich den Account zu löschen so das ich mir einen neuen Account auf meinen richtigen Nicknamen anlegen kann?
Wohl kaum.
Crazed
User
Beiträge: 171
Registriert: Sonntag 18. Mai 2008, 11:44

Hey lunar.

Oke, Ich möchte mich mit lxml.html befassen.
Habe aber vorher ein paar Fragen.

Also das was ich jetzt gelesen habe.

BeautifulSoup ist ein modul um Informationen aus Webseiten zu filtern. BeautifulSoup benutzt dabei eine bestimmte Struktur und teilt das HTML-Dokument in dieser auf so dass man dann nachher z.b mittles "div.pre.next" auf bestimmte Teil des Sources über Python zugreifen kann.

ElementTree ist eine alternative Struktur dazu mit besserer und komfortabler Handhabung.

lxml ist ein xml Parser der intern diesen ElementTree benutzt und als Parser die libxml2 und libxslt benutzt. Jetzt kam vor einiger Zeit zu lxml eine sub-klasse dazu die html heißt, also lxml.html.

Diese sub-klasse parst HTML-Sourcecode, genauso wie BeautifulSoup und benutzt ebenfalls wie die primär-klasse lxml den ElementTree um die HTML-Datei strukturiert darstellen zu können, so dass man nachher bequem mittels Python darauf zugreifen kann.

Das parsen der xml und html Dokumente läuft dabei komplett über die in c geschrieben libraries libxml2 und libxslt ab und bringt dadurch natürlich einen signifikanten Geschwindigkeitsvorteil gegenüber komplett in Python geschrieben Parsern.

Damit lxml (.html) nun in Python benutzt werden kann brauch man natürlich diese libraries. Diese libraries werden bei der Installation über EasyInstall kompiliert und benötigen dabei die Python Entwicklungs Dateien (Sourcecode) und die libxslt Entwicklungs Dateien.

Habe ich das soweit richtig verstanden? Mir ist es immer wichtig auch das zu verstehen was ich eigentlich gerade tue und die Hintergründe ein bisschen zu kennen.

MfG,
CracKPod
lunar

Crazed hat geschrieben:lxml ist ein xml Parser der intern diesen ElementTree benutzt und als Parser die libxml2 und libxslt benutzt. Jetzt kam vor einiger Zeit zu lxml eine sub-klasse dazu die html heißt, also lxml.html.
Das ist keine "Sub-Klasse", das ist ein Modul.
Damit lxml (.html) nun in Python benutzt werden kann brauch man natürlich diese libraries. Diese libraries werden bei der Installation über EasyInstall kompiliert und benötigen dabei die Python Entwicklungs Dateien (Sourcecode) und die libxslt Entwicklungs Dateien.
Nicht die Bibliotheken werden kompiliert, sondern nur die Python-Bindings. Die Bibliotheken liegen in der Regel schon binär vor. Zumindest ist es nicht Aufgabe von easy_install, den Paketmanager deines Systems zu ersetzen ;)
Crazed
User
Beiträge: 171
Registriert: Sonntag 18. Mai 2008, 11:44

Python-Bindings?

Wie soll ich mir das vorstellen? Ist das sowas wie ein Zwischenstück?

Also : *ASCII-Art Profi* ^^
Python -> Binding -> Libraries (libxml2 , libxslt)

Sind die Bindings dann in C geschrieben?
Höchstwahrscheinlich brauche ich deswegen ja auch die development packages von python damit man dieses Zwischenstück kompilieren kann, oder?

Danke für die hervorragende Hilfe.

MfG,
CracKPod
lunar

Crazed hat geschrieben:Wie soll ich mir das vorstellen? Ist das sowas wie ein Zwischenstück?
Ja.
Sind die Bindings dann in C geschrieben?
Teils direkt in C, teils in cython, einer Untermenge von Python, die anschließend in entsprechenden C-Code konvertiert und kompiliert wird.
Höchstwahrscheinlich brauche ich deswegen ja auch die development packages von python damit man dieses Zwischenstück kompilieren kann, oder?
Ja.
Crazed
User
Beiträge: 171
Registriert: Sonntag 18. Mai 2008, 11:44

Wenn du mir jetzt eventuell noch ein Anfänger freundliches Tutorial für das modul geben würdest wäre es perfekt, ist aber nicht zwingend nötig.

Ich müsste mir dann nur die offiziele ElementTree dokumentation ansehen um nachher mit lxml.html arbeiten zu können, oder?

MfG,
CrackPod
lunar

Crazed hat geschrieben:Wenn du mir jetzt eventuell noch ein Anfänger freundliches Tutorial für das modul geben würdest wäre es perfekt, ist aber nicht zwingend nötig.
Schau doch mal auf http://codespeak.net/lxml/ vorbei. Da findest du ein Tutorial zur Etree-API, eine Dokumentation über die Erweiterungen der lxml.etree Implementierung, und umfangreiche Dokumente über lxml.html, lxml.cssselect und XPATH Unterstützung.
Crazed
User
Beiträge: 171
Registriert: Sonntag 18. Mai 2008, 11:44

Also ist lxlml.extree eine erweiterte Form ElementTree die diesem aber noch sehr ähnelt, richtig?
lunar

Crazed hat geschrieben:Also ist lxlml.extree eine erweiterte Form ElementTree die diesem aber noch sehr ähnelt, richtig?
Ja. lxml.etree implementiert die etree-API vollständig, erweitert sie aber um nützliche Features.
Crazed
User
Beiträge: 171
Registriert: Sonntag 18. Mai 2008, 11:44

Hey, Danke für den Tipp, lxml.html macht einen sehr geordneten Eindruck.

Leider habe ich trotzdem (wie erwartet) ein paar Probleme.

Code: Alles auswählen

<html>
    <head>
        <title>Test</title>
    </head>
    <body>
        <div id = "testdiv">
        </div>
        <div id = "main">
            <h1>Text123YX</h1>
            <div class = "section_info>
                <h4><span>Info: Text123YX</span></h4>
            </div>
        </div>
    </body>
</html>
So angeommen ich wollte jetzt an "<h4><span>Info: Text123YX</span></h4>"

Dann müsste ich folgendes machen:

Code: Alles auswählen

import lxml.html

html = lxml.html.fromstring('''
<html>
    <head>
        <title>Test</title>
    </head>
    <body>
        <div id = "testdiv">
        </div>
        <div id = "main">
            <h1>Text123YX</h1>
            <div class = "section_info>
                <h4><span>Info: Text123YX</span></h4>
            </div>
        </div>
    </body>
</html>
''')

print html.body[1][0].text
Ist das nicht ein bisschen unschön? Mache ich es falsch?

MfG,
CracKPod
lunar

Ist das HTML so kaputt, oder ist das nur ein Typo?

Angenommen, letzteres ist der Fall, und du hast das Anführungszeichen hinter "section_info" tatsächlich nur vergessen:

Code: Alles auswählen

import lxml.html

tree = lxml.html.fromstring('''
<html>
    <head>
        <title>Test</title>
    </head>
    <body>
        <div id = "testdiv">
        </div>
        <div id = "main">
            <h1>Text123YX</h1>
            <div class = "section_info">
                <h4><span>Info: Text123YX</span></h4>
            </div>
        </div>
    </body>
</html>
''')

# entspricht deinem Index-Zugriff
print tree.cssselect('div .section_info')[0].text
# den Text der Überschrift zu extrahieren
# mit CSS Selektoren
print tree.cssselect('div .section_info > h4')[0].text_content()
# oder mit xpath und Zugriff über id
print tree.get_element_by_id('main').xpath('./div/h4/*/text()')[0]
Antworten