.NET : utilisation de l’EVT webBrowser1_DocumentCompleted
Ayant eu à réaliser des outils d’automatisation du WEB, j’ai de nombreuses fois utilisé le composant .NET « webBrowser ». Cet objet est assez facile à utiliser et facilite grandement l’accès au web pour des outils Winform.
L’un de mes soucis majeurs avec ce composant restait néanmoins l’évènement «DocumentCompleted» que l’on utilise pour connaitre la fin de chargement de la page appelée via : « webBrowser.Navigate(url) »
En effet cet évènement m’a toujours semblé avoir un comportement peu fiable, puisque que dans la majorité des cas, pour une demande ‘Navigate’, on reçoit un nombre variable de ‘DocumentCompleted’ ce qui ne facilite pas la programmation de la suite du programme. En effet, si on utilise cet évènement pour effectuer une analyse automatique du contenu de la page demandée et que celle-ci est incomplètement chargée, ça se termine généralement assez mal. Une recherche Web sur le sujet, m’a juste convaincu que le sujet était connu, mais je n’ai jusqu’à présent pas trouvé de réponse convaincante. Mes pansements divers sur le sujet étaient jusqu’à présent peu reluisants et surtout à base de tempos diverses, ce qui est en fait, un cache misère! A l’occasion d’une nouvelle commande je me suis repenché sur le sujet, bien décidé à trancher dans le vif.
– Etude des différents évènements et attributs qui pourraient résoudre mon problème
– Trace sur chaque évènement et utilisation de debugView de Mark Russinovich
J’ai réétudié l’ EVT « Navigated » qui apparait très peu de temps après la demande «webBrowser.Navigate(url)». C’est avec cet évènement que l’on découvre qu’une seule demande Navigate peut générer plusieurs « Navigated ».
Les traces avec un exemple d’automatisation du site de ‘laposte.net’ donnent ceci :
1 – Pour une demande très simple (appeler la page d’accueil de laposte.net)
0.00[4380] Navigate url : ‘http://www.laposte.net
5.20[4380] Webbrowser completed : http://www.laposte.net
On voit là qu’il n’y a aucun problème, 1 Navigate, 1 DocCompleted
Les choses se corsent quand après avoir rempli les champs, et envoyé la commande submit on constate le résultat :
2 – Suite du SUBMIT :
5.37[4380] Activate : ‘FORM’ , ‘name=userlogin’ , ‘submit’
7.84[4380] Webbrowser completed : http://webmail.laposte.net/webmail/fr_FR/advertis_bottom_iframe.html
8.04[4380] Webbrowser completed : http://www.kelkoo.fr/content/fr/partners/laposte/laposte_s_homme.htm
8.47[4380] Webbrowser completed : http://view.atdmt.com/AMF/iview/115038936/direct;wi.468;hi.60/01?click=
8.47[4380] Webbrowser completed : http://webmail.laposte.net/webmail/fr_FR/advertisement_top_iframe.html
8.48[4380] Webbrowser completed : http://webmail.laposte.net/webmail/fr_FR/inbox.html?KEY=A+183+18000+183A
Maintenant on voit que pour 1 action “click”, on récupère 5 évènements “webBrowser.DocumentCompleted”. Donc dans ce cas, si on déclenche l’analyse de la page dès le premier DocumentCompleted, on a bien des chances de rater son coup !
3- Utilisons l’évènement « Navigated » :
Le cas précédent nous montrera maintenant les traces suivantes :
5.37[4380] Activate : ‘FORM’ , ‘name=userlogin’ , ‘submit’
6.79[4380] Webbrowser Navigated : http://webmail.laposte.net/webmail/fr_FR/inbox.html?KEY=A+183+18000+183A
7.09[4380] Webbrowser Navigated : http://webmail.laposte.net/webmail/fr_FR/advertisement_top_iframe.html
7.23[4380] Webbrowser Navigated : http://webmail.laposte.net/webmail/fr_FR/advertisement_bottom_iframe.html
7.36[4380] Webbrowser Navigated : http://www.kelkoo.fr/content/fr/partners/laposte/laposte_s_homme.htm
7.68[4380] Webbrowser Navigated : http://view.atdmt.com/AMF/iview/115038936/direct;wi.468;hi.60/01?click=
7.84[4380] Webbrowser completed : http://webmail.laposte.net/webmail/fr_FR/advertisement_bottom_iframe.html
8.04[4380] Webbrowser completed : http://www.kelkoo.fr/content/fr/partners/laposte/laposte_s_homme.htm
8.47[4380] Webbrowser completed : http://view.atdmt.com/AMF/iview/115038936/direct;wi.468;hi.60/01?click=
8.47[4380] Webbrowser completed : http://webmail.laposte.net/webmail/fr_FR/advertisement_top_iframe.html
8.48[4380] Webbrowser completed : http://webmail.laposte.net/webmail/fr_FR/inbox.htmlKEY=A+183+18000+183A
Cette fois, on a toujours nos 5 évènements “DocCompleted” pour une action ‘click’, mais on voit que l’on a eu également 5 « navigated». Ce qui vient donc à l’esprit immédiatement, utilisons un compteur, mis à 0 lors du click, incrémenté par chaque«Navigated» et décrémenté par chaque « DocCompleted». Quand il passe à Zéro, j’obtiens mon vrai évènement «Fin de navigation» qui me permettra de faire tranquillement l’autopsie de ma page en étant sûr que c’est le bon cadavre !
Donc l’histoire se termine ici, tout est bien qui finit bien …
Eh bien non, car ce scénario idyllique ne marche qu’à 80% du temps, voyez donc ce qui se passe quand je tente d’interroger par programme cette autre URL :
00.00[] Navigate url : ‘http://oami..eu//Request/en_SearchBasic’
03.84[] Webbrowser Navigated : http://oami..eu//Request/en_SearchBasic, Count = 1
12.22[] Webbrowser completed : http://oami..eu//Request/en_SearchBasic, Count = 0
12.32[] Activate : ‘INPUT’ , ‘name=search’ , ‘click’
14.24[] Webbrowser Navigated : http://oami..eu//Request/en_Result_NoReg, Count = 1
14.70[] Webbrowser Navigated : http://oami..eu//Request/en_UnsuccessfulSearch_NoReg, Count = 2
19.01[] Webbrowser completed : http://oami..eu//Request/en_UnsuccessfulSearch_NoReg, Count = 1
Dans ce cas, dans la trace, j’ai ajouté la valeur du compteur qui me sert à compter les Navigated, pour décompter les DocCompleted, et là on voit qu’après l’action ‘click’ il ya eu 2 ‘Navigated’ et 1 seul ‘DocCompleted’, mon scénario de rêve tourne au cauchemar.
Explorons d’autres outils :
Le WebBrowser possède un attribut booléen «IsBusy » que j’avais déjà tenté d’utiliser, mais qui devenait false bien avant le « docCompleted».
Il existe également un attribut «ReadyState», la conjonction de ces éléments donne ceci dans les traces :
00.00[6892] Navigate url : ‘http://oami..eu//Request/en_SearchBasic’
03.84[6892] Webbrowser Navigated : http://oami..eu//Request/en_SearchBasic, Busy: True, ReadyState: Loading
12.22[6892] Webbrowser completed : http://oami..eu//Request/en_SearchBasic, Busy: False, ReadyState: Complete
12.32[6892] Activate : ‘INPUT’ , ‘name=search’ , ‘click’
14.24[6892] Webbrowser Navigated : http://oami..eu//Request/en_Result_NoReg, Busy: True, ReadyState: Complete
14.70[6892] Webbrowser Navigated : http://oami..eu//Request/en_UnsuccessfulSearch_NoReg, Busy: True, ReadyState: Loading
19.01[6892] Webbrowser completed : http://oami..eu//Request/en_UnsuccessfulSearch_NoReg, Busy: False, ReadyState: Complete
Dans cet exemple, les traces nous montrent à chaque passage dans ‘Navigated’, puis ‘DocCompleted’ l’état de ‘IsBusy’ et de ‘ReadyState’. A priori, quand on a la conjonction suivante :
- IsBusy == false
- ReadyState == Complete
La page demandée est complète et prête à être autopsiée. Ce qui pourrait donner les lignes suivantes dans webBrowser_DocumentCompleted :