Faalamva

[SOLVED] [IE.au3] How to "refresh" elements coordinates after the first use of _IECreate ?

11 posts in this topic

#1 ·  Posted (edited)

Hi,

I'm using the IE.au3 library to parse elements in a webpage and get their (x,y) coordinates.

Main commands I'm using are :         

$oIE = _IECreate($myWebPage)

$oElements = _IETagNameGetCollection($oIE, "label")

$windowleft = $oIE.document.parentwindow.screenLeft
$windowtop = $oIE.document.parentwindow.screenTop

$oElementPosX = $windowleft + _IEfindPosX($oElement)
$oElementPosY = $windowtop + _IEfindPosY($oElement)

Now things become a bit tricky when i simulate a scroll in my webpage :

$oIE.document.parentwindow.scroll(0, $myScrollY)

Because once this is done, the coordinates of the elements are still what they were before the scroll.

I can manage this problem by keeping track of the number of pixels I have scrolled, and compute the new "real" ($oElementPosX, $oElementPosY).

But I'm pretty sure there's a more efficient / more elegant way to do it.

What's more in some situations, when I click some controls in the webpage, the webpage adds new elements and shifts the controls below by a random number of pixel, so my workaround can't be used...

So here's my question : Is there a way to "refresh" the calculation of label coordinates ($oElementPosX, $oElementPosY) after a scroll ?

Thank you !

EDIT : I forgot to post the _IEfindPosX and _IEfindPosY functions (found somewhere on this forum) :

Func _IEfindPosX($o_object)
    Local $curleft = 0
    Local $parent = $o_object
    If IsObj($parent) Then
        While IsObj($parent)
            $curleft += $parent.offsetLeft
            $parent = $parent.offsetParent
        WEnd
    Else
        Local $objx = $o_object.x
        If IsObj($objx) Then $curleft += $objx
    EndIf
    Return $curleft
EndFunc

Func _IEfindPosY($o_object)
    Local $curtop = 0
    Local $parent = $o_object
    If IsObj($parent) Then
        While IsObj($parent)
            $curtop += $parent.offsetTop
            $parent = $parent.offsetParent
        WEnd
    Else
        Local $objy = $o_object.y
        If IsObj($objy) Then $curtop += $objy
    EndIf
    Return $curtop
EndFunc

 

Edited by Faalamva

Share this post


Link to post
Share on other sites



26 minutes ago, l3ill said:

Cant you just rerun the function you used to find them the first time ?

Thank you for your answer, unfortunately, I've already tried and it doesn't work.

Here is a full example to illustrate my problem. Just copy/paste and run it and you'll understand what I'm trying to achieve.

 

#include <IE.au3>

; ----------------------------------------------------------------------
; Main
; ----------------------------------------------------------------------

$oIE = _IECreate("http://www.york.ac.uk/teaching/cws/wws/webpage1.html")
WinSetState("","",@SW_MAXIMIZE)

$windowleft = $oIE.document.parentwindow.screenLeft
$windowtop = $oIE.document.parentwindow.screenTop
$oElements = _IETagNameAllGetCollection($oIE)

For $oElement In $oElements
    If $oElement.innerText = "EXERCISE" Then
        $oElementPosX = $windowleft + _IEfindPosX($oElement)
        $oElementPosY = $windowtop + _IEfindPosY($oElement)
        MsgBox(0, "", "Mouse will be moved to ""EXERCISE"" position")
        MouseMove($oElementPosX, $oElementPosY)
    EndIf
Next

MsgBox(0, "", "Let's scroll the webpage 200 pixels down")
$oIE.document.parentwindow.scroll(0, 200)

; Trying to "refresh the elements positions" --> it doesn't work
$oElements = _IETagNameAllGetCollection($oIE)

For $oElement In $oElements
    If $oElement.innerText = "EXERCISE" Then
        $oElementPosX = $windowleft + _IEfindPosX($oElement)
        $oElementPosY = $windowtop + _IEfindPosY($oElement)
        MsgBox(0, "", "Mouse will be moved again to ""EXERCISE"" position")
        MouseMove($oElementPosX, $oElementPosY)
    EndIf
Next

MsgBox(0, "", "Positions of webpage elements haven't been refreshed, the mouse was moved to the former EXERCISE position...")

; ----------------------------------------------------------------------
; Functions
; ----------------------------------------------------------------------

Func _IEfindPosX($o_object)
    Local $curleft = 0
    Local $parent = $o_object
    If IsObj($parent) Then
        While IsObj($parent)
            $curleft += $parent.offsetLeft
            $parent = $parent.offsetParent
        WEnd
    Else
        Local $objx = $o_object.x
        If IsObj($objx) Then $curleft += $objx
    EndIf
    Return $curleft
EndFunc

