Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>As a method of a <code>COMObject</code>, <code>getElementById</code> is built by <code>win32com</code> dynamically.<br/> On my computer, if url is <a href="http://ieeexplore.ieee.org/xpl/periodicals.jsp" rel="noreferrer">http://ieeexplore.ieee.org/xpl/periodicals.jsp</a>, it will be almost equivalent to </p> <pre><code>def getElementById(self): return self._ApplyTypes_(3000795, 1, (12, 0), (), 'getElementById', None,) </code></pre> <p>If the url is www.baidu.com, it will be almost equivalent to </p> <pre><code>def getElementById(self, v=pythoncom.Missing): ret = self._oleobj_.InvokeTypes(1088, LCID, 1, (9, 0), ((8, 1),),v ) if ret is not None: ret = Dispatch(ret, 'getElementById', {3050F1FF-98B5-11CF-BB82-00AA00BDCE0B}) return ret </code></pre> <p>Obviously, if you pass an argument to the first code, you'll receive a <code>TypeError</code>. But if you try to use it directly, namely, invoke <code>ie.Document.getElementById()</code>, you won't receive a <code>TypeError</code>, but a <code>com_error</code>.<br/></p> <p>Why <code>win32com</code> built the wrong code?<br/> Let us look at <code>ie</code> and <code>ie.Document</code>. They are both <code>COMObject</code>s, more precisely, <code>win32com.client.CDispatch</code> instances. <code>CDispatch</code> is just a wrapper class. The core is attribute <code>_oleobj_</code>, whose type is <code>PyIDispatch</code>.</p> <pre><code>&gt;&gt;&gt; ie, ie.Document (&lt;COMObject InternetExplorer.Application&gt;, &lt;COMObject &lt;unknown&gt;&gt;) &gt;&gt;&gt; ie.__class__, ie.Document.__class__ (&lt;class win32com.client.CDispatch at 0x02CD00A0&gt;, &lt;class win32com.client.CDispatch at 0x02CD00A0&gt;) &gt;&gt;&gt; oleobj = ie.Document._oleobj_ &gt;&gt;&gt; oleobj &lt;PyIDispatch at 0x02B37800 with obj at 0x003287D4&gt; </code></pre> <p>To build <code>getElementById</code>, <code>win32com</code> needs to get the type information for <code>getElementById</code> method from <code>_oleobj_</code>. Roughly, <code>win32com</code> uses the following procedure</p> <pre><code>typeinfo = oleobj.GetTypeInfo() typecomp = typeinfo.GetTypeComp() x, funcdesc = typecomp.Bind('getElementById', pythoncom.INVOKE_FUNC) ...... </code></pre> <p><code>funcdesc</code> contains almost all import information, e.g. the number and types of the parameters.<br/> If url is <a href="http://ieeexplore.ieee.org/xpl/periodicals.jsp" rel="noreferrer">http://ieeexplore.ieee.org/xpl/periodicals.jsp</a>, <code>funcdesc.args</code> is <code>()</code>, while the correc <code>funcdesc.args</code> should be <code>((8, 1, None),)</code>.</p> <p>Long story in short, <code>win32com</code> had retrieved the wrong type information, thus it built the wrong method.<br/> I am not sure who is to blame, PyWin32 or IE. But base on my observation, I found nothing wrong in PyWin32's code. On the other hand, the following script runs perfectly in <em>Windows Script Host</em>.</p> <pre><code>var ie = new ActiveXObject("InternetExplorer.Application"); ie.Visible = 1; ie.Navigate("http://ieeexplore.ieee.org/xpl/periodicals.jsp"); WScript.sleep(5000); ie.Document.getElementById("browse_keyword").value = "Computer"; </code></pre> <p>Duncan has already pointed out IE's compatibility mode can prevent the problem. Unfortunately, it seems it's impossible to enable compatibility mode from a script.<br/> But I found a trick, which can help us bypass the problem.<br/></p> <p>First, you need to visit a good site, which gives us a HTML page, and retrieve a correct <code>Document</code> object from it.<br/></p> <pre><code>ie = win32com.client.DispatchEx('InternetExplorer.Application') ie.Visible = 1 ie.Navigate('http://www.haskell.org/arrows') time.sleep(5) document = ie.Document </code></pre> <p>Then jump to the page which doesn't work</p> <pre><code>ie.Navigate('http://ieeexplore.ieee.org/xpl/periodicals.jsp') time.sleep(5) </code></pre> <p>Now you can access the DOM of the second page via the old <code>Document</code> object.</p> <pre><code>document.getElementById('browse_keyword').value = "Computer" </code></pre> <p>If you use the new <code>Document</code> object, you will get a <code>TypeError</code> again.</p> <pre><code>&gt;&gt;&gt; ie.Document.getElementById('browse_keyword') Traceback (most recent call last): File "&lt;interactive input&gt;", line 1, in &lt;module&gt; TypeError: getElementById() takes exactly 1 argument (2 given) </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload