Changes to Internet Explorer DOM

Started by George Vagenas, May 08, 2014, 03:44:25 AM

Previous topic - Next topic

George Vagenas

I've moved from XPx32 to Win7x64 and I'm trying to understand why some code that used to work with IE 8 does not work with IE 11.  At first I thought the problem was changes to the site I'm trying to access and while there were some changes I couldn't see how they would account for the code no longer working.
Finally (after two days of head scratching) I was able to get the script working again.  One of the problems came down to how the innerHTML property was being returned which I was able to work around with a very minor change to the script but the only solution to the other problem was to resort to using SendKeysTo.

I had archived the original pages that I based the code on and I'm stumped as to what caused the original script to stop working.  Here's the original HTML of the login page:
Code (html5) Select
<div class="formActions">
<ul>
<li><input type="submit" title="Login to Online Banking" name="Continue" id="Continue" tabindex='1004' value="Login" class="submit"/></li>

</ul>
</div>

and here's the current page:
Code (html5) Select
<div class="formActions">
<ul>
<li><input type="submit" title="Login to Online Banking" name="Continue" id="Continue" value="Login" class="submit"/></li>





</ul>
</div>
Apart from whitespace they are identical but this code no longer works:
Code (winbatch) Select
   prqDoc = prqIE.Document                                            ; Safety refresh.
   prqAll = prqDoc.all

   prqAction = inireadpvt('Internet', prqActionRqst, '', gIniPvt)     ; Get the current action.
   prqType = prqAll.%prqAction%
   prqType.Click

After substitution the line reads:
Code (winbatch) Select
prqType = prqAll.Continue and prqIE is defined earlier in the script as
Code (winbatch) Select
prqIE = objectopen("InternetExplorer.Application") Only now with IE11 it doesn't work and just in case I have designated the site as TRUSTED with LOW security and UAC is turned off.  The only work around I could come up with was resorting to SendKeysTo.  I'd really to get the click action working again but I don't have a clue as to what I need to change.

Thanks

George

JTaylor

For the "click" you will need to do something like (I have not altered this for your object names or situation) the following.  It will handle older and newer versions of IE.

Code (winbatch) Select
 
    objEvent = yobrowser.document.createEvent("HTMLEvents")
    i = yobrowser.document.GetElementById("olp_page_next")
    If objEvent == "" Then
      i.click
    Else
      objEvent.initEvent("click", @true, @true)
      i.dispatchEvent(objEvent)
    EndIf


Deana

Welcome to the wonderful world of IE. Microsoft has made some significant changes to IE between version 8 and 11. Also now with Windows 7, UAC is also a new factor.

For example:
Since Internet Explorer 4, document.all has been supported in Internet Explorer. Prior to the implementation of document.getElementById(), document.all was the best way of getting an element reference. document.all has remained in Internet Explorer through version IE10. As of IE11, document.all is no longer...Therefore you will need to modify your code accordingly and call document.getElementById instead.

Please read Microsoft's articles
Compatibility changes in IE11 : http://msdn.microsoft.com/en-us/library/ie/bg182625(v=vs.85).aspx
Internet Explorer 11 guide for developers : http://msdn.microsoft.com/library/ie/bg182636(v=vs.85).aspx

I have also found that the Click and Focus methods seem to no longer work starting with IE9. Often adding the webpage to Compatibility View resolves the Focus and Click issue. However, here is some code that can often be used in place of the Click method:

Code (winbatch) Select

; WORKAROUND - createEvent initEvent DispatchEvent
objEvent = objBrowser.document.createEvent("HTMLEvents")
objEvent.initEvent("click", @TRUE, @TRUE)
objElement.dispatchEvent(objEvent) ; objElement is the handle to the object to click (i.e. button)


Check out my Webpage Element Explorer script which can be used for Discovering form elements on a webpage: http://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/tsleft.web+WinBatch/OLE~COM~ADO~CDO~ADSI~LDAP/OLE~with~MSIE+!!~Webpage~Element~Explorer~!!.txt



