How to receive events (eg. user mouse clicks) from IE

C

cal_2pac

I am trying to trap events from internet explorer eg. when user clicks
on an html link - I need to get notified for that event.

After looking through the newgroups / internet and reading through
various sections in programming python on win32 - I understand that
this can be done using DispatchWithEvents.
I have also referred to discussions on comp.lang.python
http://groups-beta.google.com/group...q=dispatchwithevents&rnum=43#0ee3083e71316da7

and

http://groups-beta.google.com/group...q=dispatchwithevents&rnum=19#5bcec1fda216c598

So far - none of the newgroups postings report that IE events were
trapped successfully (at least I could not find any). However, there is
enough evidence that it can be done.
My problems at the moment:
a) The examples use early binding. However, I cannot get Python makepy
to generate the code to force makepy process at run time - since COM
makepy utility that I invoke from python win 32 does not have any entry
for internet explorer.
I tried to find the CLSID for IE 3050F613-98B5-11CF-BB82-00AA00BDCE0B
but I get an exception
b) Also one of the examples suggest that following code should work
mod = EnsureModule(...)
class MyEvents(mod.IDocumentEvents):
# your methods here....
handler = MyEvents(ie.document)
# handler should start recieving events.

however, what CLSID is to be used in EnsureModule... . I tried with a
few but I always get the error 'NoneType' object has no attribute
'IDocumentEvents'


An example that 'works' will be very useful
 
R

Roger Upole

The two you'll need to run makepy for are Microsoft Internet Controls and
Microsoft HTML object Library. If you run them manually, you should be
able to look at the generated code to get the guids.
Here's a minimal example:

import win32com.client

ie_mod=win32com.client.gencache.EnsureModule('{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}',0,
1, 1)
class IE_Events(ie_mod.DWebBrowserEvents2):
def OnNavigateComplete2(self, pDisp, URL):
print 'OnNavigateComplete2:', URL

ie=win32com.client.DispatchWithEvents('InternetExplorer.Application',IE_Events)
ie.Visible=1
ie.Navigate('http://www.google.com')

hth
Roger
 
C

cal_2pac

Hi
Thanks for the response and for the code.
However, I want to trap events like mouse click on the HTML document
loaded by the web browser control. The code mentioned below provides
events from the web browser control. I need to find out on which
particular HTML tag did the user click for example.
How do I find that out? There should be some way to refer to a document
from a given web browser control and start receiving events from it


Roger said:
The two you'll need to run makepy for are Microsoft Internet Controls and
Microsoft HTML object Library. If you run them manually, you should be
able to look at the generated code to get the guids.
Here's a minimal example:

import win32com.client

ie_mod=win32com.client.gencache.EnsureModule('{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}',0,

1, 1)
class IE_Events(ie_mod.DWebBrowserEvents2):
def OnNavigateComplete2(self, pDisp, URL):
print 'OnNavigateComplete2:', URL

ie=win32com.client.DispatchWithEvents('InternetExplorer.Application',IE_Events)
ie.Visible=1
ie.Navigate('http://www.google.com')

hth
Roger






----== Posted via Newsfeeds.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption
=----
 
R

Roger Upole

ie.Document will give you the document object.
That's where the Html object library comes in,
it contains the early-binding code for the Document
interface. Then you can hook one of the event classes
for the Document (I see several in the generated file)
using the same methodology as shown for the web
browser events.

Roger
 
R

Roger Upole

Here's a few more lines that hook the document's onactivate event.

import win32com.client

ie_mod=win32com.client.gencache.EnsureModule('{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}'
,0, 1, 1)
doc_mod=win32com.client.gencache.EnsureModule('{3050F1C5-98B5-11CF-BB82-00AA00BDCE0B}'
,0 ,4, 0)
class IE_Events(ie_mod.DWebBrowserEvents2):
def OnNavigateComplete2(self, pDisp, URL):
print 'OnNavigateComplete2:', URL

class Doc_Events(doc_mod.HTMLAnchorEvents):
def Ononactivate(self):
print 'onactivate', self.activeElement.outerHTML

ie=win32com.client.DispatchWithEvents('InternetExplorer.Application',IE_Events)
ie.Visible=1
ie.Navigate('http://www.google.com')