Func _IEfindPosY($o_object)
    Local $curtop = 0
    Local $parent = $o_object
    If IsObj($parent) Then
        While IsObj($parent)
            $curtop += $parent.offsetTop
            $parent = $parent.offsetParent
        WEnd
    Else
        Local $objy = $o_object.y
        If IsObj($objy) Then $curtop += $objy
    EndIf
    Return $curtop
EndFunc

 

Share this post


Link to post
Share on other sites

Sorry, no answers just some info; I added some error checking and it would seem that your If statement is not working correctly.

Spoiler
$oIE = _IECreate("http://www.york.ac.uk/teaching/cws/wws/webpage1.html")
WinSetState("", "", @SW_MAXIMIZE)

Local $windowleft = $oIE.document.parentwindow.screenLeft
Local $windowtop = $oIE.document.parentwindow.screenTop
Local $oElements = _IETagNameAllGetCollection($oIE)

For $oElement In $oElements
    If $oElement.innerText = "EXERCISE" Then
        MsgBox(0, "Success", "EXERCISE found in 'InnerText'")
        Local $oElementPosX = $windowleft + _IEfindPosX($oElement)
        Local $oElementPosY = $windowtop + _IEfindPosY($oElement)
        ConsoleWrite("$oElementPosX = " & $oElementPosX & @CRLF)
        ConsoleWrite("$oElementPosY = " & $oElementPosY & @CRLF)
        MsgBox(0, "", "Mouse will be moved to ""EXERCISE"" position")
        MouseMove($oElementPosX, $oElementPosY)
    Else
        MsgBox(0, "error", "Something went wrong here...")
    EndIf
Next

MsgBox(0, "", "Let's scroll the webpage 200 pixels down")
$oIE.document.parentwindow.scroll(0, 200)

; Trying to "refresh the elements positions" --> it doesn't work
$oElements = _IETagNameAllGetCollection($oIE)

For $oElement In $oElements
    If $oElement.innerText = "EXERCISE" Then
        MsgBox(0, "Success", "EXERCISE found in 'InnerText'")
        Local $oElementPosX = $windowleft + _IEfindPosX($oElement)
        Local $oElementPosY = $windowtop + _IEfindPosY($oElement)
        ConsoleWrite("$oElementPosX = " & $oElementPosX & @CRLF)
        ConsoleWrite("$oElementPosY = " & $oElementPosY & @CRLF)
        MsgBox(0, "", "Mouse will be moved again to ""EXERCISE"" position")
        MouseMove($oElementPosX, $oElementPosY)
    Else
        MsgBox(0, "error", "Something went wrong here...")
    EndIf
Next
MsgBox(0, "", "Positions of webpage elements haven't been refreshed, the mouse was moved to the former EXERCISE position...")

You should take a closer look at how your Functions are being called. It also good practice to use Local or Global when defining variables.

 

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Your example won't work, it will display

"Something went wrong here..."

everytime the element checked isn't "EXERCISE".

Please remember that this is just an example I wrote in a few minutes to illustrate the case, it may not be state-of-the-art of course.

But it's working as a standalone program, just copy/paste and run it to see by yourself.

Let's stick to the topic please :)

Edited by Faalamva

Share this post


Link to post
Share on other sites

Understood..

A simple test reveals that your website does not have the .innerText element you are trying to use:

From the Help File:

#include <IE.au3>
#include <MsgBoxConstants.au3>

;~ Local $oIE = _IE_Example("basic")
$oIE = _IECreate("http://www.york.ac.uk/teaching/cws/wws/webpage1.html")

Local $oElements = _IETagNameAllGetCollection($oIE)
For $oElement In $oElements
    If $oElement.id Then MsgBox($MB_SYSTEMMODAL, "Element Info", "Tagname: " & $oElement.tagname & @CRLF & "id: " & $oElement.id & @CRLF & "innerText: " & $oElement.innerText)
Next

_IEQuit($oIE)

Without the error checking your script is finding mouse coordinates one time but the rest of the code is skipping through (aka: not working)

If you have access to the code from your page I would suggest giving the 'EXERCISE' header (or whatever) its own .id and then write your code to pick up on that element.


<h4 id="myHeader">Exercise</h4>

My $0.02 ...

Good luck o:)

 

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

#include <IE.au3>
#include <MsgBoxConstants.au3>

;~ Local $oIE = _IE_Example("basic")
$oIE = _IECreate("http://www.york.ac.uk/teaching/cws/wws/webpage1.html")

Local $oElements = _IETagNameAllGetCollection($oIE)
For $oElement In $oElements
    ConsoleWrite("Tagname: " & $oElement.tagname & @CRLF & " id: " & $oElement.id & @CRLF & " innerText: " & $oElement.innerText & @CRLF)
Next

_IEQuit($oIE)

Result in console :

Quote

...

Tagname: H4
 id:
 innerText: EXERCISE

...

We're still drifting away from topic... :(

Edited by Faalamva

Share this post


Link to post
Share on other sites

No, your right. Never mind all that.

It is more difficult than I had hoped. Your coordinate variables are staying in memory for some reason and zeroing them out didn't work.

Sorry couldn't help.

...all the smart people have gone to bed...:P

might have to wait until tomorrow :'(

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

... try this:

#include <IE.au3>
; ----------------------------------------------------------------------
; Main
; ----------------------------------------------------------------------
$oIE = _IECreate("http://www.york.ac.uk/teaching/cws/wws/webpage1.html")
WinSetState("", "", @SW_MAXIMIZE)

$oElement = _IETagNameGetCollection($oIE, 'H4', 0)
MouseMove($oElement.getBoundingClientRect().left + $oIE.document.parentwindow.screenleft, $oElement.getBoundingClientRect().top + $oIE.document.parentwindow.screentop)

MsgBox(0, "", "Let's scroll the webpage 200 pixels down", 2)
$oIE.document.parentwindow.scroll(0, 200)
MouseMove($oElement.getBoundingClientRect().left + $oIE.document.parentwindow.screenleft, $oElement.getBoundingClientRect().top + $oIE.document.parentwindow.screentop)

MsgBox(0, "", "caught!", 2)
$oElement.style.setAttribute('border', '5px solid red') ; draw a red border (just for fun)

 

Edited by Chimp
1 person likes this

small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

Very interesting Chimp, it seems we're heading in the right direction :lol: !

EDIT : I managed to adapt your code to get exactly what I need (i.e. using displayed labels instead of "H4") :

#include <IE.au3>

$oIE = _IECreate("http://www.york.ac.uk/teaching/cws/wws/webpage1.html")
WinSetState("", "", @SW_MAXIMIZE)

Local $myElement
$oElements = _IETagNameAllGetCollection($oIE)
For $oElement In $oElements
    If $oElement.innerText = "EXERCISE" Then $myElement = $oElement
Next

MsgBox(0, "", "Let's locate EXERCISE")
MouseMove($myElement.getBoundingClientRect().left + $oIE.document.parentwindow.screenleft, $myElement.getBoundingClientRect().top + $oIE.document.parentwindow.screentop)
MsgBox(0, "", "Let's scroll the webpage 200 pixels down")
$oIE.document.parentwindow.scroll(0, 200)
MsgBox(0, "", "Let's locate EXERCISE again")
MouseMove($myElement.getBoundingClientRect().left + $oIE.document.parentwindow.screenleft, $myElement.getBoundingClientRect().top + $oIE.document.parentwindow.screentop)

EDIT 2 : Tested "for real" in dynamic webpages. Works perfectly, and much simpler/shorter than the original code.

Case solved, thank you ! :)

Edited by Faalamva

Share this post


Link to post
Share on other sites
2 hours ago, Faalamva said:

......

Case solved, thank you ! :)

You are welcome... ;)


