Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

WebKit URLs

24 views
Skip to first unread message

Hermie

unread,
May 2, 2012, 1:15:16 AM5/2/12
to
Hallo!

Nochmal zum WebKit-Browser-Control:

Ich hatte schon mal gefragt, wie man die links ausliest. Das
funktioniert soweit auch, aber ist echt kompliziert.

Ich habe zu jedem link eine "Base-URL", eine "URL" und eine "Add-URL".
Die hole ich mir durch den unten angehängten Code.

Beispiel:

url: #content
base: http://www.google.com/support/accounts?hl=en
add: http://support.google.com/accounts/?hl=en

Ich schaue mir jetzt immer in Firefox an, wie diese 3 Dinger kombiniert
werden, um den endgültigen Link zu erhalten, aber das ist so schwierig,
und ich habe mittlerweile eine riesige If-Then-Bedingung dafür.

Kann es wirklich sein, dass WebKit die Interpretation auf so brutale
Weise dem "Benutzer" überlässt?

Liebe Grüße,
Hermann





Private Sub pEnumerateLinksForFrame(Frame As IWebFrame)

If Frame Is Nothing Then
Exit Sub
End If

Dim Doc As WebKit.IDOMDocument
' Set Doc = Frame.DOMDocument
Dim e As WebKit.IDOMHTMLElement
' Set e = Doc.documentElement

Dim s$
's = e.innerText

'Debug.Print s

Dim i As Long
Dim NodeList As IDOMNodeList
Dim Node As IDOMNode
Dim LnkElmt As IDOMHTMLElement

m_sCurrentRequestURL = Frame.DataSource.request.URL

Dim sInit$
sInit = Frame.DataSource.initialRequest.URL
'Debug.Print "frame.name: " & Frame.Name & ", initialrequest:" &
Frame.DataSource.initialRequest.URL

Set NodeList = Frame.DOMDocument.GetElementsByTagName("a")
If NodeList.length = 0 Then
Exit Sub
End If

'Debug.Print "---Start Enumeration von Link-Tags---"

For i = 0 To NodeList.length - 1

Set Node = NodeList.Item(i)
Set LnkElmt = Node 'cast von IDOMNode auf IDOMHTMLElement

Dim sInnerText$
Dim sInnerHTML$
sInnerText = LnkElmt.innerText
sInnerHTML = LnkElmt.innerHTML

Dim sLinkText$
sLinkText = sInnerText
If Len(sLinkText) = 0 Then

Dim sOther$
sOther = ""

If Len(sOther) = 0 Then
sOther = pExtractAlt(sInnerHTML)
End If
If Len(sOther) = 0 Then
sOther = pExtractP(sInnerHTML)
End If
If Len(sOther) = 0 Then
sOther = pExtractMostProbable(sInnerHTML)
End If
If Len(sOther) = 0 Then
sOther = sInnerHTML
End If
' Debug.Print sInnerHTML
sLinkText = sOther
End If

Dim sURL$
sURL = pGetLink(LnkElmt)

pAddToLinks sInit, m_sCurrentRequestURL, sLinkText, sURL
Next i

(...)

Private Function pGetLink(ByRef LnkElmt As IDOMHTMLElement) As String

If Not LnkElmt Is Nothing Then
Dim e&
For e = 0 To LnkElmt.Attributes.length - 1
If LnkElmt.Attributes.Item(e).nodeName = "href" Then
Dim Node As IDOMNode
Set Node = LnkElmt.Attributes.getNamedItem("href")
If Not Node Is Nothing Then
Dim sURL$
sURL = Node.textContent
pGetLink = sURL
Debug.Assert Len(sURL) > 0
End If
End If
Next e
End If

End Function

Hermie

unread,
May 2, 2012, 2:37:06 AM5/2/12
to
Hier mal ein Beispiel, was da Wildes passiert:

In der Zeile "pAddToLinks" ganz unten im dargestellten Code habe ich die
folgenden Werte:

sLinkText: Datenschutzerklärung & Nutzungsbedingungen
sUrl: /intl/de/policies/
sInit: http://www.google.com/intl/de/policies/
m_sCurrentRequestURL: http://www.google.com/intl/de/policies/

Irgendwann kann da noch nicht stimmen, denke ich.

Liebe Grüße,
Hermann

Private Sub pEnumerateLinksForFrame(Frame As IWebFrame)

If Frame Is Nothing Then
Exit Sub
End If

