Avant d'aborder une variante …
… Le principe ne change pas : attendre la valeur zéro de la propriété length d'une collection d'un élément.
Tout dépend d'une condition : pointer correctement au préalable le bon élément …
Peu importe la collection, cela peut aussi être une propriété de l'élément vidée par la mise à jour
(comme innerHTML), du moment que l'élément est figé dans son statut d'avant mise à jour …
Dans le cas concret de la discussion d'itwoo (voir en première page), le résultat a été trop focalisé,
à savoir récupérer une table d'une page de cotations depuis le site NASDAQ.
Or cette table ne dispose pas de propriété id, name, … permettant de l'identifier à coup sûr !
Lors d'un changement récent de l'index de cet élément dans la collection des tables dans le code source
de la page web, la contribution d'origine s'est retrouvée logiquement prise en défaut …
Certains scanneraient toutes les tables en cherchant un repère l'identifiant
comme par exemple le titre de la première colonne "Date" …
Ou encore comme dans le post #42 en pointant directement l'avant-dernière table et en vérifiant ce titre.
Mais ce serait comme un collège de neurologues au chevet d'un VIP fouillant les méandres de son cerveau
sans voir l'origine de l'infection se situant dès la boîte crânienne !
Un train peut en cacher un autre …
Lors du changement de la période de l'historique, la table visée n'est pas la seule à être mise à jour :
l'en-tête juste au dessus blanc sur fond bleu indiquant la période l'est aussi …
Cet élément et la table ayant le même niveau hiérarchique, en remontant juste d'un cran
leur élément parent dispose lui d'un identifiant : "quotes_content_left_pnlAJAX" …
Du reste via l'inspection du code renvoyé lors de la requête, cet élément apparaît dès la première ligne, Bingo !
De la filiation objet se dévoile une variante …
Comme l'élément parent contient deux éléments, l'en-tête et la table elle-même,
il suffit de verrouiller cet élément parent pour attendre la fin de la mise à jour puis
de pointer de nouveau ce parent sur son deuxième élément pour lire la table à jour !
A coller directement dans le module d'une feuille de calculs :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| Sub DemoNASDAQieB()
Const QUOTE$ = "abbv", TXT$ = " Import en cours "
Application.StatusBar = " Connexion
"
With CreateObject("InternetExplorer.Application")
.Navigate "http://www.nasdaq.com/symbol/" & QUOTE & "/historical"
D! = Timer: F! = D + 9
Do While .Busy Or .ReadyState < 4
If Timer < D Then F = F - 86400: D = 0
If Timer > F Then F = 0: .Stop: Exit Do
Loop
If F Then
With .Document.getElementsByName("quotes_content_left_pnlAJAX")
If .Length = 1 Then
With .Item(0).Children
D = .Length = 2
If D Then
With .Item(0).Document
H$ = .Title: Application.StatusBar = TXT & "
"
With .all("ddlTimeFrame"): .Value = "10y": .onchange: End With
End With
While .Length: DoEvents: Wend
End If
End With
If D Then T$ = .Item(0).Children(1).outerHTML
End If
End With
End If
.Quit
End With
If T = "" Then
If F Then Beep Else MsgBox "Le site rame !", vbExclamation, " NASDAQ"
Else
With CreateObject("HTMLFile")
.write T
With .all(4).Rows
ReDim VA(1 To .Length, 1 To .Item(0).Cells.Length)
For R& = 1 To .Length
Application.StatusBar = TXT & ": " & Format$(R, "@@@@")
With .Item(R - 1).Cells
For C& = 1 To .Length: VA(R, C) = .Item(C - 1).innerText: Next
End With
Next
End With
End With
Application.ScreenUpdating = False
With [B1]: .CurrentRegion.Clear: .IndentLevel = 1: .Value = H: End With
With [B2].Resize(UBound(VA), UBound(VA, 2))
With .Columns("B:E")
.HorizontalAlignment = xlRight: .IndentLevel = 1: .NumberFormat = "0.0000"
End With
.Cells(2, 1)(1, 0).Select: ActiveWindow.FreezePanes = True
With .Rows(1): .Font.Bold = True: .HorizontalAlignment = xlCenter: End With
.Columns(1).HorizontalAlignment = xlCenter: .Value = VA
If .Cells(2, 1).NumberFormat <> .Cells(3, 1).NumberFormat Or _
.Cells(2, 1).Text = "" Then .Rows(2).Delete
End With
End If
Application.StatusBar = False
End Sub |
• Ligne n°2 : la constante QUOTE contient le code de la cotation, c'était la base d'un test bouclant des cotations …
• Lignes n°7 à 12 : utilisation de Timer au cas où le site rame …
Variables D pour début et F pour fin (je me suis déchiré sur ce coup là !),
les 9 secondes de pseudo timeout peuvent être augmentées pour un ordinateur lent
(principaux tests sur processeurs i3 - 2.4GHz et i5 - 2.5Ghz) …
Variables servant ensuite de Drapeau (Flag) conditionnant le processus.
• Ligne n°15 : pointage de l'élément parent de la table.
En fait, pas tout à fait ! .getElementsByName renvoyant une collection même pour un seul élément …
.all et .getElementByID pointent directement sur l'élément mais déclenchent une erreur s'il n'existe pas
dans la page, .getElementsByName renvoie alors une collection vide dont la propriété length vaut zéro,
pas d'erreur possible !
• Ligne n°16 : s'il existe un seul élément dans la collection … (déjà vu sur le site NASDAQ des pages sans)
• Ligne n°17 : verrouillage de l'élément parent sur une de ses collections.
• Ligne n°18 & 19 : si la collection contient bien deux éléments … (déjà vu sur le site NASDAQ des pages sans)
• Ligne n° 20 : retour temporaire au sommet de la page (Document).
Impossible de me résoudre à déclarer une variable objet pour l'utiliser seulement une fois …
Comme des raccourcis d'objets parents sont présents au sein de leur filiation, autant en profiter !
• Ligne n°21 : stockage du titre de la page et information dans la barre d'état de l' « Import en cours … »
Avant ce point, la barre d'état affiche « Connexion … », utile pour différencier où cela bloque …
• Ligne n°22 : demande de la mise à jour de l'historique.
• Ligne n°23 : fin du pointage temporaire vers le Document, retour au pointage précédent (en ligne 17) …
• Ligne n°25 : l'immuable boucle d'attente de la mise à jour !
Rappel : sortie de boucle lorsque la valeur vaut zéro,
évènement lié au pointeur devenu obsolète - vide - après la mise à jour …
• Ligne n°29 : stockage du code HTML de la table à jour …
… via un nouveau pointage de l'élément parent sur son deuxième élément.
Rappel : le premier élément d'une collection a pour index zéro, un pour le deuxième élément, …
Peu d'ajustements quant aux conversion et mise en page des données :
• Ligne n°42 : le code stocké contenant uniquement la table, autant pointer directement sur son élément.
• Ligne n°55 : affichage du titre de la page indiquant la cotation de la table pour mémoire …
• Ligne n°61 : (1, 0) est équivalent à .Offset(0, -1) …
Testé sur les versions d'Excel 2003 & 2007, sait-on jamais sur les versions ultérieures …
• Ligne n°65 : parfois la ligne indésirable est vide.
Edit :
Tests sous Windows 7 & 8, Internet Explorer 9, 10 et 11. Voir le post #110 …
En guise de conclusion …
Dans la contribution initiale comme dans cette démonstration, la méthode est restée la même !
Juste ont changé l'élément pointé et la collection, prouvant bien l'universalité de cette méthode …
Voilà pour le principe, se conformant à l'esprit de cette règle : Think, But Think Object !
(A voir sur des tee-shirts lors de conventions de développeurs !)
En gros c'est étudier la hiérarchie des objets, utiliser à bon escient leur structure,
optimisant et simplifiant ainsi le code, d'aucuns pourraient même le trouver beau !
… une évolution à l'horizon !
Ce code, fonctionnant à merveille pendant deux semaines, même après la modification du code
source des pages de cotations, samedi pendant toute une demi-journée affichait "Le site rame !"
mais aucun problème pourtant via des bibliothèques de requêtes !
Imaginer alors un site sur lequel ni une requête ni un objet
QueryTable n'est utilisable !
Que faire si seul reste le pilotage d'Internet Explorer ?
Comment ne pas rester bloqué pendant des heures ?!
_________________________________________________________________________________________________
L'échec est la voie du succès …
Partager