Live-Forum - Die aktuellen Beiträge
Anzeige
Archiv - Navigation
1572to1576
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

Internet Datenabfrage

Internet Datenabfrage
07.08.2017 15:53:57
Marco
Hallo,
ich versuche Daten von einer Webseite zu sammeln. Dazu nutze ich einen Code, der mir an anderer Stelle hier im Herber-Forum gezeigt wurde.
Es geht um diese Webseite: https://www.apg.at/de/markt/Markttransparenz/Netzregelung/Sekundaerregelreserve
Dort muss ich zum einem nur das Wunschdatum einstellen und auf "Tabelle" klicken. Anschließend würde ich mir die gesuchten Daten heraussuchen. Leider passiert nichts bei der Datumseingabe (wird übersprungen). Die Code-Zeile zum klicken auf "Tabelle" habe ich noch nicht geschrieben, da ja nicht mal mein Code zur Datumseingabe funktioniert.Ich hoffe ihr könnt helfen.
Der Code:

Sub Austria()
wbAE = ActiveWorkbook.Name
wkshAE = ActiveSheet.Name
myDate = Workbooks(wbAE).Sheets(wkshAE).Range("G1")
'Tabelle namens "RZ_SALDO" erstellen
Dim ie As Object, daten As Object, zeile As Object, zelle As Object, Startdate As Date,  _
objCollection As Object
Dim lZeile As Long, lSpalte As Long, anzahlTage As Integer, i As Integer
lZeile = 1: lSpalte = 1
'Beispiel vom 3.06.2017 bis 5.06.2017
Startdate = CDate(myDate) 'Startdatum anpassen
anzahlTage = 1 'Anzahl der Tage anpassen
Set ie = CreateObject("InternetExplorer.Application")
ie.Visible = True
ie.navigate "https://www.apg.at/de/markt/Markttransparenz/Netzregelung/Sekundaerregelreserve"
While ie.Busy
DoEvents
Wend
Do: Loop Until ie.document.readyState = "complete"
Do: Loop Until ie.document.readyState = "complete"
For i = 0 To anzahlTage - 1
'--------setze Datum ein---------------------------------
Set objCollection = ie.document.getElementsByTagName("input")
For Each itm In objCollection(i).all
If itm = "from" Then
itm.Value = CStr(CDate(Startdate + i))
End If
Next
ie.document.getElementById("vc_btnShow").Click
Do: Loop Until ie.document.readyState = "complete"
'-----finde und kopiere gesuchte Werte--------------------
Set daten = ie.document.getElementById("vc_tbTable")
lZeile = 1
For Each zeile In daten.Rows
For Each zelle In zeile.Cells
If lSpalte = 9 Or lSpalte = 10 Then
Workbooks(wbAE).Worksheets(wkshAE).Cells(lZeile + 5, lSpalte + 14) = Format(zelle. _
innerText, "0000")
End If
lSpalte = lSpalte + 1
Next
lSpalte = 1
lZeile = lZeile + 1
Next
Next
ie.Quit
End Sub

SG Marco
P.S.: kennt jmd. eine gute Seite wo VBA-Codes im Zusammenhang mit Internet erklärt werden?

4
Beiträge zum Forumthread
Beiträge zu diesem Forumthread

