python com getelementbyid win32com

python - Interesante "getElementById() toma exactamente 1 argumento(2 dado)", a veces ocurre. ¿Alguien puede explicarlo?



com win32com (4)

Acabo de recibir este problema cuando me actualicé a IE11 desde IE8.

Solo he probado esto en la función getElementsByTagName. Tienes que llamar a la función desde el elemento del cuerpo.

#-*- coding:utf-8 -*- import win32com.client, pythoncom import time ie = win32com.client.DispatchEx(''InternetExplorer.Application.1'') ie.Visible = 1 ie.Navigate(''http://ieeexplore.ieee.org/xpl/periodicals.jsp'') time.sleep( 5 ) ie.Document.Body.getElementById("browse_keyword").value ="Computer" ie.Document.Body.getElementsByTagName("input")[24].click()

#-*- coding:utf-8 -*- import win32com.client, pythoncom import time ie = win32com.client.DispatchEx(''InternetExplorer.Application.1'') ie.Visible = 1 ie.Navigate(''http://ieeexplore.ieee.org/xpl/periodicals.jsp'') time.sleep( 5 ) ie.Document.getElementById("browse_keyword").value ="Computer" ie.Document.getElementsByTagName("input")[24].click()

import win32com.client, pythoncom import time ie = win32com.client.DispatchEx(''InternetExplorer.Application'') ie.Visible = 1 ie.Navigate(''www.baidu.com'') time.sleep(5) print ''browse_keword'' ie.Document.getElementById("kw").value ="Computer" ie.Document.getElementById("su").click() print ''Done!''

Cuando ejecute el primer código de sección, aparecerá una ventana emergente:

ie.Document.getElementById("browse_keyword").value ="Computer" TypeError: getElementById() takes exactly 1 argument (2 given)

Y el segundo código de sección funciona bien. ¿Cuál es la diferencia que hace que el resultado sea diferente?


Como método de un COMObject , getElementById está construido por win32com forma dinámica.
En mi computadora, si url es http://ieeexplore.ieee.org/xpl/periodicals.jsp , será casi equivalente a

def getElementById(self): return self._ApplyTypes_(3000795, 1, (12, 0), (), ''getElementById'', None,)

Si la URL es www.baidu.com, será casi equivalente a

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

Obviamente, si pasa un argumento al primer código, recibirá un TypeError . Pero si intenta usarlo directamente, es decir, invocar ie.Document.getElementById() , no recibirá un TypeError , sino un com_error .

¿Por qué win32com construyó el código incorrecto?
Veamos ie y ie ie.Document . Ambos son COMObject , más precisamente, instancias de win32com.client.CDispatch . CDispatch es solo una clase de contenedor. El núcleo es el atributo _oleobj_ , cuyo tipo es PyIDispatch .

>>> ie, ie.Document (<COMObject InternetExplorer.Application>, <COMObject <unknown>>) >>> ie.__class__, ie.Document.__class__ (<class win32com.client.CDispatch at 0x02CD00A0>, <class win32com.client.CDispatch at 0x02CD00A0>) >>> oleobj = ie.Document._oleobj_ >>> oleobj <PyIDispatch at 0x02B37800 with obj at 0x003287D4>

Para compilar getElementById , win32com necesita obtener la información de tipo para el método getElementById de _oleobj_ . Aproximadamente, win32com usa el siguiente procedimiento

typeinfo = oleobj.GetTypeInfo() typecomp = typeinfo.GetTypeComp() x, funcdesc = typecomp.Bind(''getElementById'', pythoncom.INVOKE_FUNC) ......

funcdesc contiene casi toda la información de importación, por ejemplo, el número y los tipos de los parámetros.
Si url es http://ieeexplore.ieee.org/xpl/periodicals.jsp , funcdesc.args es () , mientras que el funcdesc.args debe ser ((8, 1, None),) .

Larga historia en resumen, win32com había recuperado la información del tipo incorrecto, por lo que construyó el método equivocado.
No estoy seguro de quién es el culpable, PyWin32 o IE. Pero basado en mi observación, no encontré nada incorrecto en el código de PyWin32. Por otro lado, la siguiente secuencia de comandos se ejecuta perfectamente en Windows Script Host .

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";

Duncan ya ha señalado que el modo de compatibilidad de IE puede prevenir el problema. Desafortunadamente, parece que es imposible habilitar el modo de compatibilidad desde un script.
Pero encontré un truco, que puede ayudarnos a evitar el problema.

En primer lugar, debe visitar un buen sitio, que nos proporciona una página HTML, y recuperar un objeto Document correcto a partir de él.

ie = win32com.client.DispatchEx(''InternetExplorer.Application'') ie.Visible = 1 ie.Navigate(''http://www.haskell.org/arrows'') time.sleep(5) document = ie.Document

Luego salta a la página que no funciona

ie.Navigate(''http://ieeexplore.ieee.org/xpl/periodicals.jsp'') time.sleep(5)

Ahora puede acceder al DOM de la segunda página a través del antiguo objeto Document .

document.getElementById(''browse_keyword'').value = "Computer"

Si usa el nuevo objeto Document , obtendrá un TypeError nuevamente.

>>> ie.Document.getElementById(''browse_keyword'') Traceback (most recent call last): File "<interactive input>", line 1, in <module> TypeError: getElementById() takes exactly 1 argument (2 given)


La diferencia entre los dos casos no tiene nada que ver con el nombre COM que especifique: InternetExplorer.Application o InternetExplorer.Application.1 dan como resultado exactamente el mismo CLSID que le proporciona una interfaz IWebBrowser2 . La diferencia en el comportamiento del tiempo de ejecución se reduce exclusivamente a la URL que recuperó.

La diferencia aquí puede ser que la página que funciona es HTML mientras que la otra es XHTML; o simplemente puede ser que los errores en la página que falla impidan que DOM se inicialice correctamente. Cualquiera que sea, parece ser una ''característica'' del analizador IE9.

Tenga en cuenta que esto no ocurre si habilita el modo de compatibilidad (después de la segunda línea a continuación, hice clic en el ícono del modo de compatibilidad en la barra de direcciones):

(Pdb) ie.Document.DocumentMode 9.0 (Pdb) ie.Document.getElementById("browse_keyword").value *** TypeError: getElementById() takes exactly 1 argument (2 given) (Pdb) ie.Document.documentMode 7.0 (Pdb) ie.Document.getElementById("browse_keyword").value u''''

Lamentablemente, no sé cómo alternar el modo de compatibilidad desde un script (la propiedad documentMode no se puede configurar). Tal vez alguien más lo hace?

El recuento de argumentos incorrecto es, creo, procedente de COM: Python pasa los argumentos y el objeto COM rechaza la llamada con un error engañoso.


Las llamadas a métodos de instancias en Python agregan automáticamente la instancia como primer argumento, por eso tiene que escribir explícitamente el argumento ''self'' dentro de los métodos.

Por ejemplo, instance.method(args...) es igual a Class.method(instance, args...) .

Por lo que veo, el programador debe haber olvidado escribir la palabra clave self, lo que da como resultado la ruptura del método. Intenta mirar dentro del código de la biblioteca.