Qt: Kompletten Quelltext von Webkit bekommen

Python und das Qt-Toolkit, erstellen von GUIs mittels des Qt-Designers.
Benutzeravatar
snafu
User
Beiträge: 5466
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Donnerstag 23. April 2009, 09:19

Hi,

ich möchte den Quelltext einer besuchen Seite ausgeben lassen:

Code: Alles auswählen

from PyQt4 import QtCore, QtGui, QtWebKit
import sys

app = QtGui.QApplication(sys.argv)

webview = QtWebKit.QWebView()
webview.load(QtCore.QUrl('http://www.google.de/'))

def print_content():
    print webview.page().mainFrame().toHtml()

QtCore.QObject.connect(webview, QtCore.SIGNAL('urlChanged(QUrl)'), print_content)
    
webview.show()

app.exec_()
Mir wird hier allerdings nur der head-Bereich angezeigt:

Code: Alles auswählen

<html><head><meta http-equiv="content-type" content="text/html; charset=UTF-8"><title>Google</title></head></html>
Weiß jemand wie ich an den kompletten Quelltext komme?
shcol (Repo | Doc | PyPi)
jerch
User
Beiträge: 1630
Registriert: Mittwoch 4. März 2009, 14:19

Donnerstag 23. April 2009, 10:45

Das ist prinzipiell der richtige Weg, nur ist die Seite zum Zeitpunkt des Url-Changes nur teilweise geladen. Daher solltest Du besser das loadFinished-Signal benutzen:

Code: Alles auswählen

...
QtCore.QObject.connect(webview, QtCore.SIGNAL('loadFinished(bool)'), print_content)
...
Benutzeravatar
snafu
User
Beiträge: 5466
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Donnerstag 23. April 2009, 11:16

Jetzt gibt's einen UnicodeEncodeError und ich habe das mit der Umwandlung noch nie wirklich verstanden. :(

Lasse ich es so stehen, heißt es:

Code: Alles auswählen

UnicodeEncodeError: 'ascii' codec can't encode character u'\u25bc' in position 2865: ordinal not in range(128)
Umklammert von unicode() wiederum:

Code: Alles auswählen

UnicodeEncodeError: 'latin-1' codec...
Wer weiß Abhilfe?

PS: Nutze Python 2.5...
shcol (Repo | Doc | PyPi)
jerch
User
Beiträge: 1630
Registriert: Mittwoch 4. März 2009, 14:19

Donnerstag 23. April 2009, 13:39

Der Quelltext liegt als QString unkodiert vor (vergleichbar mit Unicodestring):

Code: Alles auswählen

from PyQt4.QtCore import QString
s = QString(u'hällo') # <-- achtung hier greift schon das "input encoding"

# wirft UnicodeDecodeError: 'ascii' codec can't decode...
# Deine 1. Fehlermeldung
print s

# wirft Fehlermeldung, falls ein Zeichen nicht im Standardcodec ist
# Deine 2. Fehlermeldung (das Bsp. geht mit utf8 als Standard, bei Dir ist wohl Latin-1 Standard)
print unicode(s)

# so sollte es gehen
print unicode(s).encode('encoding')
Die unicode(s)-Wandlung ist nötig, damit das QString-Objekt ein "echter" Unicodestring wird und die Methode encode() genutzt werden kann.

Welches "encoding" Du einsetzt, hängt vom Dokument ab, da xml-files (oder html) ihr eigenes Encoding mitbringen können (ansonsten utf-8 ). Für uft8-encoding bringt QString eine eigene Methode mit:

Code: Alles auswählen

# das geht auch mit utf-8 als sys.stdout.encoding
print s.toUtf8()
Benutzeravatar
snafu
User
Beiträge: 5466
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Donnerstag 23. April 2009, 18:42

Ja, danke. Das klappt:

Code: Alles auswählen

print webview.page().mainFrame().toHtml().toUtf8()
Ich dachte mir nämlich nur so, da ``mechanize`` kein Java kann, könnte man diese Fälle ja von Webkit ausführen lassen, um an den entsprechenden Seiteninhalt zu kommen.
shcol (Repo | Doc | PyPi)
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Donnerstag 23. April 2009, 23:09

Aber gibt das dann den durch JS umgeformten und zu Text serialisierten DOM-Tree zurück oder den empfangenen Quelltext? Letzteres wäre natürlich keine Verbesserung gegenüber mechanize.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
snafu
User
Beiträge: 5466
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Freitag 24. April 2009, 05:33

