Live-Forum - Die aktuellen Beiträge
Anzeige
Archiv - Navigation
1560to1564
Aktuelles Verzeichnis
Verzeichnis Index
Übersicht Verzeichnisse
Vorheriger Thread
Rückwärts Blättern
Nächster Thread
Vorwärts blättern
Anzeige
HERBERS
Excel-Forum (Archiv)
20+ Jahre Excel-Kompetenz: Von Anwendern, für Anwender
Inhaltsverzeichnis

Bestimmte Stelle aus URL (oder txt) auslesen

Bestimmte Stelle aus URL (oder txt) auslesen
24.05.2017 12:52:05
Florian
Hallöchen
Mit folgendem Makro öffne ich eine URL.
Durch die bolsche Variable entweder mit verstecktem, oder mit sichtbarem IE (für das MAkro ja aber egal).
Den Inhalt der URL speichere ich dann in einer txt (wenn ein anderes Format mehr Sinn macht, nehme ich das natürlich auch), da es für die string Variable Response zu lang ist.
Option Explicit
Sub Startfarm(myUrl As String)
Dim oIE As Object
Dim Response As String
Dim bolhidden As Boolean
bolhidden = ThisWorkbook.Worksheets("Einstellungen").Range("B2")
'INternetexplorer starten
Set oIE = CreateObject("InternetExplorer.Application")
oIE.Visible = bolhidden
oIE.Navigate myUrl
' Warten, bis die Seite geladen ist
Do While oIE.busy
DoEvents
Loop
Response = oIE.Document.Body.InnerHtml
Open ThisWorkbook.Path & "\test.txt" For Output As #1
Print #1, Response
Close
Set oIE = Nothing
End Sub
Hier die so erzeugte Textdatei: https://www.herber.de/bbs/user/113772.txt
Da diese allerdings nur aus einer Zeile besteht, bekomme ich sie nicht sauber importiert, auch dauert dies sehr lange.
In der Textdatei steht unter anderem folgendes:
 

riddersmurf gewinnt

riddersmurf erbeutet 17 Silber.

Hier benötige ich nun die Menge des erbeuteten Silbers, dies kann jedoch auch einstellig oder mehrstellig sein.
Hat jemand eine Idee, wie ich nur diese Zahl aus der txt Datei (oder halt einem anderen Format) bekomme?

26
Beiträge zum Forumthread
Beiträge zu diesem Forumthread

Betreff
Datum
Anwender
Anzeige
AW: Bestimmte Stelle aus URL (oder txt) auslesen
24.05.2017 12:55:32
Florian
Oh, das Forum stellt html ja "in gescheit" dar.
So sieht die Passage in der txt Datei aus.
<h1><em>riddersmurf gewinnt</em></h1><p>riddersmurf erbeutet <em>17</em> Silber.</p>
AW: Bestimmte Stelle aus URL (oder txt) auslesen
24.05.2017 14:18:40
JoNNy
Hallo Florian,
in genau diesem String(Auszug aus .txt) den du gepostet, kannst du doch einfach immer nach "" suchen lassen und dann überprüfen ob der Wert dazwischen eine Zahl ist.(Teil durch 1 und mach dann ein "On Error" zum Anfang der Abfrage).
Ich hoffe das reicht/hilft als Denkanstoß und das ich dein Problem nicht falsch verstanden hab :)
Gruß JoNNy
Anzeige
AW: Bestimmte Stelle aus URL (oder txt) auslesen
24.05.2017 14:24:53
Florian
So in etwas ging meine Denkrichtung auch.
Jedoch habe ich keine Ahnung, wie ich mittels VBA eine Textdatei durchsuche.
Und das erbeutete Silber steht in (eckigen Klammern) em - da gibt es aber nochmehr Zahlenwerte.
Ich müsste also nach erbeutet em XXX /em Silber (wobei XXX das Suchergebnis ist).
Daran (und daran, dass ich nicht weiß wie viele stellen das Suchergebnis hat), scheitere ich.
AW: Bestimmte Stelle aus URL (oder txt) auslesen
24.05.2017 14:32:42
JoNNy
Ok so schwer ist das denk ich garnicht sobald das erstmal in Excel ist, kannst du mit dem String alles mögliche machen.
Ich denke aber das die Problematik sein wird:
1. Das auslesen (gucke da gleich nach ob das direkt aus .txt klappt)
2. Die Menge an Text da das ja im Prinzip die ganze Seite als Text ist.
Frage:
Hat der Wert eine ungefähr feste Stelle im Quellcode, also zum Beispiel im oberen drittel?
Wenn nicht bedeutet das, das man die ganze .txt durchsuchen muss, wenn ja kann man ja den Rest von vornherein gleich rauslöschen.
Gruß JoNNy
Anzeige
Nicht über eine txt, sondern direkt übers DOM
24.05.2017 14:28:12
Zwenn
Hallo Florian,
das Zwischenspeichern des HTML Codes als Text-Datei kannst Du Dir sparen. Der Wert, den Du auslesen willst findest Du sehr einfach über das Document Object Modell (DOM) und kannst ihn direkt auslesen.