Betreff
Datum
Anwender
Anzeige
Ein paar Anmerkungen, nicht erschöpfend
07.08.2017 17:19:40
Zwenn
Hallo Marco,
es fällt mir schwer zu glauben, dass Du den von Dir geposteten Code hier aus dem Forum hast. Ich gehe davon aus, dass Du einen Quellcode genommen und versucht hast ihn so umzustricken, dass er für Deine Zwecke paßt. Kann das sein?
Ich nenne mal ein paar Punkte, warum Dein Makro nicht funktioniert:
  • DIM Anweisungen gehören grundsätzlich nach vorne. Du kannst doch keine Variablen initialisieren, die gar nicht deklariert sind (Tabellen- und Workbookname)

  • Schreib ganz oben ins Modul immer Option Explicit Dadurch prüft der VBA Interpreter vor Ausführung des Makro, ob alle verwendeten Variablen auch deklariert wurden. Bei Dir fehlen so einige.

  • Das Warten auf den Browser ist kein Befehl, der das Dokument betrifft. Deshalb heißt es nicht Do: Loop Until ie.document.readyState = "complete" sondern Do: Loop Until ie.readyState = "complete"

  • Ein Array, das Du über die getElementsBy-Befehle bildest, wird durch For Each ohne weitere Strukturangaben durchlaufen. Also nicht For Each itm In objCollection(i).all sondern For Each itm In objCollection

  • Du willst mehrere Daten durchlaufen, definierst aber nur ein Startdatum. Wo ist das Endedatum und wozu switcht Du myDate auf Startdate um? Das ist doch genau das Gleiche.

  • Wenn Du die Seite aufrufst, das Datum platzierst und dann den Link Tabelle aufrufst, wird die Tabelle mit den richtigen Inhalten zum gewählten Datum aufgerufen. Aber nur einmal. Wenn Du anschließend ein neues Datum wählst, kannst Du nicht noch einmal auf einen Link namens Tabelle klicken, weil es den nicht mehr gibt. Du bist schon auf Tabelle. Du musst also Tabelle aufrufen, dann das Datum eingeben und dann auf den Button Anzeigen klicken. Danach kannst Du ein neues Datum eingeben und wieder auf Anzeigen klicken, usw.

  • ...

  • Da sind mit Sicherheit noch mehr grundsätzliche Fehler drin. Wer Dir also helfen will, der muss Dir das Teil komplett schreiben, weil Dein Code so unbrauchbar ist. Dazu muss man sich aber eingehend mit dem Quellcode der Seite beschäftigen, von der Du die Daten holen willst. Dazu habe ich im Moment leider keine Zeit.
    Du fragtest nach Seiten, die sich mit VBA und Internet beschäftigen. Eine Seite, die genau diese Kombination behandelt ist mir nicht bekannt. Womit Du Dich aber beschäftigen solltest, ist das Document Object Model (DOM) des Internet Explorers:
    https://msdn.microsoft.com/en-us/library/hh772384(v=vs.85).aspx
    Unter Basic DOM Reference und dann Methods, findest Du z.B. die Erklärungen zu den GetElemetsBy befehlen. Da das Ganze fürs Internet gedacht ist, sind die Codebeispiele meistens in JavaScript. Das ist aber nicht so wild. Die Beschreibungen kannst Du 1 zu 1 auch in VBA umsetzen.
    Viele Grüße,
    Zwenn
    Anzeige
    Habe mir die Zeit genommen, die ich nicht hatte
    08.08.2017 02:27:44
    Zwenn
    Hallo Marco,
    nun habe ich mich doch dran gesetzt. Also, es funktioniert nicht mal im Ansatz so, wie Du es angefangen hast. Schon der Link ist falsch. Die Tabelle wird in einem iFrame aufgerufen. Da kommst Du über Deinen Link nicht dran. Man muss den direkt aufrufen mit:
    https://www.apg.at/transparency/Visualization.aspx?PRESENTATIONDESCRIPTION=SCP#mode|,|table|,|from|,|20170807|,|resolution|,|15M
    Wie man sieht, ist das Datum enthalten. Deshalb spart man sich das Ganze Steuern über das Datum-Element und den Auslöse-Button. Wir rufen einfach für jeden benötigten Tab im Datums-Zeitraum die Seite neu auf. Das dafür immer der Internet Explorer geschlossen und neu gestartet werden muss, fällt zeitlich nicht ins Gewicht. Ganz im Gegenteil ist es für die Stabilität des Makros sogar von Vorteil. Denn, ruft man innerhalb einer Internet Explorer Instanz oft neue Seiten auf, verhällt er sich gerne instalbil. Das ist jedenfalls meine Erfahrung.
    Auch Dein Versuch die Zeilen und Zellen einfach über For Each durchzugehen, klappt hier nicht. Es handelt sich nicht um einen Table-Tag. Wir haben es mit einem tbody-Tag zu tun, was auch immer das sein mag ;-) Es ist egal, wir gehen über den eindeutigen Namen der ID vc_tbTable und dann durch die Zeilen und einzelenen Zellen pro Zeile.
    Du willst in jeder HTML Zeile Spalte Nr. 9 und 10 auslesen und in der Excel Tabelle ab Zeile 6 in Spalte 15 und 16 eintragen, wenn ich es richtig interpretiert habe. So habe ich es jetzt programmiert. Kann man aber auch einfach ändern.
    In Den Zellen G1 und G2 trägst Du vor dem Makro Aufruf einfach das Start- und das Ende-Datum ein. Dann werden für jeden dieser Tage die genannten Informationen in die Excel Tabelle eingetragen.
    Schau Dir den Quellcode an. Falls was nicht funktioniert, musst Du evtl. die Pause zum Laden der Tabelle anpassen. Die muss man schätzen. Bei mir läuft es sauber mit 3 Sekunden Pause pro Tabellenaufruf. Das ganze Makro ist gut kommentiert. So viele Zeilen Quellcode sind es dann am Ende auch gar nicht geworden. Wie vermutet, war die Analyse der HTML Seite entscheidend für das richtige Vorgehen.
    Die Lösung. Einfach mal den Button drücken ;-)
    https://www.herber.de/bbs/user/115322.xlsm
    Viele Grüße,
    Zwenn
    Anzeige
    AW: Habe mir die Zeit genommen, die ich nicht hatte
    08.08.2017 16:21:22
    Marco
    Hallo Zwenn,
    danke das du dir die Zeit genommen hast. Deine Lösung funktioniert einwandfrei, danke dir dafür.
    Ja, das mit Option Explicit ist mir bekannt, aus Bequemlichkeit mach ich das oft erst zum Schluss wenn alles klappt. Ich muss sehr viel probieren (bzw. andere Codes vom Internet in meinen vorhanden Code reinkopieren), und ich will schnell testen, ohne ständig Variablen deklarieren zu müssen. Einige Variablen (z.B.: wksh) waren nicht deklariert, weil diese zuvor global deklariert waren. Allerdings habe ich diesen Code vom Rest separiert um ihn einzeln testen zu können anstatt jedesmal das ganze Makro durchlaufen zu lassen. Mit der Zeit wird der Code etwas "messy"
     Das Warten auf den Browser ist kein Befehl, der das Dokument betrifft. Deshalb heißt es nicht  _
    Do: Loop Until ie.document.readyState = "complete" sondern Do: Loop Until ie.readyState = "complete"
    
    Den Code habe ich aus einem anderen Themenbeitrag übernommen ("Unregelmäßiger Laufzeit-Fehler 424 Internetabfrage", Lösung von Matthias) und funktionierte einwandfrei. Hat der Code mit und ohne document bzw. zwischen 4 und complete im Allgemeinen also die selbe Wirkung ?
     Wenn Du die Seite aufrufst, das Datum platzierst und dann den Link Tabelle aufrufst,...
    
    Ich weiß der Code hat diese Schleife drinnen:
    
    For i = 0 To anzahlTage - 1
    
    Dies habe ich aus diesem Forumsbeitrag übernommen (Lösung von Anton): URL Download von generierter Datei. Ich ließ es vorerst unangetastet, allerdings rufe ich bisher immer nur einen Tag ab, weswegen es bisher kein Problem darstellte.
    Das mit der URL versuche ich nächstes Mal im Hinterkopf zu behalten. Ich hatte nach deinem Hinweis versucht die entsprechende Zeile im HTML-Quellcode zu finden ohne Erfolg. Erst bei der Nutzung deines Makros hab ich es gesehen ;). Hast du das rein durch Analyse des HTML-Quellcodes herausgefunden? Wenn ich selber manuell die Daten abrufe, sehe ich keine Änderungen in der URL.
    Auch Dein Versuch die Zeilen und Zellen einfach über For Each durchzugehen, ...
    
    Hier bin ich etwas verwirrt. Der verwendete Code ist eine Kopie von Antons Lösung aus dem Forumsbeitrag URL Download von generierter Datei. Auch hier gibt es ein tbody-Tag, der Code klappte einwandfrei weswegen ich ihn erneut verwenden wollte. Für Testzwecke habe ich ihn in deinem Code eingefügt und er funktioniert auch fast einwandfrei. Aber auch nur fast, denn merkwürdigerweise sind die Werte in der ersten Zeile um eine Spalte verruscht, alle anderen Werte stimmen aber. Verstehst du vielleicht warum?
    SG Marco
    Anzeige
    AW: Habe mir die Zeit genommen, die ich nicht hatte
    10.08.2017 21:39:12
    Zwenn
    Hallo Marco,
    ich bin die letzten zwei Tage nicht dazu gekommen Dir ordentlich zu antworten. Aber besser spät als nie :-) Zunächst einmal freut es mich, dass es nun so läuft, wie Du willst. Ich gehe mal davon aus, dass Du die Lösung in Dein Projekt integrieren konntest.
    Zu Deinen Anmerkungen und Fragen folgendes:
  • Option Explicit erst hinzuschreiben, wenn Du fertig bist macht ja eher wenig Sinn finde ich. Das man rumtestet ist ja normal und auch ich kenne natürlich überflüssigen Code, der auch manchmal im Endprodukt stehen bleibt. Z.B. das Modul2 in der Mappe, die ich Dir hochgeladen habe ;-)
    Das Prüfen der Variablen durch den Interpreter finde ich grade bei der Entwicklung hilfreich, weil vor allem falsch geschriebene Variablen dann sofort erkannt und gemeldet werden. Findet die Prüfung nicht statt und Du schreibst eine Variable ausversehen falsch, legt der Interpreter ohne Option Explicit einfach eine neue an. Dann hast Du 2, von denen eine garantiert nicht macht, was Du willst. Bei umfangreicherem Code ist das extrem nervig und aufwändig zu finden. Kann man sich einfach sparen.

  • Du schreibst von nicht deklarierten Variablen, weil diese in Deinem eigentlichen Projekt global deklariert wurden. Da rollen sich mir immer die Zehnägel hoch meine Nackenhaare stellen sich auf ;-) Ich weiß, ich wiederhole mich, weil ich das immer schreibe, wenn es um die Verwendung globaler Variablen geht. Aaaaber troootzdem:
    Globale Variablen sind zu vermeiden!
    Sie wiedersprechen dem Paradigma der strukturierten Programmierung. Der Code wird unübersichtlich und er kann nicht einfach wiederverwendet werden. Das Einzige, was noch schlimmer ist, ist die Verwendung von GoTo. Wenn man Variablen in mehreren Funktionen und Prozeduren benötigt, dann werden sie als Parameter durchgereicht. Das ist ein Grundsatz, den jeder lernt, wenn er professionell in diesem Bereich ausgebildet wird.

  • Die Zeile Do: Loop Until ie.document.readyState = "complete" hat bei mir einen Fehler geworfen, als ich Deinen ersten Code zum laufen bringen wollte. Als ich das .document rausnahm, lief es. Ich habe das nicht weiter hinterfragt oder untersucht. Aber es wundert mich schon, dass Du sagst, bei Dir ging das. Das probiere ich vielleicht nochmal aus. Wenn Du es von Matthias hast, dann habe ich vermutlich etwas übersehen oder einen falschen Rückschluss gezogen.
    Ich verwende allerdings immer die Zeile Do Until ie.ReadyState = 4: DoEvents: Loop. Die macht genau das Gleiche. Warten, bis der Browser die aktuelle Seite ganz geladen hat. Genauso wie While ie.Busy: DoEvents: Wend
    Früher brauchte man so eine Zeile immer mindestens zweimal. Das ist aber schon länger nicht mehr so, einmal reicht. Allerdings gibt es inzwischen Webtechniken, die Daten nachladen, nachdem der Internet Explorer gemeldet hat, dass das Dokument komplett geladen wurde. In der Regel sind das sogenannte AJAX Inhalte.
    https://de.wikipedia.org/wiki/Ajax_(Programmierung)
    Deshalb habe ich die Zeile Application.Wait (Time + TimeValue("00:00:03")) direkt hinter die eben beschriebenen Zeile gesetzt. Wenn man die wegläßt, ist die Tabelle noch nicht nachgeladen, aus der die Daten gelesen werden, um die es Dir geht.
    Für readyState gibt es übrigens 5 Zustände von 0 bis 4, wobei wir 4 verwenden, weil das der Zustand "complete" ist. Du kannst hier nachlesen, wofür readyState sonst noch gut ist:
    https://msdn.microsoft.com/de-de/library/ms534361(v=vs.85).aspx

  • Auch ich erinnere mich an Antons Lösung zum Durchgehen der Zeilen. Allerdings wußte ich nicht mehr, dass es sich da auch um einen tbody-Tag handelte. Als ich es ausprobierte, lief der Code nicht, weshalb ich ihn änderte. Man kann die Werte aus Spalte 9 und 10 ja auch direkt abgreifen, wie ich es gemacht habe. Die Kommentare darüber sind allerdings noch falsch. Die gehörten zu Antons Code. Auch das muss ich mir ggf. noch einmal ansehen, um selber zu verstehen, warum Antons Code hier nicht lief. Zu meiner Verteidigung ;-) muss ich allerdings dazu sagen, dass es echt schon spät war, als ich den Code zum Abschluss brachte. Siehst Du ja an der Uhrzeit meines entsprechenden Postings.
    Das der Code bei Dir läuft zeigt ja auch, dass ich wohl was falsch gemacht habe bei seiner Anwendung. Die Verschiebung um eine Spalte müsste ich mir nochmal ansehen. Ad Hoc schätze ich, das liegt daran, dass der Code anfängt bei 0 zu zählen und nicht bei 1.

  • Du fragst, ob ich das mit der Tabelle und dem zugehörigen Link durch die Analyse des Quelltextes rausgefunden habe. Die einfache Antwort lautet, ja. Ich versuche mal zu erklären, wie ich das gemacht habe, also, was ich mir bei meinem Vorgehen gedacht habe. Sei Dir aber bewußt, dass das für andere Seiten ganz anders aussehen kann.
    Ich habe mir zunächst mal den Quelltext der Seite angesehen. Natürlich nicht von oben nach unten, weil ja zunächst eigentlich erstmal interessierte, wie man an das Kalender Element kommt. Da kam man über den Quelltext Deines Links gar nicht dran. Das Kalender Element taucht nicht auf. Ich habe dann einen Zeitstempel aus den Daten der Tabelle kopiert und im Quelltext gesucht. Auch der tauchte nicht auf.
    Also habe ich mir einen Teil des Textes kopiert, der direkt über der Tabelle auf der normalen Seite auftaucht. Dieser wurde gefunden. Dazu eine Anmerkung, die Du Dir merken musst:
    Der Text genau über der Tabelle lautet auf meinem Bildschirm Downloadbereich zurückzugreifen. Wenn Du den kopierst, findest Du ihn im Seitenquelltext nicht. Das liegt am ü im Wort zurückzugreifen. Das ist ein Sonderzeichen und wenn eine HTML Seite richtig damit umgeht, dann werden solche Zeichen mit einem eigenen HTML Code kodiert. Schau dazu in solche Tabellen:
    https://wiki.selfhtml.org/wiki/Referenz:HTML/Zeichenreferenz
    Um also die richtige Stelle im Seitenquelltext zu finden, sucht man einfach nur die Zeichen davor: Downloadbereich zur
    Ich bin dann im Quelltext einfach weiter nach unten gegangen und habe ausschau danach gehalten, wo die gesuchte Tabelle eingebettet wird. Denn die muss ja irgendwo auftauchen, schließlich wird sie angezeigt. Dadurch bin ich auf den genannten iFrame gestoße und mir war klar, das sich in genau dem die Tabelle befinden muss. Aber nicht nur die Tabelle, sondern auch ihre gesamte Funktionalität mit Kalender Element und Anzeigen Button.
    Zunächst kommt im Code der Seite die Anzeige der rechten Spalte, dem Download Bereich. Aber dann kommt die Zeile [iframe src="https://www.apg.at/transparency/Visualization.aspx?PRESENTATIONDESCRIPTION=SCP" name="iframe_application" frameborder="0" style="z-index: 1; display: inline; position: relative;" width="100%" height="950" scrolling="auto"][/iframe] und danach kommt Zeugs, dass unter der Tabelle angezeigt wird. Also muss der iFrame das entscheidende Element sein.
    Da steht der Link, den ich im Makro verwende allerdings gar nicht drin. Wie bekommen wir den also? Ziemlich einfach. Kopiere den iFrame Link https://www.apg.at/transparency/Visualization.aspx?PRESENTATIONDESCRIPTION=SCP and füge ihn einfach in einen eigenen Browser Tab ein. Wenn Du den abschickst, wird die Tabelle mit Bedienelementen aufgerufen. Klicke nun auf den Tab Tabelle und der Link in der URL Zeile ändert sich in den gesuchten und von mir verwendeten.
    Das dort das Datum enthalten ist muss man einfach sehen. Ich war selbst von der Form des Links überrascht, weil die einzelnen Parameter mit Pipes (dem senkrechten Strich) abgeteilt sind. Das ist eigentlich kein Standard, aber es funktioniert einwandfrei und das habe ich einfach ausgenutzt.
    Das klingt jetzt, als hätte ich diesen Weg direkt beschritten und war nach 5 Minuten am Ziel. So war es natürlich nicht. Ich gehe mal davon aus, dass Du Teile in der Tabelle markiert hast und dir dann den Seitenquelltext zum ausgewählten Bereich hast anzeigen lassen. Sonst wärst Du nicht auf die ID des Kalender Elements gekommen. So bin ich auch erst vorgegangen und habe auch einiges Programmiert, weil ich dachte, der Quelltext ist zwar nicht zu sehen, aber vielleicht ist er trotzdem da und lässt sich verwenden. Das habe ich auch schon erlebt, hier war es aber nicht der Fall.
    Das man den Inhalt des iFrames komplett als eigene Seite laden kann muss wahrscheinlich auch nicht immer so sein. Hier werden einfach auch alle Variablen der zugehörigen Skripte im iFrame gahandelt. Wenn das nicht so ist, muss man wieder einen neuen Weg finden.

  • So, ich glaube jetzt habe ich alles :-) Ich wünsche Dir noch viel Spaß mit Deinen Projekten.
    Zwenn
    Anzeige

    Links zu Excel-Dialogen

    Beliebteste Forumthreads (12 Monate)

    Anzeige

    Beliebteste Forumthreads (12 Monate)

    Anzeige
    Anzeige
    Anzeige