Dim Doc As WebKit.IDOMDocument
' Set Doc = Frame.DOMDocument
Dim e As WebKit.IDOMHTMLElement
' Set e = Doc.documentElement

Dim s$
's = e.innerText

'Debug.Print s

Dim i As Long
Dim NodeList As IDOMNodeList
Dim Node As IDOMNode
Dim LnkElmt As IDOMHTMLElement

m_sCurrentRequestURL = Frame.DataSource.request.URL
' Debug.Print Frame.DOMDocument.namespaceURI
--------------

Martin KoWi

unread,
May 2, 2012, 4:12:39 AM5/2/12
to
Hi Hermie,

schau dir mal getElementsByTagNameNS an, das könnte sein was du suchst.
ich hab leider momentan kaum zeit - da musst du selbst weiterprobieren.

gruß, martin.

Schmidt

unread,
May 2, 2012, 7:55:13 AM5/2/12
to
Am 02.05.2012 08:37, schrieb Hermie:
> Hier mal ein Beispiel, was da Wildes passiert:
>
> In der Zeile "pAddToLinks" ganz unten im dargestellten Code habe ich die
> folgenden Werte:
>
> sLinkText: Datenschutzerklärung & Nutzungsbedingungen
> sUrl: /intl/de/policies/
> sInit: http://www.google.com/intl/de/policies/
> m_sCurrentRequestURL: http://www.google.com/intl/de/policies/
>
> Irgendwann kann da noch nicht stimmen, denke ich.

Vielleicht zur Erklärung nochmal:

sInit hält die Basis-Url, mit welcher der Request
startet - m_sCurrentRequestURL hält die (eventuell
"forwarded" bzw. redirected) URL, auf der der Request
dann am Ende tatsächlich endet.

z.B. wenn Du mit http://www.google.com den Request
startest, dann wird "geforwarded" auf http://www.google.de

sInit wäre in dem Falle dann also http://www.google.com/
m_sCurrentRequestURL wäre dann http://www.google.de

Und sUrl (stammend aus dem href-Attribute) kann eine absolute
URL, aber auch eine relative URL sein - wenn relativ, dann
in zwei Spielarten (entweder beginnend mit einem Slash, oder
ohne Slash).

Hier mal eine auf die schnelle zusammengestellte Kombinations-
Helfer-Routine...

Private Sub pAddToLinks(sInit, m_sCurrentRequestURL, sLinkText, sURL)
Dim BaseURL$, BaseDomain$, CombinedURL$, PosProto&
BaseURL = IIf(Len(m_sCurrentRequestURL), m_sCurrentRequestURL, sInit)
BaseDomain = Left$(BaseURL, InStr(8, BaseURL, "/") - 1)

PosProto = InStr(sURL, "://")
If PosProto > 1 And PosProto < 10 Then 'it's an absolute URL
CombinedURL = sURL
ElseIf Left$(sURL, 1) = "/" Then 'a relative URL (use the Domain-Root)
CombinedURL = BaseDomain & sURL
Else 'it's a relative URL, starting from the BaseURL
CombinedURL = BaseURL & sURL
End If

sLinkText = Trim$(Replace$(Replace$(sLinkText, vbCr, ""), vbLf, ""))
Debug.Print sLinkText
Debug.Print , CombinedURL; vbCrLf
End Sub


Wenn ich mit deren Hilfe www.google.com "ansurfe", dann
erhalte ich am Ende diesen Debug-Output (Links ohne
beschreibenden sLinkText jetzt mal weggelassen).

+Ich
https://plus.google.com/?gpsrc=ogpy0&tab=wX

Suche
http://www.google.de/webhp?hl=de&tab=ww

Bilder
http://www.google.de/imghp?hl=de&tab=wi

Videos
http://video.google.de/?hl=de&tab=wv

Maps
http://maps.google.de/maps?hl=de&tab=wl

News
http://news.google.de/nwshp?hl=de&tab=wn

Shopping
http://www.google.de/shopping?hl=de&tab=wf

Mail
https://mail.google.com/mail/?tab=wm

Mehr
http://www.google.de/intl/de/options/

Anmelden

https://accounts.google.com/ServiceLogin?hl=de&continue=http://www.google.de/


Erweiterte Suche
http://www.google.de/advanced_search?hl=de

Sprachoptionen
http://www.google.de/language_tools?hl=de

Werben mit Google
http://www.google.de/intl/de/ads/

Unternehmensangebote
http://www.google.de/services/

Google+
https://plus.google.com/117570067846637741468

