Что нового

Работа с <IE.au3>, проверка на существование объекта

DruKot

Новичок
Сообщения
8
Репутация
0
Добрый день,
Пишу программку - автоматизацию рутинной работы (до 10 000 повторений)
Изначально использовал функцию Sleep, как и все нормальные люди, но из за большого колличества повторений случается, что браузер подвисает и некоторые циклы заканчиваются с ошибкой.
Написал функцию проверки, должна работать так: если поле (форма, фрейм) не загрузились - ждать, но проблема в том, что если объект еще не загрузился и запускается цикл ожидания - то он из него уже никогда не выходит, а если успевает погрузиться до вызова этой функции, то проходит ее без проблем.
Ниже кусок кода и сама функция.
Код:
;.........
_IELoadWait($oIE)

check(_IEFrameGetObjByName($oIE, "fr3"))

$oFrame = _IEFrameGetObjByName($oIE, "fr3");
_IEFormElementSetValue(_IEGetObjById($oFrame,"pname"),"Иван")
;Заполняем форму.....

Func check($obj)
	While 1
		If IsObj($obj) Then
			ExitLoop
		EndIf
		Sleep(100)
	WEnd
EndFunc

Прошу помочь разобраться почему код зацикливается
 

alex33

Скриптер
Сообщения
1,457
Репутация
186
Попробуй проверять флаг @error, если он не равен нулю то ошибка.
Код:
If @error Then
	; ошибка
Else
	; успешно
EndIf


Код:
If @error Then ; ошибка
If Not @error Then ; успешно
 
Автор
D

DruKot

Новичок
Сообщения
8
Репутация
0
Сделал так, теперь пролетает функцию насквозь, даже если объект еще не загрузился
Код:
Func check($obj)
	While 1
		IsObj($obj)
		If @error == 0 Then
			ExitLoop
		EndIf
		Send("1")
		Sleep(100)
	WEnd
EndFunc


Send("1") - это я проверяю, что цикл "живой"


Добавлено:
Сообщение автоматически объединено:

На сколько я понимаю проблемма заключается в том, что на момент вызова функции я отправляю в нее переменную с пустым объектом, и она уже гоняет его по кругу независимо от того появился объект на самой странице, или нет.... Проблему бы решила ссылка, или goto, но ни того, ни другого в autoit нет... Я даже подумывал подключить в код JQuery с document.ready, но если я правильно понял проблемму - ситуация не измениться, тк на момент вызова в функцию опять попадет пустая переменная...
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Так вы в цикле и ищите объект, если нашелся значит выход. Добавьте еще таймер, и если цикл длится больше 30 секунд, например, то выходите.
Таймеры:
Код:
TimerInit TimerDiff
 
Автор
D

DruKot

Новичок
Сообщения
8
Репутация
0
inververs
Если так сделать, то он каждый раз будет ждать 30 секунд, тк если заменить мою функцию на Sleep(3000), то все выполняется в 95% случаев, да и визуально я вижу, что форма загрузилась, а цикл продолжает рисовать единицы (то есть объекта не видит).
 

inververs

AutoIT Гуру
Сообщения
2,135
Репутация
465
Как так? Если так как вы сделаетe то да, будет ждать 30 секунд :rofl:
Вот так делайте:
Код:
Func wait()
	Local $iTimer = TimerInit()
	Do
		If IsObj(_IEFrameGetObjByName($oIE, "fr3")) Then Return True
		Sleep(500)
	Until TimerDiff($iTimer) > 30000
	Return False
EndFunc
 
Автор
D

DruKot

Новичок
Сообщения
8
Репутация
0
inververs
Попробовал Ваш код - то же самое, объект давно загружен, но цикл этого не видит - через 30 секунд продолжает выполнение. В общем не помогло, вариант поставить везде слип на 10 секунд - не вариант, тк один проход цикла должен будет спать около минуты в общем, а если умножить это на 10 000 повторений, то как то грустно... Поэтому мне и нужна эта функция - продолжать выполнение по готовности

Как так? Если так как вы сделаетe то да, будет ждать 30 секунд :rofl:

Не понял, если Вы понимаете почему он не работает, то так и скажите, но Ваш код работает точно так же...


Добавлено:
Сообщение автоматически объединено:

alex33
Спасибо за совет
 

uritalex

Новичок
Сообщения
197
Репутация
3
Если я Вас правильно понял то у Вас проблема с задержкой времени для проверки наличия элемента т.к. одна и та же задержка (при постоянном значении) один раз слишком много, один раз слишком мало. Как раз недавно нашел для себя своеобразное решение:

Код:
;.........
_IELoadWait($oIE)

Do 
	  Sleep (1000)
Until  Wait ("fr3") = 1 
    ; стандартный цикл на проверку условия, если условие Wait ("fr3") = 1 соблюдается то цикл останавливается и ;идет дальнейшее выполнение скрипта, если условие Wait ("fr3") = 1 не соблюдается то цикл выполняет команду ;Sleep (1000) до тех пор пока условие Wait("fr3") = 1 не будет соблюденным.