d=win32com.client.DispatchWithEvents(ie.Document, Doc_Events)

Roger
 
C

cal_2pac

Thanks for your prompt responses and the code.
However, when I run the code I get com error
d=win32com.client.DispatchWithEvents(ie.Document, Doc_Events)
File "C:\Python23\lib\site-packages\win32com\client\__init__.py",
line 199, in __getattr__
return getattr(self._obj_, attr)
File "C:\Python23\lib\site-packages\win32com\client\__init__.py",
line 455, in __getattr__
return self._ApplyTypes_(*args)
File "C:\Python23\lib\site-packages\win32com\client\__init__.py",
line 446, in _ApplyTypes_
return self._get_good_object_(
com_error: (-2147352567, 'Exception occurred.', (0, None, None, None,
0, -2147467259), None)

I am a newbie to python(started coding a few months ago).
This appears to be a fairly common error when COM objects are not
hooked up properly. Though I have not been able to find a solution or
the reason for this.
Thanks again for the explanation.All the information that I had
acquired now seems to fall into place. I was not aware about
doc_mod.HTMLAnchorEvents. Where can I find more documentation about
this?
 
R

Roger Upole

Usually you get that error if you try to access the Document object
before the page has loaded. Try adding a delay after ie.Navigate,
something like

while ie.ReadyState<>4:
time.sleep(0.5)
There are some constants that show up in win32com.client.constants
that represent the ReadyState's, but I can't remember the names offhand.

The only real reference for the Html objects (other than reading the
generated module) is MSDN. Google turned this up:
http://msdn.microsoft.com/library/d.../events/htmlanchorevents/htmlanchorevents.asp

Roger
 
C

cal_2pac

Thanks for the response again. The solution is pretty close but not yet
complete
This is what I observed.
a) I tried to use the delay mechanism as suggested below
ie.
ie.Navigate('www.google.com')
while ie.ReadyState !- 4
time.sleep(0.5)

d=win32com.client.DispatchWithEvents(ie.Document, Doc_Events)

IE *fails* to load the webpage

b) Then I changed the delay to a specified time interval eg
ie.Navigate('www.google.com')
time.sleep(60) #wait for a minute
d=win32com.client.DispatchWithEvents(ie.Document, Doc_Events)

IE loads the web page *after* 60 seconds

c) Then I used raw_input() eg
ie.Navigate('www.google.com')
raw_input()
d=win32com.client.DispatchWithEvents(ie.Document, Doc_Events)
IE now loads the webpage and prompts the user. If I click on the web
page *before* clicking ok on the raw_input prompt - then it correctly
invokes the Doc_Events method Ononactivate method.
From these observations, it seems that there is some kind of a race
condition / timing issue happening. Can you please comment (or maybe
point me to other sources of info that I can investigate).
I am running Python 2.3 on Windows 2k machine.

Roger said:
Usually you get that error if you try to access the Document object
before the page has loaded. Try adding a delay after ie.Navigate,
something like

while ie.ReadyState<>4:
time.sleep(0.5)
There are some constants that show up in win32com.client.constants
that represent the ReadyState's, but I can't remember the names offhand.

The only real reference for the Html objects (other than reading the
generated module) is MSDN. Google turned this up:
http://msdn.microsoft.com/library/d.../events/htmlanchorevents/htmlanchorevents.asp

Roger






----== Posted via Newsfeeds.Com - Unlimited-Uncensored-Secure Usenet News==----
http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
----= East and West-Coast Server Farms - Total Privacy via Encryption
=----
 
J

J Correia

Thanks for the response again. The solution is pretty close but not yet
complete
This is what I observed.
a) I tried to use the delay mechanism as suggested below
ie.
ie.Navigate('www.google.com')
while ie.ReadyState !- 4
time.sleep(0.5)

d=win32com.client.DispatchWithEvents(ie.Document, Doc_Events)

IE *fails* to load the webpage

Thought this was quite curious so tried it myself (on Python 2.3 Win2k
machine). Put in some timing conditions and the problem is not that it
fails to load, but that it takes really long (min time during tests = 60
secs
, maximum time 580 secs).