Über Google
http://www.google.de/intl/de/about.html

Google.com in English
http://www.google.com/ncr

Datenschutzerklärung & Nutzungsbedingungen
http://www.google.de/intl/de/policies/


Olaf

Hermie

unread,
May 4, 2012, 12:19:06 AM5/4/12
to
Hi Martin,

danke. Was wäre denn in getElementsByTagNameNS der erste Parameter in
meinem Fall?

Liebe Grüße,
Hermann

Martin KoWi

unread,
May 4, 2012, 9:55:07 AM5/4/12
to
Am 04.05.2012 06:19, schrieb Hermie:

> danke. Was wäre denn in getElementsByTagNameNS der erste Parameter in
> meinem Fall?

Sorry Hermie, ich komme momentan zu gar nix.
Ich hatte das nur beim durchblättern im Object Browser gesehen und es
klang so, als könnte das was damit zu tun haben.
Wahrscheinlich liege ich auch falsch, aber leider liegen meine Projekte
in der Richtung momentan auf Eis.

War denn Olafs Bsp. nicht OK? das tut doch?

gruß, martin.

Hermie

unread,
May 5, 2012, 2:57:36 AM5/5/12
to
Hi Martin,

ich dachte, Du hättest vielleicht einen Weg gefunden, die "schon
vorkompilierten" links auszulesen.

Es gibt noch viele andere Arten, wie ein link zusammengesetzt werden
kann, die Olafs Beispiel nicht abdeckt, z. B. mit "../", "/...", usw.

Weil meine eigenen Bemühungen in dieser Richtung zu viel auf
Trial-And-Error beruhten, hatte ich stattdessen versucht, die von WebKit
"vorgeparsten" links auszulesen.

Olafs Beispiel ist schön, aber meine eigenen Bemühungen gingen schon
viel weiter und waren dennoch nicht zufriedenstellend.

Viele Grüße,
Hermann

Martin KoWi

unread,
May 5, 2012, 4:09:08 AM5/5/12
to
Am 05.05.2012 08:57, schrieb Hermie:

> ich dachte, Du hättest vielleicht einen Weg gefunden, die "schon
> vorkompilierten" links auszulesen.

Ich verstehe dein Problem, aber wie schon gesagt liegt das bei mir
momentan auf Eis.
Du hast mittlerweile sicher viel mehr Zeit mit Webkit verbracht.

Aber ich sehe das genauso wie du:
dieses selbst "parsen und raten" KANN nicht die Lösung sein -
der Browser weiss es ja sowieso!
Ich hätte auch angenommen dass es hierfür eindeutige Methoden gibt.

Falls du da weiterkommst, wäre es trotzdem schön, wenn du deine
Erkenntnisse posten könntest.

gruß, martin.

Schmidt

unread,
May 5, 2012, 7:55:29 AM5/5/12
to
Am 05.05.2012 08:57, schrieb Hermie:

> Weil meine eigenen Bemühungen in dieser Richtung zu viel auf
> Trial-And-Error beruhten, hatte ich stattdessen versucht, die von WebKit
> "vorgeparsten" links auszulesen.

Das *interne* (C++)DOMDocument-Objekt von WebKit besitzt
eine 'links' property.

Diese ist jedoch im COM-Interface (IDomDocument)
nicht herausgeführt ... aber wie immer in solchen
Fällen hilft dann das Rückgreifen auf (injiziertes) Javascript:

Im LoadFinished-Event zu platzieren:
'----------------------
With New_c.StringBuilder
.Append "function GetLinks(){"
.Append " var Links = new Object();"
.Append " Links.text = new Array();"
.Append " Links.html = new Array();"
.Append " Links.href = new Array();"
.Append " Links.count = document.links.length;"
.Append " for (var i=0; i < document.links.length; i++){"
.Append " var li = document.links[i];"
.Append " Links.text[i] = li.innerText;"
.Append " Links.html[i] = li.innerHTML;"
.Append " Links.href[i] = li.href;"
.Append " }"
.Append " return JSON.stringify(Links);;"
.Append "}"

ucWebKit1.Browser.WebKit.AddScript .ToString
End With

ParseLinks
'----------------------

Hier der Beginn einer kleinen Helfer-Routine, welche
jetzt nicht mehr mit dem Zusammensetzen der vorgeparsten
URLs (href) befasst sein muss, sondern nur noch die
zur href gehörigen "friendly descriptions" zuordnen muss:

