Подтвердить что ты не робот

Интересный "getElementById() принимает ровно 1 аргумент (2 данный)", иногда это происходит. Может кто-нибудь объяснить это?

#-*- 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!'

При запуске кода первого раздела он будет всплывать:

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

И код второго раздела работает нормально. В чем разница между тем, что результат отличается?

4b9b3361

Ответ 1

Разница между этими двумя случаями не имеет никакого отношения к указанному COM-имени: либо InternetExplorer.Application, либо InternetExplorer.Application.1 приводит к тому же CLSID, который дает вам интерфейс IWebBrowser2. Разница во времени выполнения сводится к тому, что вы получили URL.

Разница здесь может заключаться в том, что страница, которая работает, является HTML, тогда как другая - XHTML; или просто может быть, что ошибки на странице с ошибкой предотвращают правильную инициализацию DOM. Какая бы ни была "особенностью" парсера IE9.

Обратите внимание, что это не происходит, если вы включаете режим совместимости (после второй строки ниже я нажал значок режима совместимости в адресной строке):

(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''

К сожалению, я не знаю, как переключить режим совместимости с script (свойство documentMode не может быть установлено). Может быть, кто-то другой?

Неверный подсчет аргументов, я думаю, исходит из COM: Python передает аргументы, а объект COM отклоняет вызов с ошибочной ошибкой.

Ответ 2

Как метод a COMObject, getElementById динамически построен win32com.
На моем компьютере, если url http://ieeexplore.ieee.org/xpl/periodicals.jsp, он будет почти эквивалентен

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

Если URL-адрес www.baidu.com, он будет почти эквивалентен

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

Очевидно, что если вы передадите аргумент первому коду, вы получите TypeError. Но если вы попытаетесь использовать его напрямую, а именно invoke ie.Document.getElementById(), вы не получите TypeError, но com_error.

Почему win32com построил неправильный код?
Посмотрим на ie и ie.Document. Они как COMObject s, точнее, win32com.client.CDispatch экземпляры. CDispatch - это просто класс оболочки. Ядром является атрибут _oleobj_, тип которого 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>

Чтобы построить getElementById, win32com необходимо получить информацию о типе для метода getElementById из _oleobj_. Пример: win32com использует следующую процедуру

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

funcdesc содержит почти всю информацию об импорте, например. количество и типы параметров.
Если url http://ieeexplore.ieee.org/xpl/periodicals.jsp, funcdesc.args - (), а для коррекции funcdesc.args должно быть ((8, 1, None),).

Короче говоря, win32com получил неверную информацию о типе, поэтому он построил неправильный метод.
Я не уверен, кто виноват, PyWin32 или IE. Но, основываясь на моем наблюдении, я не нашел ничего плохого в коде PyWin32. С другой стороны, следующий script отлично работает в 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";

Дункан уже указал, что режим совместимости IE может предотвратить проблему. К сожалению, кажется невозможным включить режим совместимости с script.
Но я нашел трюк, который может помочь нам обойти проблему.

Сначала вам нужно посетить хороший сайт, который дает нам HTML-страницу и извлекает из него правильный объект Document.

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

Затем перейдите на страницу, которая не работает

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

Теперь вы можете получить доступ к DOM второй страницы через старый объект Document.

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

Если вы используете новый объект Document, вы снова получите TypeError.

>>> 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)

Ответ 3

Вызов методов экземпляров в Python автоматически добавляет экземпляр в качестве первого аргумента - поэтому вы должны явно писать аргумент "self" внутри методов.

Например, instance.method(args...) равно Class.method(instance, args...).

Из того, что я вижу, программист, должно быть, забыл написать ключевое слово self, что привело к нарушению метода. Попробуйте заглянуть в библиотечный код.

Ответ 4

У меня появилась эта проблема, когда я обновился до IE11 из IE8.

Я тестировал это только в функции getElementsByTagName. Вы должны вызвать функцию из элемента Body.

#-*- 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()