Tried using just WithEvents, same problem. The problem seems to
lie with the call to ie.ReadyState while trapping events. 2 things lead me
to believe this...
1) Interrupting the Python code after the browser window opens, results in
the window
finishing and loading the URL immediately with no problems.
2) Running the code with just Dispatch (no events) and it works fine (< 1
sec).

All I can think is that each call to ie.ReadyState triggers some internal
event which hogs resources to process.

It seems like the problem is with IE Events only... so a possible workaround
(if all you need is the Doc events) is the following:
-------------------------
import win32com.client

class Doc_Events:
def Ononactivate(self):
print 'onactivate:', doc.location.href
def Ononclick(self):
print 'onclick fired.'
def Ononreadystatechange(self):
print 'onreadystatechange:', doc.readyState

ie = win32com.client.Dispatch("InternetExplorer.Application")
ie.Visible = 1
ie.Navigate('http://www.google.com')

while ie.ReadyState != 4:
time.sleep(1)

doc = ie.Document
doc_events = win32com.client.WithEvents(doc, Doc_Events)
# OR can use following:
# doc = win32com.client.DispatchWithEvents(ie.Document, Doc_Events)

while ie.ReadyState != 4 and doc.readyState != "complete":
# readystate is case sensitive and differs for ie (R) and doc (r)
# ie.ReadyState: 0=uninitialised; 1=loading; 2=loaded;
# 3=interactive; 4=complete
time.sleep(1)
 
R

Roger Upole

There does appear to be some sort of conflict between the two event
hooks. I wasn't seeing it before since IE was getting google from my
browser cache and it was coming up almost instantaneously. As soon
as I switched the URL to a page that loads slowly, I got the same
result.

Adding win32gui.PumpWaitingMessages() to the wait loop
seems to allow both event hooks to run without blocking each other.

Roger
 
J

J Correia

Roger Upole said:
There does appear to be some sort of conflict between the two event
hooks. I wasn't seeing it before since IE was getting google from my
browser cache and it was coming up almost instantaneously. As soon
as I switched the URL to a page that loads slowly, I got the same
result.

Adding win32gui.PumpWaitingMessages() to the wait loop
seems to allow both event hooks to run without blocking each other.

Roger

I added that line to the wait loop and while it does indeed speed it
up dramatically (in 10 tests: min = 13 sec; max = 33, ave ~ 20 secs)
it's still nowhere near the 1-2 secs it takes without hooking the
IE events. I also can't explain the wide differences between min
and max times since they seem to occur randomly
(e.g. min occurred on 7th run, max on 4th).

I assume that that response time won't be adequate for the original
poster's needs, due to the slowdown in browsing for his users.

Jose
 
R

Roger Upole

Reducing the sleep time in the loop also seems to speed things up.
I'm guessing due to giving both event loops more resources, but
I can't prove it conclusively.

This might make a good candidate for the Cookbook (or there's
a collection of IE automation examples at win32com.de)
so anybody else trying to do something similar knows some of the pitfalls.

Roger
 
C

cal_2pac

This might make a good candidate for the Cookbook (or there's
a collection of IE automation examples at win32com.de)
so anybody else trying to do something similar knows some of the
pitfalls.

This thread has been very valuable for me and has provided
clarifications which I could not get after hours of surfing web
/reading python on win32 / python developer handbook and so on.

Here are more questions that I am encountering
a) the code above will return a click event from an anchor element.
However, I need to identify which anchor element was clicked on.
Similarly, if a user clicks on one cell in HTML table - I need to
determine its identity.
One possible solution to this will be to look at the onClick event
provided by HTML_DocumentEvents and as desribed in msdn library
http://msdn.microsoft.com/library/d...op/browser/mshtml/reference/events/events.asp

The problem is that msdn documentation says that in order to identify
the element that was clicked - one has to query on IHTMLWindow2::event
property on iHTMLWindow2 interface to get IEventOBj interface and then
from there - use query interfce to get to the id of the element.

How do I do this in python? ie. I have this code
class Doc_Events(doc_mod.HTMLDocumentEvents):
def Ononclick(self):
print 'onClick fired '
and I see onClick being trapped.
Now I need to go and get a reference to the iHTMLWindow2 interface. For
this I need to get a reference to doc_mod (as far as I can see). How do
I get that in the OnonClick method above.