Sub Startfarm(myUrl As String)
Dim oIE As Object
'Dim Response As String
Dim bolhidden As Boolean
Dim knotenAst As Object
bolhidden = ThisWorkbook.Worksheets("Einstellungen").Range("B2")
'INternetexplorer starten
Set oIE = CreateObject("InternetExplorer.Application")
oIE.Visible = bolhidden
oIE.Navigate myUrl
' Warten, bis die Seite geladen ist
Do While oIE.busy
DoEvents
Loop
'Response = oIE.Document.Body.InnerHtml
'   Open ThisWorkbook.Path & "\test.txt" For Output As #1
'   Print #1, Response
'   Close
Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0). _
GetElementsByTagName("p")(0).GetElementsByTagName("em")(0)
If Not knotenAst Is Nothing Then
MsgBox knotenAst.innertext
Else
MsgBox "Kein Gewinn"
End If
oIE.Quit
Set oIE = Nothing
End Sub
Unter folgendem Link kannst Du Dir mal ein Beispiel zum Umgang mit dem DOM ansehen, dass ich vor einiger Zeit mal hier für jemand anderen veröffentlicht habe. Falls Du noch weitere Werte von Webseiten brauchst, ist das ein ganz guter Ansatzpunkt denke ich.
https://www.herber.de/cgi-bin/callthread.pl?index=1492241#1493245
Viele Grüße,
Zwenn
Anzeige
AW: Nicht über eine txt, sondern direkt übers DOM
24.05.2017 14:50:42
Florian
Hui.
Das scheint zu funktionieren.
Den Link werde ich mir heute Abend in Ruhe zu gemüte führen.
Aber könntest du mir vorab folgende Zeile erläutern?
    Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0). _
GetElementsByTagName("p")(0).GetElementsByTagName("em")(0)

AW: Nicht über eine txt, sondern direkt übers DOM
24.05.2017 15:24:57
Florian
Also ich meine, wenn ich jetzt etwas anderes suchen würde, meinetwegen den Schaden den ich ausgeteilt habe, oder was auch immer - wie suche ich nach anderen Dingen?
Bzw. woher weißt du dass fightResultsInner richtig ist? oder wo kommt das her?
Anzeige
AW: Nicht über eine txt, sondern direkt übers DOM
24.05.2017 15:31:25
Florian
uhuuund nerv nerv.
Es kann natürlich sein, dass eine andere Seite geladen wird (wenn ich nicht angreifen kann, oder nicht eingeloggt bin)
Dann kann natürlich knotenAst nicht gesetzt werden, weil ich ja nix angegriffen habe.
Muss ich hier mit onerror Resume Next arbeiten, oder kann ich den Fehler auf andere Art abfangen?
AW: Nicht über eine txt, sondern direkt übers DOM
24.05.2017 15:49:34
Zwenn
Ich weiß, dass es funktioniert, weil ich es ausprobiert habe ;-)
Den Link hatte ich eigentlich wegen genau der von Dir nachgefragten Zeile angegeben. Aber seis drum, ich versuche es mal mit einem kurzen Abriss.
Das DOM (Document Object Model) ist in einer Baumstruktur organisiert. Genauer gesagt sind Webseiten als Baumstruktur organisiert, die den Regeln des DOM unterliegt. Unter anderem kann man direkt auf Elemente im Dokument des Browsers zugreifen. Dafür gibt es mehrere Möglichkeiten. Ich habe die Möglichkeit von zwei Get-Methoden verwendet.

GetElementsByClassName("CLASSNAME")
GetElementsByTagName("TAGNAME")

Mit GetElementsByClassName() spricht man direkt alle Elemente einer Seite an, die den in Klammern angegebenen CSS-Klassennamen haben. Die Elemente mit dem Klassennamen werden alle in einem Array abgelegt, das mit dem Index 0 beginnt. Ich habe in Deinem Seitenquelltext nachgesehen, in was für einem Codeblock der Wert steht, den Du auslesen willst. Dieser Block muss eindeutig identifizierbar sein und sollte einen möglichst kleinen Codeausschnitt einschließen.
In Deinem Fall gibt es die CSS-Klasse "fightResultsInner" und das genau ein einziges Mal auf der ganzen Seite. Deshalb habe ich hinter GetElementsByClassName("fightResultsInner") direkt (0) angegeben. Das ist der erste Index des gebildeten Arrays für alle Elemente mit dem Klassennamen "fightResultsInner". Wie gesagt, davon gibts nur eins, also muss der gesuchte Codeblock den Index 0 in unserem Array haben.
Zu diesem Zeitpunkt arbeiten wir nur noch auf dem Codeausschnitt:
(Alle Spitzen Klammenrn habe ich wegen der Darstellung gegen Eckige ausgetauscht)

[div class="fightResultsInner"]
[h1][em]riddersmurf gewinnt[/em][/h1][p]riddersmurf erbeutet [em]17[/em] Silber.[/p]
[p]riddersmurf erhält [em]1[/em] EP.[/p]
[p]legend erhält [em]1[/em] EP.[/p]
[div class="divider"] [/div]
[p]Schaden - Angreifer: [em]187[/em][/p]
[p]Schaden - Verteidiger: [em]0[/em][/p]
[/div]
Auch für diesen Abschnitt ist noch das DOM gültig. Deshalb habe ich den Code direkt weiter mit GetElementsByTagName("p")(0) eingegerenzt. Wie man sich jetzt leicht denken kann, wird hier ein Array aus allen Elementen mit dem Tag Namen "P" gebildet. Allerdings nur aus dem Codeblock, der vorher schon durch die Klassenauswahl begrenzt wurde. Du siehst hier die Begründung für meine Forderung weiter vorne, der entstehende Codeblock sollte möglichst eng um den gesuchten Wert liegen.
Wir bekommen also ein Array mit allen P-Tags:

[p]riddersmurf erbeutet [em]17[/em] Silber.[/p]
[p]riddersmurf erhält [em]1[/em] EP.[/p]
[p]legend erhält [em]1[/em] EP.[/p]
[p]Schaden - Angreifer: [em]187[/em][/p]
[p]Schaden - Verteidiger: [em]0[/em][/p]
Der von Dir gesuchte Wert befindet sich im ersten P-Tag, also im ersten Element unseres Arrays, mit dem Index 0. Nun habe ich nur auf dieses Element (0) noch einmal die Eingrenzung über den Tag-Namen angewendet. Diesmal auf den Tag "em".
Davon gibts wieder nur einen, weshalb nach GetElementsByTagName("em")(0) nur noch folgendes übrig bleibt:

[em]17[/em]
Auch dieser nun letzte Tag unterliegt den Regeln des DOM. Deshalb können wir auf seinen Inhalt mit der Methode Innertext zugreifen. Um zu prüfen, ob wir überhaupt einen Wert vorliegen haben, prüfen wir zunächst, ob das Object knotenAst wirklich gebildet werden konnte. Das machen wir mit dem komisch anmutenden Doppel-Negativ-Konstrukt:

If Not knotenAst Is Nothing Then

Wir fragen also, ob knotenAst nicht existiert, also Nothing ist und drehen das Ergebnis mit Not um. Auf diese Weise können wir entsprechend des Ergebnisses dieser Prüfung unseren Code weiter schreiben. Ich habe einfach zwei MsgBoxes verwendet. Du wirst sicherlich eine andere Verwendung für das Ergebnis haben.
Wie Du nun leicht sehen kannst, habe ich lediglich einen möglichen Weg gewählt, um an den Wert zu kommen. Du kommst genauso dran, mit der Zeile:

Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0). _
GetElementsByTagName("em")(1)

Hier wird das zweite Array direkt aus den em-Tags gebildet. Der gesuchte Wert steht dann im zweiten Element des Arrays, das den Index 1 hat.
Ich hoffe das ist einigermaßen nachvollziehbar gewesen.
Wenn Der Aufbau der Seite sich ändert, muss das Makro angepasst werden. Deshalb empfehle ich Dir, prüfe mal ein paar verschiedene Ausgaben der Seite hinter deinem Link ab. Was steht z.B. im Quelltext, wenn gar kein Silber gewonnen wurde? Kann man auch Verlust machen? Wie wird der dargestellt? Kann "fightResultsInner" unter Umständen doch noch ein zweites Mal auftauchen, wenn ja wird das relevant, wenn es vor dem jetzigen ist. Denn dann wärst Du von vorn herein im falschen Codeabschnitt unterwegs (falscher Array Index).
Das klingt erstmal kompliziert. Diese Gedanken musst Du Dir aber nur einmal machen oder reagieren, wenn sich etwas ergibt, was Du vorher nicht gesehen hast. Ist das Ganze aber mal fertig, läuft das erfahrungsgemäß sehr stabil, weil sich Seitenstrukturen selten ändern.
Anzeige
AW: Nicht über eine txt, sondern direkt übers DOM
24.05.2017 16:07:20
Florian
Mist.
Also erstmal danke für die Ausführung.
Bevor ich jetzt noch weitere Fragen stelle, warte ich besser erst mal bis heute Abend und schaue mir den Link an.
Wenn ich dann was nicht raffe, gebe ich nochmal laut :)
AW: Nicht über eine txt, sondern direkt übers DOM
24.05.2017 16:16:35
Zwenn
Probiere einfach mal etwas mit den Möglichkeiten rum. Dabei lernst Du am meisten.
Hier ist nochmal die Arbeitsmappe mit dem Makro, die eigentlich in dem Beitrag runterzuladen war, den ich Dir verlinkt habe. Der Download dort funktioniert aber scheinbar nicht mehr. Du kannst an diesem Beispiel sehen, was ich damit meine, dass eine Seitenstruktur meistens lange bestehen bleibt und solche Makros deshalb sehr stabil laufen. Die NBA Ergebnisse kann man noch heute mit dem vor über einem Jahr erstellten Makro abrufen. (paar Sekunden warten, die Seite scheint etwas langsam zu reagieren):
https://www.herber.de/bbs/user/113778.xlsm
Anzeige
AW: Nicht über eine txt, sondern direkt übers DOM
24.05.2017 20:54:50
Florian
fein fein :)
Die meisten meiner Fragen sind geklärt - oder werden sich nach ein bisschen rumprobieren.
Eine Sache ist aber noch.
Wenn ich nicht wie erwartet auf die Seite komme auf der das Duell angezeigt wird (also wo mein _ Gewinn ist), z.B. weil ich nicht eingeloggt bin, oder weil der Ritter nicht angegriffen werden kann, schlägt natürlich

Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0). _
GetElementsByTagName("p")(0).GetElementsByTagName("em")(0)