Private Sub ParseLinks()
Dim i As Long, Links As cCollection, Count As Long
Dim Href As cCollection, Text As cCollection, Html As cCollection

Set Links = New_c.JSONDecodeToCollection( _
CStr(ucWebKit1.Browser.WebKit.Evaluate("GetLinks();")))

Count = Links("count")
Set Href = Links("href")
Set Text = Links("text")
Set Html = Links("html")

For i = 0 To Count - 1
Debug.Print Href.ItemByIndex(i)
Debug.Print Html.ItemByIndex(i)
Debug.Print Text.ItemByIndex(i)
Next i
End Sub

Also Href.ItemByIndex(i) hält nun bereits die vorgeparsten URLs ...

Text.ItemByIndex(i) enthält den .innerText, des Link-Elements
an Index 'i' - ist jedoch nicht immer besetzt - deswegen halt zusätzlich
noch:
Html.ItemByIndex(i), welches das zum jeweiligen Link gehörige
.innerHTML widerspiegelt und für erweiterte Suche nach einer
"gut passenden Klartext-Beschreibung" der in Href.ItemByIndex(i)
stehenden URL geeignet ist.


Olaf


Ulrich Korndoerfer

unread,
May 5, 2012, 11:39:54 AM5/5/12
to
Hallo,

Hermie schrieb:
> Hi Martin,
>
> ich dachte, Du hättest vielleicht einen Weg gefunden, die "schon
> vorkompilierten" links auszulesen.
>
> Es gibt noch viele andere Arten, wie ein link zusammengesetzt werden
> kann, die Olafs Beispiel nicht abdeckt, z. B. mit "../", "/...", usw.
>

Quark. Es gibt keine einem href Attribut zugeordnete Links, die "/..."
enthalten.

Ich vermute mal, Du hast Dir den Wert des href Attributes im Firefox
mittels des Firebug-Addons angesehen und dabei ignoriert, daß der Wert
des Attributes verkürzt angezeigt wird (erkenntlich daran, daß das
Kästchen links mit "+" beschriftet ist). Die drei Punkte in "/..." nennt
man Ellipse oder auch Auslassungszeichen.

"../" dagegen ist Standardnotation und bedeutet: gehe in der
Ordnerhierarchie einen Schritt nach oben. Das kann man auch mehrfach
anwenden, zB "../../" etc. Olafs Parser mußte nur noch um diesen Fall
erweitert werden.

--
Ulrich Korndoerfer

VB tips, helpers, solutions -> http://www.prosource.de/Downloads/
MS Newsgruppen Alternativen -> http://www.prosource.de/ms-ng-umzug.html

Hermie

unread,
May 6, 2012, 12:15:54 PM5/6/12
to
Hi Olaf,

danke für die Hilfe und den Code.
Derzeit crasht mir der webbrowser, wenn ich das Skript injecte.
Ich melde mich wieder, sobald ich den Fehler gefunden habe.
Vielleicht mag er es auch nicht, dass ich zuerst das Skript injecte, um
den Cursor in die Eingabebox zu setzen ("Google-Sucheingabe-Maske") und
hinterher direkt das Skript einfüge, um die Links auszulesen.
Bewundernswert finde ich das Vertrauen, das Du in die Skript-Injections
hast.
Mir kommt dieses Einfügen sehr "heiß" vor, aber Du hast da ja mehr
Erfahrung.

Viele Grüße,
Hermann

W. Wolf

unread,
May 6, 2012, 1:15:05 PM5/6/12
to
"Hermie" <herman...@lycos.de> schrieb

> Bewundernswert finde ich das Vertrauen, das Du in die Skript-Injections hast.
> Mir kommt dieses Einfügen sehr "heiß" vor, ...

Warum denn? Diese Injections werden durch dein
eigenes Programm vorgenommen und nicht etwa von
ausserhalb des Browsers. Gleiches könnte man
sicher auch mit anderen Browsern machen, wenn
ein Zugriff auf die Schnittstellen des Browsers
vorhanden ist. Und die sind bei den meisten
Browsern vorhanden.
Schau dir nur mal die Debug-Tools der Browser an.
Du kannst z.B. mit Firebug jederzeit JS-Kommandos
an das Browser-Dokument absetzen, das DOM oder
CSS-Eigenschaften ändern, usw. usw. Manche Browser
unterstützen sogar die Eingabe von JS-Code in die
Adsressleiste des Browsers. Also so ungewöhnlich
ist das alles nicht.