small minds discuss people average minds discuss events great minds discuss ideas.... and use AutoIt....

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now

  • Similar Content

    • taylansan
      By taylansan
      Hi All, 
      I'm using an online translator for Spanish in which you give the verb and website gives the conjugations. The website I'm using is: http://www.spanishdict.com/conjugate/tener where "tener" means "to have" in English. 
      In the screenshot, you can see the present tense (5 yellow highlighted items) and the imperfects (5 blue boxes). I don't need to get the translation for "vosotros", so I didn't make any color on that row. I'm trying to get these 10 translations to be written on the output for my code. But my code is so simple (because I couldn't go into the div / tr / td): 
      #include <IE.au3> #include <Array.au3> Local $sSpanishWord = "tener" ;to have ;Local $sSpanishWord = "abrir" ;to open Local $oIE = _IECreate ("http://www.spanishdict.com/conjugate/" & $sSpanishWord) ;http://www.spanishdict.com/conjugate/tener ;http://www.spanishdict.com/conjugate/abrir ;== Try using _IETagNameAllGetCollection Local $oElements = _IETagNameAllGetCollection($oIE) For $oElement In $oElements If $oElement.id Then ConsoleWrite("Tagname: " & $oElement.tagname & @CRLF & "id: " & $oElement.id & @CRLF & "innerText: " & $oElement.innerText & @CRLF & @CRLF) EndIf Next ;== Try using _IETagNameGetCollection Local $sTable Local $oTableCells Local $oTableRows = _IETagNameGetCollection($oIE, "tr") For $oTableRow In $oTableRows $sTable = "" $oTableCells = _IETagNameGetCollection($oTableRow, "td") ;I don't know how to continue from here on Next I used the IE to find out the tr / td stuff, but I think I'm lost. 
      P.S: The verb "tener" can be difficult, because it has red letters because of irregular. The verb "abrir" can be much easier, because it's a regular verb. 


    • kevin42036
      By kevin42036
      Hi All,

      I am very new to AutoIt and scripting in general and have a question about IEFormGetObjByName. The help function says:
      _IEFormGetObjByName ( ByRef $oObject, $sName [, $iIndex = 0] )
      But how do I find what to enter for $sName? In the example below, it says that it can be found by viewing the HTML source. So I went to the google home page, clicked Ctrl U to view the source, and cant figure out how they determined that the $sName is 'gbqf'. Can someone explain this process to me? Thanks in advance!
      ; Get a reference to a specific form by name.  In this case, submit a query
      ; to the Google search engine.  Note that the names of the form and form
      ; elements can be found by viewing the page HTML source
      #include <IE.au3>
      Local $oIE = _IECreate("http://www.google.com")
      Local $oForm = _IEFormGetObjByName($oIE, "gbqf")
      Local $oQuery = _IEFormElementGetObjByName($oForm, "q")
      _IEFormElementSetValue($oQuery, "AutoIt IE.au3")
      _IEFormSubmit($oForm)
       
    • jonson1986
      By jonson1986
      Hello I'm trying to translate few text using below code, I found it working previously couple of months ago but Now these days it's not working at all and I'm getting below errors when I run the script and Array display at the end of text also not able to show any translated text instead of value 0 & 1;
      --> IE.au3 T3.0-2 Warning from function _IEGetObjById, $_IESTATUS_NoMatch (gt-res-data)
      --> IE.au3 T3.0-2 Error from function _IEPropertyGet, $_IESTATUS_InvalidDataType
      Here is code,
      #include <IE.au3> #include <Array.au3> Local $tag="* # * # *" Local $oIE=_IECreate("https://translate.google.com/#auto/es") Local $oForm=_IEFormGetCollection($oIE,0) Local $oQuery=_IEGetObjByName($oForm,"text") _IEFormElementSetValue($oQuery, $tag & @CR & "Hello World" & @CR & "This is a test" & @CR & $tag) _IEFormSubmit($oForm) _IELoadWait($oIE) Local $oText=_IEGetObjById($oIE,"gt-res-data") $lines=StringSplit(_IEPropertyGet($oText,"innerText"),@CRLF,1) _IEQuit($oIE) _ArrayDelete($lines,_ArraySearch($lines,$tag,1,0,0,1,0) & "-" & $lines[0]) _ArrayDelete($lines,"1-" & _ArraySearch($lines,$tag,1,0,0,1,1)) $lines[0]=UBound($lines)-1 _ArrayDisplay($lines)  
    • smellyfingers
      By smellyfingers
      Hey, i hope someone can point me in the right direction, i have a page with tables, inside i have TD,TR,INPUT tags, the input tags is buttons and i need to click on one of theese buttons but they have the same value and type so the only way that i am going to know that it's the correct button is to find out the name of the innerhtml of the TD before (the parent node) because the input comes after, like this
      <TABLE> <TR> <TD> Name of the td </TD> <TR> <TD colSpan=3<INPUT> value=my button type=button</INPUT></TD> <TR> <TD> Other name of a td </TD> <TR> <TD colSpan=3<INPUT> value=my button type=button</INPUT></TD> <TR> I know how to find all td's and inputs but not (in a loop) look for the td's and once it has found it click on the corresponding or "closest" input, maybe a nested loop?
      I made a for loop using _IETagnameGetCollection($ie,"TD") and after it found the TD i tried looking for nextSibling but that might be impossible with INPUT perhaps?
    • Faalamva
      By Faalamva
      Hello,
      Let's take a simple example to illustrate my case.
      I open a webpage with the command _IECreate and I parse all its elements :
      #include <IE.au3> $oIE = _IECreate("http://www.york.ac.uk/teaching/cws/wws/webpage1.html") $oElements = _IETagNameAllGetCollection($oIE) For $oElement In $oElements ConsoleWrite("Tagname: " & $oElement.tagname & @CRLF & "Id: " & $oElement.id & @CRLF & "InnerText: " & $oElement.innerText & @CRLF & "--------------------------------" & @CRLF) Next Now let's imagine I simulate a click with MouseClick to the link "lesson two" at the bottom of this webpage. A new webpage will open :
      http://www.york.ac.uk/teaching/cws/wws/webpage2.html
      I'd like to get the elements (tagname, id, innertext) of this new webpage, just like I got them for the first webpage. But for this, I presume I would have to get a new $oIE2 Object variable of an InternetExplorer.Application, in order to be able to use the _IETagNameAllGetCollection once again.
      How am I supposed to do this ?
      Thank you !