fehl.
Könntest du mir hier eine Art Rückfrage bauen?
Also wenn es die ClassName fightresultsinner gibt, dann Set... sonst ...
Anzeige
AW: Nicht über eine txt, sondern direkt übers DOM
24.05.2017 21:50:52
Zwenn
VBA gut? ;-)
Du brauchst doch nur abfragen, ob fightresultsinner vorhanden ist und das entsprechend in Deine Makro Struktur aufnehmen. Wenn nicht vorhanden, wirds wohl nicht die Ergebnisseite eines Kampfes sein. Das wäre dann die Billigvariante:

Sub Startfarm(myUrl As String)
Dim oIE As Object
Dim bolhidden As Boolean
Dim knotenAst As Object
bolhidden = ThisWorkbook.Worksheets("Einstellungen").Range("B2")
'INternetexplorer starten
Set oIE = CreateObject("InternetExplorer.Application")
oIE.Visible = bolhidden
oIE.Navigate myUrl
' Warten, bis die Seite geladen ist
Do While oIE.busy
DoEvents
Loop
Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0)
If Not knotenAst Is Nothing Then
MsgBox "Die ist nicht die Ergebnisseite für einen Kampf" & Chr(13) & Chr(13) & "(Bitte  _
einloggen oder einen Ritter angreifen, der kampfbereit ist)"
Else
Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0). _
GetElementsByTagName("p")(0).GetElementsByTagName("em")(0)
If Not knotenAst Is Nothing Then
MsgBox knotenAst.innertext
Else
MsgBox "Kein Gewinn"
End If
End If
oIE.Quit
Set oIE = Nothing
End Sub
Allerdings würde ich die Sub in eine Function umwandeln und den zurückgegebenen Wert verarbeiten. Der zurück gegebene Wert ist ein String, den Du in der aufrufenden Routine verarbeiten kannst. Damit wird der Code insgesamt übersichtlicher.
Die "teurere" Variante wäre übrigens, dass Du Dir ansiehst, welche Seiten ansonsten geladen werden können und auf diese reagierst. Dafür musst Du auf jeder Seite etwas eindeutiges identifizieren, woraus Du ableiten kannst, welche Seite das nun ist. Dann kannst Du ganz gezielt auf jede Seite reagieren. Ist halt mehr Aufwand.
Anzeige
AW: Nicht über eine txt, sondern direkt übers DOM
24.05.2017 21:55:17
Zwenn
Sorry, habs genau verkert herum aufgeschrieben.

Sub Startfarm(myUrl As String)
Dim oIE As Object
Dim bolhidden As Boolean
Dim knotenAst As Object
bolhidden = ThisWorkbook.Worksheets("Einstellungen").Range("B2")
'INternetexplorer starten
Set oIE = CreateObject("InternetExplorer.Application")
oIE.Visible = bolhidden
oIE.Navigate myUrl
' Warten, bis die Seite geladen ist
Do While oIE.busy
DoEvents
Loop
Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0)
If Not knotenAst Is Nothing Then
Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0). _
GetElementsByTagName("p")(0).GetElementsByTagName("em")(0)
If Not knotenAst Is Nothing Then
MsgBox knotenAst.innertext
Else
MsgBox "Kein Gewinn"
End If
Else
MsgBox "Die ist nicht die Ergebnisseite für einen Kampf" & Chr(13) & Chr(13) & "(Bitte  _
einloggen oder einen Ritter angreifen, der kampfbereit ist)"
End If
oIE.Quit
Set oIE = Nothing
End Sub

Anzeige
AW: Nicht über eine txt, sondern direkt übers DOM
24.05.2017 22:42:28
Florian
Kein Kommentar bitte :)
Ich dachte
Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0)

geht nicht, weil es diesen Ast ja einfach nicht gibt, wenn ich auf der falschen Seite bin.
Aber haut hin.
AW: Nicht über eine txt, sondern direkt übers DOM
24.05.2017 22:43:37
Florian
Ja, ist auch so.
Manchmal (ich habe noch nicht genau herausgefunden wann) kommt der Fehler das das Objekt die Methode nicht unterstützt.
AW: Nicht über eine txt, sondern direkt übers DOM
24.05.2017 22:45:54
Florian
Jetzt kommt der Fehler bei jeder Ausführung.
Es macht ja keinen Unterschied ob ich die Variable
Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0)

oder mit
        Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0). _