Deana F.
Technical Support
Wilson WindowWare Inc.

George Vagenas

Sorry for not responding immediately but other lives do look in from time to time.  Thank you both for the input and I've used JTaylor's code to fix the script (it would appear that IE11 is not consistent in whether it will honor the request to create an event).
I followed Deana's links and learned that "Document modes are deprecated", the current version of IE11 still supports "document.all", but if future versions no longer support it then my script will be seriously broken.
Currently I'm using "document.all" like this
Code (winbatch) Select
   prqObj = prqAll.item(prqObjNum)
   prqTag = prqObj.tagname
   prqInner =  prqObj.InnerHtml
   if strindexnc(prqInner, '<INPUT', 0, @fwdscan)==1 && strindexnc(prqInner, 'class="checkbox eventEnabledFields2"', 0, @fwdscan)!=0 && strupper(prqTag)=='LABEL'
      return prqObj
   else
      prqCnts = prqAll.length-1
      for prqCnt = 0 to prqCnts
         prqObj = prqAll.item(prqCnt)
         prqTag = prqObj.tagname
         prqInner =  prqObj.InnerHtml
         if strindexnc(prqInner, '<INPUT', 0, @fwdscan)==1 && strindexnc(prqInner, 'class="checkbox eventEnabledFields2"', 0, @fwdscan)!=0 && strupper(prqTag)=='LABEL'
            iniwritepvt(Section, KeyName, prqCnt, gIniPvt)
            prqChk = @true
            ; prqObj = prqAll.item(prqCnt)
            ; prqTable =  prqObj.InnerHtml
            display(3, 'Page Change', 'Ini file has been updated with new table object number.')
            return prqObj
         endif
      next
   endif

Later in the script the same code is called again to verify the value in prqInner and if it checks out then it is  is written to a file for further processing.  This code is part of Winbatch app that I've patched and prodded over the last sixteen years to retrieve bank statements and feed them to a bookkeeping program.
As usual and help is greatly appreciated.
Thanks

George

Deana

Instead of using document.all use one of the following to access the individual page elements:

document.getElementById() Returns the element that has the ID attribute with the specified value
document.getElementsByName() Accesses all elements with a specified name
document.getElementsByTagName() Returns a NodeList containing all elements with the specified tagname
Reference: http://www.w3schools.com/jsref/dom_obj_document.asp

Check out my Webpage Element Explorer script which can be used for Discovering form elements on a webpage: http://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/tsleft.web+WinBatch/OLE~COM~ADO~CDO~ADSI~LDAP/OLE~with~MSIE+!!~Webpage~Element~Explorer~!!.txt

NOTE: This script can also be used as an example of how to access all off the elements on a webpage.
Deana F.
Technical Support
Wilson WindowWare Inc.

Deana

If you need assistance getting an object handle to the webpage element...Post the HTML source of the element that you are trying to query with your code.
Deana F.
Technical Support
Wilson WindowWare Inc.

George Vagenas

It turns out that the innerHtml IE is returning is not the same as IE8's which means I have to revise the script to handle this.  The page has a search button which refreshes the page with the requested transactions, after the refresh the page has a DIV structure containing the transactions.
Code (html5) Select
<div class="summarygroup">
.
</div>

Now, if there was a getElementByClass function I could actually simplify the code.
Thanks

George

Deana

Quote from: George Vagenas on May 14, 2014, 01:08:10 PM
It turns out that the innerHtml IE is returning is not the same as IE8's which means I have to revise the script to handle this.  The page has a search button which refreshes the page with the requested transactions, after the refresh the page has a DIV structure containing the transactions.
Code (html5) Select
<div class="summarygroup">
.
</div>

Now, if there was a getElementByClass function I could actually simplify the code.

See the getElementByClassName Method:

http://msdn.microsoft.com/en-us/library/ie/ff975198(v=vs.85).aspx

Code (winbatch) Select

#DefineFunction udfIEPageLoadWait( objIE )
    ; Wait for webpage to load
    While !(objIE.readyState == 'complete' || objIE.readyState == 4 )
       TimeDelay(0.1)
    EndWhile
    While !(objIE.document.readyState == 'complete' || objIE.document.readyState == 4 )
       TimeDelay(0.1)
    EndWhile
    Return 1
#EndFunction


url = ????
classname = ????

; Initialize MSIE object
oIE   = ObjectCreate("InternetExplorer.Application")
oIE.Visible = @TRUE ; Change to @FALSE to hide the process from the user
oIE.Navigate(url)

; Wait for webpage to load
udfIEPageLoadWait( oIE )

; Get document object
oDoc = oIE.Document

cElements = oDoc.getElementsByClassName(classname)

ForEach oElement In cElements
      ErrorMode(@off)
      prqType  = oElement.type
      ErrorMode(@cancel)
      prqTag = oElement.tagname ;The value of tagName is the same as that of nodeName.
      prqInner =  oElement.InnerHtml
      if prqtype=='INPUT' && strindexnc(prqInner, 'class="checkbox eventEnabledFields2"', 0, @fwdscan)!=0 && strupper(prqTag)=='LABEL'
         Pause('',prqInner)
         ;return oElement
      endif
Next



:CleanUp

; Quit
oIE.Quit

; Close open COM/OLE handles
oElement = 0
oDoc = 0
oIE = 0
Exit
Deana F.
Technical Support
Wilson WindowWare Inc.

George Vagenas

Deana thanks but I'm not sure what object I should be using with this method.
Code (winbatch) Select
prqType = prqDoc.getElementByClassName("summarygroup")
returns "VT NULL". 
I've successfully invoked the getElementById method in other parts of the script with:
Code (winbatch) Select
prqType = prqDoc.getElementById("acctnum")
Because there was a page change I used this code
Code (winbatch) Select
prqDoc = prqIE.Document prior to invoking the method.  As usual with IE and OOP I'm stumped and feeling like a n00b.
Thanks

George

Deana

Quote from: George Vagenas on May 14, 2014, 02:15:36 PM
Deana thanks but I'm not sure what object I should be using with this method.
Code (winbatch) Select
prqType = prqDoc.getElementByClassName("summarygroup")
returns "VT NULL". 

Can you confirm the source HTML that contains the class attribute 'summarygroup'?
Deana F.
Technical Support
Wilson WindowWare Inc.

George Vagenas

If by confirm you mean can I see the updated page in IE, yes (I've set IE.visible to @true while I'm debugging).  Also the DIV structure I posted was from the source Html which I downloaded from the website after the transaction request.
Thanks

George

Deana

Quote from: George Vagenas on May 14, 2014, 03:16:09 PM
If by confirm you mean can I see the updated page in IE, yes (I've set IE.visible to @true while I'm debugging).  Also the DIV structure I posted was from the source Html which I downloaded from the website after the transaction request.

Actually I was asking you to share the HTML source code of the page, if you need further assistance.
Deana F.
Technical Support
Wilson WindowWare Inc.

George Vagenas

Here's the source, I've removed any personal info and left two modified transactions in the DIV structure.  If you search for "summarygroup" that will take you to the content that is added to the page after the script clicks the Search input.
Thanks

George

Deana

The code I posted previously Can get the innerHTML of that DIV! Here is it is again with a slight modification:

Code (winbatch) Select
#DefineFunction udfIEPageLoadWait( objIE )
    ; Wait for webpage to load
    While !(objIE.readyState == 'complete' || objIE.readyState == 4 )
       TimeDelay(0.1)
    EndWhile
    While !(objIE.document.readyState == 'complete' || objIE.document.readyState == 4 )
       TimeDelay(0.1)
    EndWhile
    Return 1
