Qt: Kompletten Quelltext von Webkit bekommen

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

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?
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

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: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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...
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

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: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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 (former) Modvoice
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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. :)
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@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: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

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: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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 (former) Modvoice
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

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: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

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.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@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.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich habe noch etwas neues entdeckt (hoffe, ihr seid nicht genervt vom Dreifachpost... ;P). Und zwar gibt es Webkit auch für Gtk (was der ein oder andere sicher schon wusste). Nun habe ich allerdings entdeckt, dass jemand `jswebkit` entwickelt hat. Das ist offenbar ein Wrapper für Webkits JavaScript-Engine und allein das was in der `testwebkit.py` gemacht wird (Zugriff auf den DOM-Tree via `getElementsByTagName()`, Abschicken einer Suchanfrage in Google durch Ausfüllen von `form`) sieht IMHO höchst vielversprechend aus und erinnert auch schon sehr an die API von `mechanize`. Mal sehen, vielleicht probiere ich mich in den nächsten Tagen mal an einer Implementierung hinsichtlich Links besuchen, Dinge anklicken usw...

Achso, hier der Issue wo es auch das Archiv gibt (letzter Eintrag).
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Vllt. ist den Leuten von mechanize ja an einer Komplettrevision im Hinblick auf mögliche JS-Features gelegen. Du könntest die ja mal kontaktieren, oder halt selbst die Sache in die Hand nehmen ;)
Allerdings ändern sich die Anforderungen an ein so aufgebortes mechanize grundlegend, ich sag nur Gtk/Qt + Webkit, GUI-Zugriffsmöglichkeit und JS-Engine, von evtl. Portierungsschwierigkeiten mit den erweiteren Abhängigkeiten ganz zu schweigen. Ein Browsertoolkit in einer Sprache vorzuhalten ist eben ein "bisschen" mehr als das, was mechanize derzeit kann.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Ich werde das bisher erreichte (siehe `Codesnippets`) erstmal auf Qt portieren, da mir die Gtk-Version zu fehleranfällig ist und ich jetzt herausgefunden habe, wie ich dort die JS-Engine ansprechen (also Code direkt ausführen lassen) kann. Allerdings muss ich mir da erstmal einen Wrapper für schreiben (ist in der Mache, gibt ja auch einen entsprechenden Thread).

Das ganze werde ich nach und nach erweitern bis es in etwa mechanize-Niveau erreicht hat und die grundsätzliche Struktur somit steht. Bei meinem Arbeitstempo ist bis dahin vielleicht schon Qt 4.6 erschienen (*lölz*) und man kann das Programm dann auf die versprochene DOM-API von Qt umstellen (mal sehen wie der gute phil von PyQt da Schritt hält).

Am schönsten wäre es natürlich, wenn die Webkit-API bald dokumentiert würde. Aber selbst dann dauert es sicher eine ganze Weile bis jemand entsprechende Python-Bindings geschrieben hat (diese Aufgabe ist mir persönlich zu hoch).

Was natürlich der große Vorteil an einem Toolkit als Abhängigkeit ist. Man kann bestimmte Befehle ausprobieren und sich dann bspw. mittels `show()` den Stand der Dinge als Fenster anzeigen lassen (z.B. das dieses und jenes Feld nun ausgefüllt wurden und man auf der korrekten Folgeseite ist - oder eben auch nicht). Umgekehrt ließe sich *vielleicht* auch verfolgen, welche Schritte im Browserfenster gemacht wurden und man erhält entsprechenden Python-Code. Das wäre ja schon irgendwie ganz ... cool. :)
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Eine Runde "Wünsch Dir was":
mechanize abwärtskompatibel, eleganter DOM-Zugriff, volle JS-Unterstützung, Konsolen-/Guimodus, Makrorecorder: in Gui-Fenster-Modus Makro browsend aufzeichen, Makrosprache - Python (was sonst), Konsolenmodus: Abspielen der Makros, komplette curl-Unterstützung, HTML-Editor, lxml-binding, Seitenindizierung, Spielekonsole, google nachbauen, Zeitreisen, Weltherrschaft

Hab ich was vergessen? ;)

Spaß beiseite, ich habe absolut keine Ahnung, wie brauchbar das WebKit-Gtk-Binding ist oder dessen JS-Unterstützung. Mit QWebKit habe ich bisher recht gute Erfahrungen gemacht, auch wenn es etwas unpythonisch daher kommt. Und da sich die WebKit-Leute über eine Roadmap ausschweigen, würde ich eben zur Qt-Lösung tendieren.

Wie wärs, das ganze als Projekt aufzuziehen, vllt. findest Du hierfür Mitstreiter im Forum bzw. unter den mechanize-Leuten. So wäre auch eine halbwegs sichere Platzierung in das Biotop mechanize-webkit-pyqt-python möglich.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Bin heute auf OWB gestoßen. Dazu das englische Wikipedia im Artikel zu WebKit:
There is also a project synchronized with WebKit (sponsored by Pleyo) called Origyn Web Browser, which provides a meta-port to an abstract platform with the aim of making porting to embedded or lightweight systems quicker and easier.
<Quelle>

Das klang vielversprechend und tatsächlich finde ich die API einigermaßen verständlich, zumal auch ein bißchen Doku dabei ist.

Ich kompiliere es gerade noch und werde dann mal versuchen, ob ich durch diese Methode den richtigen Einstiegspunkt für mein Vorhaben finde.

Langfristig ist das hoffentlich auch eine gute Basis, um die Abläufe in WebKit selbst besser zu verstehen.
Antworten