GetElementsByTagName("p")(0).GetElementsByTagName("em")(0)
belege, wenn es gar keinen "FightResultsInner" gibt, kommt der Fehler doch in beiden Fällen gleichermaßen, oder habe ich da jetzt einen Denkfehler?
AW: Nicht über eine txt, sondern direkt übers DOM
24.05.2017 22:58:54
Florian
Hier nochmal mein Code wie er bisher aussieht:
Option Explicit
Const cURL_BK As String = "https://s21-de.battleknight.gameforge.com/duel/duel/?enemyID="
Const cSchreibSpalte As String = "E"
Sub Farm()
On Error GoTo EH
'Aktive Reihe auslesen
Dim Reihe As Long
Reihe = ActiveCell.Row
'URL zusammenbauen
Dim URL As String
With ThisWorkbook.Worksheets("Farm")
If IsNumeric(.Range("B" & Reihe)) Then
URL = cURL_BK & .Range("B" & Reihe)
'Farm starten und Beute Schreiben
.Range(cSchreibSpalte & Reihe) = Startfarm(URL)
Else
MsgBox "bitte Farm auswählen"
End If
End With
Fertig:
Exit Sub
EH:
MsgBox Err.Description & "ModulFarm.Farm"
End Sub
Function Startfarm(myUrl As String) As String
On Error GoTo EH
Dim bolhidden As Boolean
bolhidden = ThisWorkbook.Worksheets("Einstellungen").Range("B2")
'Internetexplorer starten
Dim oIE As Object
Set oIE = CreateObject("InternetExplorer.Application")
oIE.Visible = bolhidden
oIE.Navigate myUrl
' Warten, bis die Seite geladen ist
Do While oIE.busy
DoEvents
Loop
'erbeutetes Silber auslesen
Dim knotenAst As Object
Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0). _
GetElementsByTagName("p")(0).GetElementsByTagName("em")(0)
If Not knotenAst Is Nothing Then
Startfarm = knotenAst.innertext
Else
Startfarm = "x"
End If
'IE wieder beenden, wenn nicht angezeigt
If bolhidden = False Then
oIE.Quit
Set oIE = Nothing
End If
Fertig:
Exit Function
EH:
MsgBox Err.Description & "ModulFarm.StartFarm"
End Function