#EndFunction


url = 'C:\TEMP\Results.htm'
classname = 'summarygroup'

; Initialize MSIE object
oIE   = ObjectCreate("InternetExplorer.Application")
oIE.Visible = @TRUE ; Change to @FALSE to hide the process from the user
oIE.Navigate(url)

; Wait for webpage to load
udfIEPageLoadWait( oIE )

; Get document object
oDoc = oIE.Document

cElements = oDoc.getElementsByClassName(classname)

ForEach oElement In cElements
      ErrorMode(@off)
      prqType  = oElement.type
      ErrorMode(@cancel)
      prqTag = oElement.tagname ;The value of tagName is the same as that of nodeName.
      prqInner =  oElement.InnerHtml
      Pause('InnerHtml',prqInner)
      ;if prqtype=='INPUT' && strindexnc(prqInner, 'class="checkbox eventEnabledFields2"', 0, @fwdscan)!=0 && strupper(prqTag)=='LABEL'
      ;   Pause('',prqInner)
         ;return oElement
      ;endif
Next


:CleanUp

; Quit
oIE.Quit

; Close open COM/OLE handles
oElement = 0
oDoc = 0
oIE = 0
Exit
Deana F.
Technical Support
Wilson WindowWare Inc.

George Vagenas

Code (winbatch) Select
   ; Get document object
   prqDoc = prqIE.Document
   cElements = prqDoc.getElementsByClassName(classname)

returns VT Null. 
I think its major revision time, I've got an idea for a different approach and I can take this opportunity to lose the called batch files and convert them to UDFs.
As you said Deana "Welcome to the wonderful world of IE".  The click method would not work on the login page but worked in two other parts of the script, one to select a radio button and another to submit the transaction query.  Maybe there's a "Hmm" in there somewhere for the Html gurus because in these instances the "createEvent("HTMLEvents")" did not succeed but on the login page it did.
At any rate if my idea pans out hopefully I'll have a more bullet proof script against IE's search for browser legitimacy.  And I know I've said it before but if this was the movie industry your team would be walking off with all the oscars.
Thanks

George

Deana

Previously you mentioned ' If you search for "summarygroup" that will take you to the content that is added to the page after the script clicks the Search input.' Have you confirmed that the click is successfully being sent. Based on the NULL result returned from getElementsByClassName, I suspect the click was not successfully sent.

To debug, try adding a Pause(0,0) or a breakpoint just before the getElementsByClassName. Do you visually see the data you are trying to query? Look at the webpage source at this point to see if the class appears. IF not, then address the Search input click problem. Might just need a TimeDelay after the click to give the page time to load the new data.
Deana F.
Technical Support
Wilson WindowWare Inc.

George Vagenas

As you could see from the page I emailed you the transactions are definitely showing up in IE which means the click was received and processed. Also, I ran your udfIEWait4Page before trying to access the class.
Thanks

George

George Vagenas

This stuck in my head from another topic
QuoteProgress...it's 2014 and I'm installing 2003...because it works LOL
and seemed apropos.
Its 2014 and after using OLE to get to a page I'm using basic page scrapping, as per your post,
Code (winbatch) Select
objBrowserDoc = objBrowser.Document
objBrowserBody = objBrowserDoc.Body
Message("InnerText", objBrowserBody.InnerText )

and modifying it to suit my needs.
Code (winbatch) Select
   prqDoc = prqIE.Document
   prqBody = prqDoc.Body
   prqInner = prqBody.InnerText

   prqIE.GoBack()    ; Back to the request page.
   IEWait4Page(prqIE)

   ; Test prqInner for expected content.
   gErr = strindexnc(prqInner, 'Skip to Content', 0, @fwdscan)-1
   if gErr==0
      fileput(prqParam2, prqInner)
      return ; to CUrAcct.wbt - ;: Call OlePostReq
   endif


All I have to do is write a simple parsing routine to extract the transactions.
Thanks

George