$oFrame = _IEFrameGetObjByName($oIE, "fr3");
_IEFormElementSetValue(_IEGetObjById($oFrame,"pname"),"Иван")
;Заполняем форму.....

Func Wait ($Text)
  $Gobj = _IEFrameGetObjByName($oIE, $Text)
  If IsObj($Gobj) Then Return 1
EndFunc
 
Автор
D

DruKot

Новичок
Сообщения
8
Репутация
0
К сожалению все та же история - после входа в цикл, он уже от туда не выходит, как будто объект не существует, я бы уже подумал что что то с самим сайтом, но опять же - заменить все это дело на слим в 3 секунды и все проходит без проблем.
 

uritalex

Новичок
Сообщения
197
Репутация
3
Хм... Как вариант конечно могу предложить еще один способ через UIAutomate.au3 и утилиту Inspect (загрузить можно тут: http://autoit-script.ru/index.php?topic=16780.0):

Код:
#include <UIAutomate.au3> 

Для начала берем Хендл вызванного окна 

$handle = WinGetHandle ($oIE)

_IELoadWait($oIE)

Do 
      Sleep (1000)
Until  Wait ("??????") = 1 ; тут вводить уникальную строчку с формы которую ждете 
    
$oFrame = _IEFrameGetObjByName($oIE, "fr3");
_IEFormElementSetValue(_IEGetObjById($oFrame,"pname"),"Иван")
;Заполняем форму.....

Func Wait ($Text, $fInStr = True)
  Local $oParent = _UIA_GetElementFromHandle($handle)
  Local $oElement = _UIA_GetControlTypeElement($oParent, $UIA_EditControlTypeId, $Text, "Name")
  If IsObj($oElement) Then Return 1
EndFunc

А еще конечно лучше указать ссыль на сайт и страницу которые нужно обработать ;)
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
DruKot [?]
если поле (форма, фрейм) не загрузились - ждать
Код:
#include<IE.au3>

Local $bComplete = False
Local $oIE = _IECreate('about:blank')
Local $oIEEvents = ObjEvent($oIE, "_IEEvent_", "DocumentComplete")
_IENavigate($oIE, 'http://autoit-script.ru')

_Authorization($oIE, 'Login', 'Passw')

Func _Authorization(ByRef $o_Obj, $s_Login, $s_Passw)

	If $bComplete Then
		; Заполняем форму.....
		$o_Frame = _IEGetObjById($o_Obj, 'guest_form')
		_IEFormElementSetValue(_IEGetObjByName($o_Frame, "user"), $s_Login)
		_IEFormElementSetValue(_IEGetObjByName($o_Frame, "passwrd"), $s_Passw)
		_IEFormSubmit($o_Frame)
	EndIf

	$bComplete = False
EndFunc ;==>_Authorization

Func _IEEvent_DocumentComplete($o_Disp, $s_URL)

	If IsObj($o_Disp) And ObjName($o_Disp) == 'IWebBrowser2' Then
		ConsoleWrite(StringFormat('Document: %s --> complete...\n', _IEPropertyGet($o_Disp, 'title')))
		$bComplete = True
	EndIf
EndFunc   ;==>_IEEvent_DocumentComplete
 
Автор
D

DruKot

Новичок
Сообщения
8
Репутация
0
uritalex
Подключил либу, но все та же проблемма....