AW: Nicht über eine txt, sondern direkt übers DOM
25.05.2017 14:57:00
Zwenn
Hallo Florian,
ob es einen Unterschied macht, welche der beiden Zeilen Du Abfragst kann ich nicht beantworten. Das was ich habe, um mir einen Eindruck Deines Problems zu verschaffen, ist der HTML-Code, den Du im ersten Posting dieses Threads als txt-Datei angehängt hast. Alles andere ist bei mir nur: "Ich denke mir, dass es so oder so sein könnte."
Was habe ich mir also gedacht?
  • Das die richtige Seite geladen wird (Ausgangssituation dieses Threads)

  • Das die richtige Seite geladen wird, aber kein erbeutetes Silber ausgewiesen wird (keine Ahnung, ob es das gibt)

  • Das die falsche Seite geladen wird (hast Du gesagt, ich weiß aber nichts weiter über diese Seiten)

  • Dein erstes Problem, wie Du an den Silberwert kommst, haben wir ja direkt gelöst. Du bist dann aber auf weitere Probleme gestoßen (was völlig normal ist) und hast hier gefragt. Meine Ausgangssituation blieb aber gleich. Also habe ich etwas im Nebel gestochert.
    Weil ich davon ausgehe, dass "fightResultsInner" ein sprechender Name ist, den die Entwickler bewußt gewählt haben, gehe ich im Umkehrschluss also davon aus, dass er seinem Sinn nach auf keiner anderen Seite verwendet wird. Also habe ich diese Annahme verwendet, um Deine Frage nach dem Abfangen einer falsch geladenen Seite zu beantworten.
    Wenn Du einen Objektfehler bekommst, liegt das aber an keiner der beiden Zeilen. Denn Set versucht das Objekt knotenAst nach der folgenden Vorgabe in der Zeile zu bilden. Wenn das nicht geht, dann ist das Objekt Nothing. Genau das Prüfen wir aber in der Zeile danach und reagieren entsprechend: If Not knotenAst Is Nothing Then
    Ich benutze in meiner Version "fightResultsInner" zwar zweimal, aber das passiert, um unterschiedliche Dinge in Erfahrung zu bringen. Nämlich die, die ich oben als Liste aufgeschrieben habe. Als erstes wird geprüft, ob überhaupt die richtige Seite geladen wurde. Das kann nach meinem Gedankengang nur der Fall sein, wenn "fightResultsInner" überhaupt verwendet wird. Wenn das gar nicht gefunden wird, liefert die Funktion Startfarm() direkt zurück, dass die falsche Seite geladen wurde. Wenn "fightResultsInner" gefunden wurde (und wir also auf der richtigen Seite unterwegs sind), wird geprüft, ob sich ein Silberbetrag auslesen lässt. Dabei wird "fightResultsInner" zwar auch abgefragt, aber nur als Bestandteil des Pfades zum Silberbetrag. Die Prüfung, ob sich ein Betrag auslesen lässt hängt deshalb gar nicht mehr von "fightResultsInner" ab, sondern davon, ob der ganze Pfad funkitioniert. Wenn er funktioniert ist das Objekt vorhanden und die Funktion Startfarm() liefert der Silberwert zurück. Wenn das Objekt knotenAst jedoch an dieser Stelle des Makros Nothing ist, sind wir zwar auf der Ergebnisseite eines Kampfes, es wird aber kein Silberbetrag ausgewiesen.
    Ich habe mal Deinen Makro Code genommen und ihn an meine Gedankengänge angepasst. Ausserdem habe ich ihn entschlackt und sortiert. Dazu sage ich noch was nach dem folgenden Code, dem Du auch nochmal die grade erfolgten Erklärungen an den richtigen Stellen als Kommentare entnehmen und direkt zuordnen kannst:
    
    Option Explicit
    Sub Farm()
    Const cURL_BK As String = "https://s21-de.battleknight.gameforge.com/duel/duel/?enemyID="
    'Testfälle
    'Const cURL_BK As String = "file:///E:/Dokumente/Herber%20Forum/Wert%20von%20Webseite% _
    20holen%20(Ritterspiel)/Ergebnis.htm"
    'Const cURL_BK As String = "file:///E:/Dokumente/Herber%20Forum/Wert%20von%20Webseite% _
    20holen%20(Ritterspiel)/KeinErgebnis.htm"
    'Const cURL_BK As String = "file:///E:/Dokumente/Herber%20Forum/Wert%20von%20Webseite% _
    20holen%20(Ritterspiel)/FalscheSeite.htm"
    Dim Reihe As Long
    Dim ieAnzeige As Boolean
    Dim URL As String
    'Aktive Reihe auslesen
    Reihe = ActiveCell.Row
    'Anzeige IE ja oder nein
    ieAnzeige = ThisWorkbook.Worksheets("Einstellungen").Range("B2")
    'URL zusammenbauen
    With ThisWorkbook.Worksheets("Farm")
    If IsNumeric(.Range("B" & Reihe)) Then
    URL = cURL_BK & .Range("B" & Reihe)
    'Farm starten und Beute Schreiben
    .Range("E" & Reihe) = Startfarm(URL, ieAnzeige)
    Else
    MsgBox "bitte Farm auswählen"
    End If
    End With
    End Sub
    Function Startfarm(myUrl As String, bolhidden As Boolean) As String
    Dim oIE As Object
    Dim knotenAst As Object
    'Internetexplorer starten
    Set oIE = CreateObject("InternetExplorer.Application")
    oIE.Visible = bolhidden
    oIE.Navigate myUrl
    ' Warten, bis die Seite geladen ist
    Do While oIE.busy: DoEvents: Loop
    'Prüfen ob Ergebnisseite eines Kampfes angezeigt wird
    'Das Kriterum dafür ist, ob die CSS Klasse "fightResultsInner" verwendet wird
    Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0)
    'Konnte das Objekt nicht gebildet werden
    'direkt mit dem Else-Zweig weitermachen
    If Not knotenAst Is Nothing Then
    'Wenn die richtige Seite geladen wurde,
    'versuchen erbeutetes Silber auszulesen
    Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0). _
    GetElementsByTagName("p")(0).GetElementsByTagName("em")(0)
    'Prüfen, ob das Objekt, in dem der Silberbetrag
    'steht gebildet werden konnte
    If Not knotenAst Is Nothing Then
    'Wenn das Objekt gebildet werden konnte, absahnen
    Startfarm = knotenAst.innertext
    Else
    'Wenn das Objekt nicht gebildet werden konnte,
    'wird auf der Ergebnisseite kein Gewinn angezeigt
    'oder er steht in einem anderen Teil des HTML Dokuments
    Startfarm = "x"
    End If
    Else
    'Wenn die falsche Seite geladen wurde,
    'diesen Umstand der aufrufenden Routine
    'mitteilen
    Startfarm = "Falsche Seite"
    End If
    'IE wieder beenden, wenn nicht angezeigt
    If bolhidden = False Then
    oIE.Quit
    Set oIE = Nothing
    End If
    End Function
    
    Folgendes habe ich geändert:
  • Änderung 1: Die Konstanten waren global definiert, ich habe sie in den lokalen Teil der Hauptfunktion verschoben.
    Grund: Ich halte globale Werte persönlich nicht nur für schlecht, sondern für grundlegend falsch. Globale Werte sollten vermieden werden, weil sie den Code unübersichtlich machen, wenn man sie in irgendwelchen Funktionen verwendet (geht in VBA leider nicht konsequent, hier aber sehr einfach)

  • Änderung 2: Die Konstante, in der Du die Spalte hinterlegt hast, in die geschrieben werden soll, habe ich rausgeschmissen.
    Grund: Dieser Wert wird nur an einer einzigen Stelle im ganzen Code verwendet. Darüber hinaus gibt es im gleichen Codeabschnitt die Verwendung des Spaltenwertes "B", der aber nicht extra als Konstante oder Variable vereinbart wurde. Das wirkte etwas inkonsistent vom Programmierstil her.

  • Änderung 3: Ich habe den Booleanwert, der darüber entscheidet, ob der IE angezeigt wird oder nicht, aus der Funktion Startfarm() in die Hauptroutine Farm() verschoben und sowohl die Parameterliste von Startfarm() entsprechend erweitert, wie auch den Funktionsaufruf in Farm().
    Grund: Es ist übersichtlicher, wenn die von außen beeinflussbaren Daten sich an einer Stelle im Code versammeln. Darüber hinaus ist die Funktion Startfarm() jetzt frei von direkten Zugriffen auf die Tabelle und ihr Code kann einfacher wiederverwendbar. Im Endeffekt ist das die Konsequente Fortführung, warum wir aus der alten Sub Startfarm() eine Funktion gemacht haben. Dabei haben wir dafür gesorgt, dass das Ergebnis in der Hauptroutine Farm() verarbeitet wird. Dort laufen also die Daten-Fäden zusammen. In diesem Makro erscheint das trivial. Bei größerem Code-Umfang wird es aber wichtig, um die Daten im Auge zu behalten. Also sollte dieses Prinzip konsequent angewendet werden.

  • Änderung 4: Alle lokalen Variablen Deklarationen (Zeilen die mit Dim beginnen), wurden von mir an den Anfang der beiden vorhandenen Routinen Farm() und Stratfarm() verschoben.
    Grund: Auch das dient der Übersichtlichkeit. So stehen alle verwendeten lokalen Werte an einer Stelle und man kann sie auf einen Blick erfassen. Ein mitten im Quelltext auftauchendes Dim URL As String erscheint an der Stelle erstmal sinnvoll. Aber wie gesagt, ist es unübersichtlich, ausserdem gibt es bei größerem Code-Umfang durchaus Situationen, in denen ein Zugriff auf eine vielleicht erst weiter unten deklarierte Variable notwendig ist. Die Folge ist ein Fehler, weil die Variable dem Makro an der zuerst verwendeten Stelle noch gar nicht bekannt ist

  • Änderung 5: Die On Error Konstrukte habe ich ersatzlos rausgeschmissen
    Grund: Wozu sollen die gut sein?

  • Änderung 6: Ich habe die Funktion Startfarm() um die If-Then-Else-Klammer für die Abfrage auf die richtig aufgerufene Seite erweitert.
    Grund: Deine Frage danach ;-) Habe ich oben schon lang und breit ausgewalzt.

  • So, wenn Du das durchgekaut hast, kommen die nächsten Fragen ;-)
    Viele Grüße,
    Zwenn
    AW: Nicht über eine txt, sondern direkt übers DOM
    26.05.2017 22:00:57
    Florian
    Ich glaube ich habs doch noch nicht ganz verstanden.
    Habe eine neue Seite in den Live Dom Viewer geschmissen.
    Hier der relevante Auszug (hier das ganze, falls ich Müll für relevant halte: https://www.herber.de/bbs/user/113815.txt)
    
    [table id="profileDetails" class="profileTable" width="100%" border="0" cellspacing="0"  _
    cellpadding="0"]
    [tr]
    [th scope="row"]
    Stufe:
    [/th]
    [td]
    66				[/td]
    [/tr]
    [tr]
    [th scope="row"]
    Orden				[/th]
    [td]
    

    Ich möchte die Stufe auslesen, folgender Versuch (habe mich bewusst sehr an das alte Schema gehalten, weil ich hier weiß, dass wenigstens der Code läuft :)
    Sub test()
    Dim oIE As Object
    Dim knotenAst As Object
    'Internetexplorer starten
    Set oIE = CreateObject("InternetExplorer.Application")
    oIE.Visible = True
    oIE.Navigate "https://s21-de.battleknight.gameforge.com/common/profile/234/Scores/Player"
    ' Warten, bis die Seite geladen ist
    Do While oIE.busy: DoEvents: Loop
    'Prüfen ob Ergebnisseite eines Kampfes angezeigt wird
    'Das Kriterum dafür ist, ob die CSS Klasse "fightResultsInner" verwendet wird
    Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0)
    'Konnte das Objekt nicht gebildet werden
    'direkt mit dem Else-Zweig weitermachen
    If Not knotenAst Is Nothing Then
    'Wenn die richtige Seite geladen wurde,
    'versuchen erbeutetes Silber auszulesen
    Set knotenAst = oIE.document.GetElementsByClassName("profileTable")(0). _
    GetElementsByTagName("tr")(0).GetElementsByTagName("td")(0)
    'Prüfen, ob das Objekt, in dem der Silberbetrag
    'steht gebildet werden konnte
    If Not knotenAst Is Nothing Then
    'Wenn das Objekt gebildet werden konnte, absahnen
    Debug.Print knotenAst.innertext
    Else
    'Wenn das Objekt nicht gebildet werden konnte,
    'wird auf der Ergebnisseite kein Gewinn angezeigt
    'oder er steht in einem anderen Teil des HTML Dokuments
    Debug.Print "x"
    End If
    Else
    'Wenn die falsche Seite geladen wurde,
    'diesen Umstand der aufrufenden Routine
    'mitteilen
    Debug.Print "x"
    End If
    End Sub
    
    Mein Ergebnis ist immer "x"
    warum?
    AW: Nicht über eine txt, sondern direkt übers DOM
    26.05.2017 22:03:19
    Florian
    Edit:
    Diese Zeile:
        'Prüfen ob Ergebnisseite eines Kampfes angezeigt wird
    'Das Kriterum dafür ist, ob die CSS Klasse "fightResultsInner" verwendet wird
    Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0)
    
    lautet natürlich
    Set knotenAst = oIE.document.GetElementsByClassName("profileTable")(0)
    

    AW: Nicht über eine txt, sondern direkt übers DOM
    26.05.2017 22:11:56
    Florian
    Ah jetzt kommt es:
            Set knotenAstLVL = oIE.document.GetElementsByClassName("profileTable")(0). _
    GetElementsByTagName("tr")(0).GetElementsByTagName("td")(0)
    

                    Set knotenAstOrden = oIE.document.GetElementsByClassName("profileTable")(0). _
    GetElementsByTagName("tr")(1).GetElementsByTagName("td")(0)
    
    Hast du eventuell einen Link zu einer Übersicht wonach ich alles suchen kann?
    AW: Nicht über eine txt, sondern direkt übers DOM
    27.05.2017 08:57:15
    Florian
    Ich habs geschafft und erfolgreich den Spielernamen, das Level und den Orden ausgelesen :)
    Heute oder morgen mache ich mich dann ans erkennen der Startseite und Eintragen der Login Daten.
    Aber dazu mache ich mal besser einen neuen Thread auf.
    Das freut mich :-) (owT)
    30.05.2017 13:44:45
    Zwenn
    ohne weiteren Text
    AW: Nicht über eine txt, sondern direkt übers DOM
    25.05.2017 17:00:04
    Florian
    Hier nochmal mein Code wie er bisher aussieht:
    Option Explicit
    Const cURL_BK As String = "https://s21-de.battleknight.gameforge.com/duel/duel/?enemyID="
    Const cSchreibSpalte As String = "E"
    Sub Farm()
    On Error GoTo EH
    'Aktive Reihe auslesen
    Dim Reihe As Long
    Reihe = ActiveCell.Row
    'URL zusammenbauen
    Dim URL As String
    With ThisWorkbook.Worksheets("Farm")
    If IsNumeric(.Range("B" & Reihe)) Then
    URL = cURL_BK & .Range("B" & Reihe)
    'Farm starten und Beute Schreiben
    .Range(cSchreibSpalte & Reihe) = Startfarm(URL)
    Else
    MsgBox "bitte Farm auswählen"
    End If
    End With
    Fertig:
    Exit Sub
    EH:
    MsgBox Err.Description & "ModulFarm.Farm"
    End Sub
    Function Startfarm(myUrl As String) As String
    On Error GoTo EH
    Dim bolhidden As Boolean
    bolhidden = ThisWorkbook.Worksheets("Einstellungen").Range("B2")
    'Internetexplorer starten
    Dim oIE As Object
    Set oIE = CreateObject("InternetExplorer.Application")
    oIE.Visible = bolhidden
    oIE.Navigate myUrl
    ' Warten, bis die Seite geladen ist
    Do While oIE.busy
    DoEvents
    Loop
    'erbeutetes Silber auslesen
    Dim knotenAst As Object
    Set knotenAst = oIE.document.GetElementsByClassName("fightResultsInner")(0). _
    GetElementsByTagName("p")(0).GetElementsByTagName("em")(0)
    If Not knotenAst Is Nothing Then
    Startfarm = knotenAst.innertext
    Else
    Startfarm = "x"
    End If
    'IE wieder beenden, wenn nicht angezeigt
    If bolhidden = False Then
    oIE.Quit
    Set oIE = Nothing
    End If
    Fertig:
    Exit Function
    EH:
    MsgBox Err.Description & "ModulFarm.StartFarm"
    End Function
    

    AW: Nicht über eine txt, sondern direkt übers DOM
    25.05.2017 17:08:16
    Florian
    Ay, da hatte ich wohl einen Denkfehler.
    Denn nach deinem letzten Post habe ich dann keine Ahnung mehr, wo der Fehler, welcher bei mir auftrat herkommt.
    Du sagst, wenn es den Zweig auf den knotenAst zielt nicht gibt, ist knotenAst einfach nothing.
    Meiner Logik nach kam der Fehler daher, dass knotenAst auf etwas verweist, was es nicht gibt.
    Aber nach ersten Tests, scheint der Code sauber (also ohne den entsprechenden Fehler) zu laufen.
    Wenn du erlaubst möchte ich jedoch einige Fragen zu deinen Änderungen stellen
    (Fragen zum eigentlichen Code kommen bestimmt auch noch^^)
    Den Code habe ich nämlich gestern, nachdem ich ein Webinar von Paul Kelly gesehen habe (https://excelmacromastery.com) noch ein wenig umgestellt.
    Änderung1 globale Variablen und auch Änderung2:
    Dies habe ich gemacht, weil ich an anderen Stellen (Modulen) ebenfalls auf diese Variablen zugreife.
    (Das hätte ich jedoch besser erwähnen sollen) - wenn ich nun die Struktur meiner Tabelle umändere, brauche ich nur an einer einzigen Stelle ein paar Variablen ändern und alles läuft weiter.
    Änderung3 nehme ich dankend hin, ist ja eigentlich nur logisch was du schreibst.
    Änderung4 ist wohl eher eine Geschmackssache (behaupte ich als halb jähriger VBA Anfänger, ich behaupte beides hat vor und Nachteile.
    Änderung5 sollte dazu dienen, dass ein eventueller Anwender den Excel Fehler nicht sieht und nicht im Code landet - für meine Zwecke natürlich wurscht

    305 Forumthreads zu ähnlichen Themen

    Anzeige
    Anzeige
    Anzeige

    Beliebteste Forumthreads (12 Monate)

    Anzeige

    Beliebteste Forumthreads (12 Monate)

    Anzeige
    Anzeige
    Anzeige