b) You had mentioned PumpWaitingMessages in the previous posting. I
first encountered this on newsgroup postings. None of the standard
books (python on win32 / python developer) seem to explain this in
detail although this seems to be commonly used. Though I understand
this now - my problem is that there seems to be a lack of cohesive
explanation on how python ties up with COM (despite a good chapter 12
on python win32 book). How does a newbie get more info on coding?
Essentially (a) is also a generic question which can be included in a
standard text. If nothing of this sort exists - maybe I will think of
jotting down the notes and posting on a public website.
 
R

Roger Upole

....
The problem is that msdn documentation says that in order to identify
the element that was clicked - one has to query on IHTMLWindow2::event
property on iHTMLWindow2 interface to get IEventOBj interface and then
from there - use query interfce to get to the id of the element.

How do I do this in python? ie. I have this code
class Doc_Events(doc_mod.HTMLDocumentEvents):
def Ononclick(self):
print 'onClick fired '
and I see onClick being trapped.
Now I need to go and get a reference to the iHTMLWindow2 interface. For
this I need to get a reference to doc_mod (as far as I can see). How do
I get that in the OnonClick method above.

To get the IHTMLWindow2, you can just use self.parentWindow
inside the event hander, and then get the event from it. And then
the event's srcElement should be what you need.

class Doc_Events(doc_mod.HTMLDocumentEvents):
def Ononclick(self):
print 'onclick'
ev=self.parentWindow.event
src=ev.srcElement
print 'tagName:',src.tagName,'name:',src.getAttribute('name')

For clicking on google's input field, this yields
tagName: INPUT name: q
b) You had mentioned PumpWaitingMessages in the previous posting. I
first encountered this on newsgroup postings. None of the standard
books (python on win32 / python developer) seem to explain this in
detail although this seems to be commonly used. Though I understand
this now - my problem is that there seems to be a lack of cohesive
explanation on how python ties up with COM (despite a good chapter 12

PumpWaitingMessages is just a way to ensure that normal message processing
(window messages, events, dde, etc) happens while python code is running.
Normally you don't need it, but every once in a while you hit a situation
where
blocking occurs.

For how exactly python interacts with COM, the source is your best bet.

Roger
 
C

cal_2pac

Resurrecting an old thread..
It seems that this solution does not return events on objects within
frames in webpages eg . if you go to www.andersondirect.com - the page
is composed of three frames called as topFrame main and address. Now
when I click on say 'Select a Vehicle' which is within main - I do not
get any Onclick event. I also do not get an OnMousemove event if I move
the mouse. However, I do get on Mousemove event on a tag called as
frameset (which is part of the top page).
How does one get events from the frames then?
As always thanks a lot.
 
R

Roger Upole

Each frame acts as a separate document.
You should be able catch document events
from a frame using something like
win32com.client.DispatchWithEvents(ie.Document.frames(<nbr of frame>).document, <your event class>)

Roger
 
J

J Correia

Roger Upole said:
Each frame acts as a separate document.
You should be able catch document events
from a frame using something like
win32com.client.DispatchWithEvents(ie.Document.frames(<nbr of
frame>).document said:

What Roger said is correct, however the frames you're wanting on that site are
running Flash apps. I'm not aware of any method that allows one to intercept
clicks within a Flash app. And even if you could determine a click occurred,
you'd have to figure out where in the app precisely and what Flash will do with
that
information. I suspect this is not possible by design (i.e. security reasons,
etc.)

JC
 
C

calfdog

You also want to make sure the frame you want is loaded

I use the following method:

def _frameWait(self, frameName=None):

thisCount = self._timeOut
while self._ie.Busy:
time.sleep(0.1)
thisCount = thisCount - 1
if thisCount == 0: break

# wait for user specified Document to load
doc = self._ie.Document.frames[frameName].Document
# Check results
bresult = False

thisCount = self._timeOut #reset the timeout counter
while doc.ReadyState != 'complete':
time.sleep(0.1)
thisCount = thisCount - 1
if thisCount == 0: break
if doc.ReadyState == 'complete':
bresult = True
if bresult == True:

print "Using Frame: " ,frameName
else:
print " Loading . . ."
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top