Schönen Gruß
W. Wolf

Hermie

unread,
May 9, 2012, 9:47:06 AM5/9/12
to
Hallo Olaf,

wenn mir VB6 jedes Mal in dieser Zeile abschmiert...


Set Links = New_c.JSONDecodeToCollection( _
CStr(ucWebKit1.Browser.WebKit.Evaluate("GetLinks();")))

... was würdest Du denn dann als Erstes machen?

Liebe Grüße,
Hermann

Schmidt

unread,
May 9, 2012, 1:57:11 PM5/9/12
to
Am 09.05.2012 15:47, schrieb Hermie:

> wenn mir VB6 jedes Mal in dieser Zeile abschmiert...
>
>
> Set Links = New_c.JSONDecodeToCollection( _
> CStr(ucWebKit1.Browser.WebKit.Evaluate("GetLinks();")))
>
> .... was würdest Du denn dann als Erstes machen?

Auf Bugsuche gehen... ;-)

Soeben hier gemacht - und das Resultat ist, dass die
WebKit.Evaluate-Funktion (zumindest im COM-Interface,
wo dann vom C++-Code die JS-StringKlassen-Inhalte zu BSTR
gewandelt werden) offenbar nur maximal 16384 Zeichen
zurückgeben kann.
Das liegt nicht am RC4 (hab gerade nochmal gecheckt),
sondern direkt in den WebKit-C++ Sourcen.

Bei Google.de (bei mir so um die 35 Links) die per
JSON.stringify zu serialisieren waren, klappt das noch gut -
bei heise.de (405 zu serialisierende Link-Infos)
wird dann das zurückgegebene evaluierte String-Result
größer als 16kB - und dann gab es (auch beim mir) den crash.

Weiss nicht, ob die JS-Eval-Funktion nur zum Rausreichen
kleinerer Sachen gedacht war, jedenfalls klappt das
beim Wandeln von JS::string zu BSTR bei langen Strings
nicht wie es soll...

Ein Workaround, bei dem offenbar keine Probleme mit dem
Rausreichen langer Strings in die COM-Welt auftreten,
ist der Umweg über ein vom JS-Code geraistes Event...

Die finale Helfer-Funktion sieht bei mir also jetzt so aus:

Private Sub ParseLinks(Links As cCollection)
Dim i As Long, Count As Long
Dim Href As cCollection, Text As cCollection, Html As cCollection

If Not Links.Exists("count") Then Exit Sub

Count = Links("count")
Set Href = Links("href")
Set Text = Links("text")
Set Html = Links("html")
Debug.Print Count
' For i = 0 To Count - 1
' Debug.Print Href.ItemByIndex(i)
' Debug.Print Html.ItemByIndex(i)
' Debug.Print Text.ItemByIndex(i)
' Next i
End Sub

Und dann halt noch das Bestücken der entsprechenden Events,
einmal im LoadFinished...

Private Sub ucWebKit1_LoadFinished(...)
With New_c.StringBuilder
.Append "function GetLinks(){"
.Append " var Links = new Object();"
.Append " Links.text = new Array();"
.Append " Links.html = new Array();"
.Append " Links.href = new Array();"
.Append " Links.count = document.links.length;"
.Append " for (var i=0; i < document.links.length; i++){"
.Append " var li = document.links[i];"
.Append " Links.text[i] = li.innerText;"
.Append " Links.html[i] = li.innerHTML;"
.Append " Links.href[i] = li.href;"
.Append " }"
.Append " return Links;"
.Append "}"
.Append "RaiseVBEvent(GetLinks(),'ParseLinks');"

ucWebKit1.Browser.WebKit.AddScript .ToString
End With
End Sub

Und dann enstprechend im JSEventCallback-Event,
welches wie gesagt mit längeren Strings klarkommt.

Private Sub ucWebKit1_JSEventCallBack(...)
If EventName="ParseLinks" And Not JSONEventObj Is Nothing Then
ParseLinks JSONEventObj
End If
End Sub


Ansonsten vielleicht doch besser direkt mit dem DOM
arbeiten, wenn Dir JS (bzw. obiger Workaround) "zu heiß"
ist. Ulrich hat ja schon was dazu geschrieben (also
gar soviel wäre an meiner Basis-Routine eigentlich nicht
nachzurüsten).

Olaf


Hermie

unread,
May 10, 2012, 12:29:15 AM5/10/12
to
Super, vielen Dank!!!

Liebe Grüße,
Hermann
0 new messages