Was da intern abläuft, weiß ich nicht. Man sollte aber IMHO sowieso auf die Erstellung der Webkit-API warten, weil es wohl ein bißchen übertrieben wäre, dafür ein komplett installiertes PyQt vorauszusetzen. Ich bin wirklich sehr gespannt, was sich in der nächsten Zeit noch bei dem Projekt tut. :)
shcol (Repo | Doc | PyPi)
jerch
User
Beiträge: 1630
Registriert: Mittwoch 4. März 2009, 14:19

Montag 4. Mai 2009, 15:30

@Leonidas:
Die Methode serialisiert den zum Aufrufzeitpunkt vorliegenden DOM-Tree.

QtWebKit läßt sich gut zur Browserautomatisierung auch für Seiten mit Javascript nutzen, wobei es derzeit ohne die WebKit-API viel Handarbeit via Javascript-Code ist. Mit der API soll es dann einen direkten Weg zur DOM-Manipulation geben, derzeit ist das nur mit Javascript-Injections möglich.
Benutzeravatar
snafu
User
Beiträge: 5466
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Montag 4. Mai 2009, 16:12

Kennst du dich damit ein bißchen aus? Es wäre doch super, wenn man z.B. `mechanize` auf diesem Weg JS-Fähigkeit beibringen könnte.

Oder aber man greift direkt auf das eigentliche Webkit-Modul zurück (also nicht das von Qt oder anderen Toolkits) als Ersatz für `mechanize` und integriert nur noch `ClientForm`. Denn die ganzen History-Eigenschaften bringt Webkit ja schon mit und beim Simulieren eines echten Browsers scheint es mir ohnehin geeigneter zu sein.

Vielleicht grenzt das Webkit-Team ja irgendwann mal Codeaufruf von Darstellung ab. Dann hätte man sozusagen den DOM-Tree ohne sich den ganzen "GUI-Kram" mitinstallieren zu müssen. Denn unabhängig von solchen Mechanize-Geschichten könnte es ja durchaus sein, dass ein Browserentwickler bestimmte Elemente mal anders darstellen - sprich: Einfluss auf den Part des Renderns nehmen - will.
shcol (Repo | Doc | PyPi)
jerch
User
Beiträge: 1630
Registriert: Mittwoch 4. März 2009, 14:19

Montag 4. Mai 2009, 18:57

Es wäre doch super, wenn man z.B. `mechanize` auf diesem Weg JS-Fähigkeit beibringen könnte.
Naja, das wäre in bisschen so, als würde man hinter einem Tretroller einen Panzerkreuzer auf Rädern hinterher ziehen, nur um über den JS-Fluß zu kommen ;) Der Vergleich hinkt natürlich massiv und dient nur der Veranschaulichung. Auch will ich keinesfalls mechanize damit diskreditieren.
Was evtl. ginge: Teile des JSCores separat zu binden, um wenigstens rundimentäre JS-Unterstützung zu bekommen. (Ohne Renderer würden alle Positionierungsfunktionen lahmgelegt.)
Oder aber man greift direkt auf das eigentliche Webkit-Modul zurück (also nicht das von Qt oder anderen Toolkits) als Ersatz für `mechanize` und integriert nur noch `ClientForm`.
WebKit als kompletter mechanize-Ersatz macht auch aus meiner Sicht mehr Sinn. Allerdings stellt die Abtrennung von der GUI resp. der Toolkits ein Problem dar, da die Verzahnung mit der Ausgabe (Rendering) relativ eng ist. Nicht nur übernehmen die Toolkits so lästige Sachen wie das Eventhandling, auch ein Teil der DOM-Attribute ist erst mit Ausgabe sinnvoll, ganz zu schweigen von JS, welches diese manipuliert (Element-Positionierung, Font-Rendering etc.). Zumindest hat sich das WebCore-Team eine bessere Trennung von der Ausgabe auf die Fahnen geschrieben, und mit der API soll auch in die Ausgabepräsentation eingegriffen werden können. Ist alles noch Zukunftsmusik, WebKit wäre dann das Schweizer Taschenmesser unter den Browser(toolkits). Man darf gespannt sein.

wegen der GUI:
Du kannst mit Qt auch ohne GUI arbeiten (QCoreApplication). Leider funktioniert das nicht mit QtWebKit, da alle WebKit-Klassen in Qt mehr oder weniger von QWidget abstammen (aus oben genannten Ausgabegründen). Ich nutze hierfür einfach Xvfb.
Benutzeravatar
snafu
User
Beiträge: 5466
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Montag 4. Mai 2009, 21:55