arrett
Я вообще Вас не понял, у меня все хорошо с авторизацией, к этому моменту я давно ее прохожу. Видимо Вы вообще не поняли суть проблемы((
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
DruKot [?]
Видимо Вы вообще не поняли суть проблемы
Видимо вы не правильно поставили вопрос.

Что тут непонятного?
если поле (форма, фрейм) не загрузились - ждать

У вас происходит обращение к элементу DOM в момент когда он ещё не загружен. Не загружен он может быть по разным причинам. Я написал вам пример который гарантирует полную загрузку DOM.
Пример функции _Authorization это как пример, в тело функции вы можете написать всё что угодно.
Ключевой момент тут:
Код:
Local $bComplete = False

Func _Authorization(ByRef $o_Obj, $s_Login, $s_Passw)

    If $bComplete Then ; Если DOM загружен...
        ; Делаем всё что угодно...
    EndIf

    $bComplete = False
EndFunc ;==>_Authorization

Func _IEEvent_DocumentComplete($o_Disp, $s_URL)

    If IsObj($o_Disp) And ObjName($o_Disp) == 'IWebBrowser2' Then
        ConsoleWrite(StringFormat('Document: %s --> complete...\n', _IEPropertyGet($o_Disp, 'title')))
        $bComplete = True
    EndIf
EndFunc   ;==>_IEEvent_DocumentComplete
 
Автор
D

DruKot

Новичок
Сообщения
8
Репутация
0
Garrett
Возможно я космически туп, но я вообще не понимаю что делает ваш код и как он работает, конкретно:
Код:
Local $bComplete = False ;Создаем переменную, которая следит за состоянием, окай

Func _Authorization(ByRef $o_Obj, $s_Login, $s_Passw) ; здесь Вы зачем то суете заполнение формы в функцию, зачем - не понятно

    If $bComplete Then ; ну тут понятно, если переменная изменила значение - работаем, а если нет..... то тупо пролетаем мимо??
        ; Делаем всё что угодно...
    EndIf

    $bComplete = False ;зачем то возвращаем значение переменной назад на "не загружен"
EndFunc ;==>_Authorization

Func _IEEvent_DocumentComplete($o_Disp, $s_URL) ; функция, которая проверяет состояние страницы... нигде не вызывается........ так и должно быть? $s_URL - зачем??

    If IsObj($o_Disp) And ObjName($o_Disp) == 'IWebBrowser2' Then ; Делаем то же, что делал и я + сравниваем с каким то  'IWebBrowser2' ...
        ConsoleWrite(StringFormat('Document: %s --> complete...\n', _IEPropertyGet($o_Disp, 'title'))) ; пишем в консоль... зачем то... что то....
        $bComplete = True ; ура, каким то чудом узнаем, что сайт загрузился и меняем значение переменной
    EndIf
EndFunc   ;==>_IEEvent_DocumentComplete


Не поймите меня не правильно, я очень благодарен за любую помощь и не прошу сделать все за меня.... но Ваш код просто чудовищно непонятен...


Добавлено:
Сообщение автоматически объединено:

Есть небольшой прогресс, просто передаю в функцию строку с именем объекта, а не сам объект и цикл теперь каждый раз проверяет существование объекста с таким именем на странице, а не стал ли передаваемый объект существующим :D

Код:
_IELoadWait(_IEFrameGetObjByName($oIE, "fr3")) ;костыль №1 - Не работает сам по себе, но немного повышает стабильность, решил оставить
check("fr3")
Sleep(1000) ;Костыль №2 - тк после того, как объект появляется в DOM он не сразу же рисуется... короче без этого пролетает мимо

Func check($name)
	While 1
		If IsObj(_IEFrameGetObjByName($oIE,$name)) Then ;проверяем реальную ситуацию на странице
			ExitLoop
		EndIf
		Sleep(1000)
	WEnd
EndFunc


Почему то, если засунуть костыли в саму функцию до и после цикла - возвращает ошибку


Line 1899 путь к IE.au3
If IsObj($oObject.document.getElementById($sID)) Then
If IsObj($oObject.document^ ERROR
Error: The requested action with this object has failed.

:scratch:

ПС жду еще сутки и если решения лучше и стабильнее не придумается - закрою тему

ППС - ВАЖНО! нужно поменять вызов функции с костылем №1 местами!!!
Код:
check("fr3")
_IELoadWait(_IEFrameGetObjByName($oIE, "fr3"))
Sleep(1000)
 

Garrett

Модератор
Локальный модератор
Сообщения
3,999
Репутация
967
DruKot [?]
ПС жду еще сутки и если решения лучше и стабильнее не придумается - закрою тему
Это ваше право. Но в таком тоне не нужно писать, вам ни кто ни чем не обязан!

Есть небольшой прогресс
Хоть что-то, чем ничего.

Может ссылку на сайт дадите?
Код:
#include<IE.au3>

Local $bComplete = False
Local $oIE = _IECreate('about:blank')
Local $oIEEvents = ObjEvent($oIE, "_IEEvent_", "DocumentComplete")
_IENavigate($oIE, 'http://yousite.com')


While 1
	If $bComplete Then ; Если DOM загружен...
		  ; Делаем всё что угодно...
		$oFrame = _IEFrameGetObjByName($oIE, "fr3")
		_IEFormElementSetValue(_IEGetObjById($oFrame,"pname"),"Иван")
		;Заполняем форму.....
		$bComplete = False
	EndIf
	Sleep(10)
WEnd

Func _IEEvent_DocumentComplete($o_Disp, $s_URL)

	If IsObj($o_Disp) And ObjName($o_Disp) == 'IWebBrowser2' Then
		ConsoleWrite(StringFormat('Document: %s --> complete...\n', _IEPropertyGet($o_Disp, 'title')))
		$bComplete = True
	EndIf
EndFunc   ;==>_IEEvent_DocumentComplete


И ещё, не забывайте что для загрузки документа в кадр (frame) может понядобится время.

P.S. Учитесь хоть немного осмысливать информацию.
 
Автор
D

DruKot

Новичок
Сообщения
8
Репутация
0
Garrett
Это ваше право. Но в таком тоне не нужно писать, вам ни кто ни чем не обязан!
Я не имел в виду ничего подобного, это обращение к модераторам, что бы они не закрыли тему, тк какое то решение было найдено.

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

И ещё, не забывайте что для загрузки документа в кадр (frame) может понядобится время.
Скорее всего в этом и есть проблема, тк сайт кидает из фрейма в фрейм как сумасшедший...

В общем мой вариант вполне отвечает моим требованиям, остановлюсь именно на нем, всем спасибо за советы, тему закрываю.

ПС: Если кто то знает что то про ошибку из предыдущего поста - буду рад, если подскажите ))
 
Верх