jerch hat geschrieben:Was evtl. ginge: Teile des JSCores separat zu binden, um wenigstens rundimentäre JS-Unterstützung zu bekommen.
Sowas in der Art meinte ich auch. Ich hatte mir vor kurzem auch mal den Webkit-Quellcode mit meinen bescheidenen C++-Kenntnissen angeguckt, aber nicht wirklich verstanden, wo und wie die JS-Engine zum Einsatz kommt. Man müsste halt Squirrelfish mit JS-Code füttern können und er spuckt einem dann irgendwie das Ergebnis aus. Aber ich glaube, der Gedankengang ist eher sinnlos. ;) Geschickter wäre es - wie du schon sagtest - gänzlich auf Webkit zu setzen.
jerch hat geschrieben:Du kannst mit Qt auch ohne GUI arbeiten (QCoreApplication). Leider funktioniert das nicht mit QtWebKit, da alle WebKit-Klassen in Qt mehr oder weniger von QWidget abstammen (aus oben genannten Ausgabegründen).
Ebenfalls schon probiert und bemerkt. Es ist wohl auch ziemlich übertrieben, für den Nachbau von mechanize ein komplettes Qt (oder zumindest große Teile daraus) zu verlangen. Den Gedanken kann man getrost vergessen.

Hast du denn nähere Infos darüber, wann die API kommen soll, was sie kann usw?
shcol (Repo | Doc | PyPi)
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 4. Mai 2009, 22:48

snafu hat geschrieben:Man müsste halt Squirrelfish mit JS-Code füttern können und er spuckt einem dann irgendwie das Ergebnis aus. Aber ich glaube, der Gedankengang ist eher sinnlos. ;)
Ohne DOM-Handling ist so ein Spielzeug ja eher für den Einsatzzweck ungeeignet. Man kann ja durchaus Spidermonkey etwa separat kompilieren und als Javascript-Interpreter nutzen nur hilft das einem beim scrapen nicht.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
jerch
User
Beiträge: 1630
Registriert: Mittwoch 4. März 2009, 14:19

Dienstag 5. Mai 2009, 22:12

Ohne DOM-Handling ist so ein Spielzeug ja eher für den Einsatzzweck ungeeignet. Man kann ja durchaus Spidermonkey etwa separat kompilieren und als Javascript-Interpreter nutzen nur hilft das einem beim scrapen nicht.
Und selbst mit JS-Unterstützung und tollem DOM-Handling wird die Automatisierung immer schwieriger, da JS in den "Automaten Webseite" jenseits von geladen/nicht geladen beliebig viele Zustände einführen kann. Sind diese Zustände dann auch noch an so weiche Ereignisse wie "scroll doch mal ein Stück nach unten und ich lade Dir ein neues Bild" geknüpft, also auf menschliches Verhalten getrimmt, wirds ohne großen Zusatzaufwand unmöglich. Gleichzeitig ist JS quasi überall im Dokument erlaubt und kann von Information über Präsentation bis hin zum eigenen Kontrollfluß alles zu jeder Zeit manipulieren. Aus dogmatischer Sicht gehört JS aus dem Dokument-body verbannt. Naja, die Geister, die ich rief...
Hast du denn nähere Infos darüber, wann die API kommen soll, was sie kann usw?
Die WebKit-Leute sind nicht so geschwätzig, die geben da keine Roadmaps bekannt. Qt wollte in 4.5 schon mit einem erweiterten DOM-Zugriff aufwarten, und ist nun auf Qt 4.6 verschoben worden. Nokia bekundet selber starkes Interesse hieran, denke, daß wenigstens von deren Seite einiges zu erwarten ist.
Benutzeravatar
snafu
User
Beiträge: 5466
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Mittwoch 6. Mai 2009, 11:05

Die ganze DOM-Funktionalität findet sich dann wohl in QWebElement (ich weiß ja nicht wie offiziell diese Angaben sind).

Hier ein paar Erläuterungen.
shcol (Repo | Doc | PyPi)
Benutzeravatar
snafu
User
Beiträge: 5466
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Samstag 9. Mai 2009, 13:33

@jerch:

Man könnte aber doch trotzdem besser unterscheiden zwischen dem was Webkit macht und dem was das Toolkit macht.

Über Signale sollte das Toolkit ja wohl sagen können, dass das Fenster gerade gescrollt wurde. Webkit prüft dann, ob die Seite sozusagen eine bestimmte `on_scroll()`-Methode besitzt.

Es wäre halt schön, wenn man das in einer Art Lowlevel-API (v.a. für's Zeichnen) hätte. So ein Automatisierungstool wie `mechanize` könnte dann bestimmte Fenstergrößen und Scrolling simulieren. Es macht die Sache zwar komplexer, schafft aber auch mehr Freiheiten und man hätte eine einheitliche Ausgabe/API, die jedes Toolkit / jede weiterverabeitende Instanz in seinem Sinne nutzen kann.
shcol (Repo | Doc | PyPi)
Antworten