1 (изменено: Gh0sTG0, 2018-12-04 00:08:32)

Тема: AHK: chrome.ahk внезапно зависает при выполнении команд.

Добрый вечер.
Использую библиотеку chrome.ahk.
Регулярно сталкиваюсь с тем, что выполняемая команда зависает и не возвращает ответ.
К примеру сейчас столкнулся с тем, что этим занимается команда Target.closeTarget.
Я разместил tooltip'ы в разных местах, так что если команда зависает, то предыдущий tooltip отображается, следующий уже нет, программа встала.


ToolTip A
PageInst.Call("Target.closeTarget", {targetId: id}) ;И я вижу, что вкладка закрылась, т.е. команда прошла и сработала.
ToolTip, B ;И я все еще вижу под курсором мыши букву A. И через 10 минут будет висеть буква А, а программа не будет работать дальше.

Случается эта неприятность далеко не каждый раз, возможны десятки применений команды без всяких проблем... или десяток зависаний подряд.
Сталкивался ли кто то с подобной проблемой? Удалось ли ее решить/выявить почему оно так?

2 (изменено: MandarinKa02, 2018-12-04 00:35:42)

Re: AHK: chrome.ahk внезапно зависает при выполнении команд.

Вот, вызываемая вами функция. Как вариант, установите влаг WaitForResponse в значение False и будет вам счастье.


Call(DomainAndMethod, Params:="", WaitForResponse:=True)
{
	if !this.Connected
		throw Exception("Not connected to tab")
	
	; Use a temporary variable for ID in case more calls are made
	; before we receive a response.
	ID := this.ID += 1
	this.ws.Send(Chrome.Jxon_Dump({"id": ID
	, "params": Params ? Params : {}
	, "method": DomainAndMethod}))
	
	if !WaitForResponse
		return
	
	; Wait for the response
	this.responses[ID] := False
	while !this.responses[ID]
		Sleep, 50
	
	; Get the response, check if it's an error
	response := this.responses.Delete(ID)
	if (response.error)
		throw Exception("Chrome indicated error in response",, Chrome.Jxon_Dump(response.error))
	
	return response.result
}	

P.S. отдельно замечание по поводу этой ф-ии.
Алгоритм здесь таков:
- отправляем действие N браузеру
- устанавливаем действию N значение FALSE (this.responses[ID] := False).
Есть предположение, что после послания действия браузеру, он(браузер) сразу же выдает ответ.
И как итог, алгоритм выглядит следующим образом:
- послал действие
- браузер ответил
- установил значение действию FALSE (то бишь, не выполнено)
На выходе получаем бесконечный цикл: (спасибо хоть задержку поставили, так-то бы и комп бухнул)

; Wait for the response
	while !this.responses[ID]
		Sleep, 50

P.P.S. Только догадки.

Попробуйте такой вариант:
- установил значение действию FALSE (то бишь, не выполнено)
- послал действие

+ открыть спойлер
Call(DomainAndMethod, Params:="", WaitForResponse:=True)
{
	if !this.Connected
		throw Exception("Not connected to tab")
	
	; Use a temporary variable for ID in case more calls are made
	; before we receive a response.
	ID := this.ID += 1
	this.responses[ID] := False
	this.ws.Send(Chrome.Jxon_Dump({"id": ID
	, "params": Params ? Params : {}
	, "method": DomainAndMethod}))
	
	if !WaitForResponse
		return
	
	; Wait for the response
	while !this.responses[ID]
		Sleep, 50
	
	; Get the response, check if it's an error
	response := this.responses.Delete(ID)
	if (response.error)
		throw Exception("Chrome indicated error in response",, Chrome.Jxon_Dump(response.error))
	
	return response.result
}

3

Re: AHK: chrome.ahk внезапно зависает при выполнении команд.

Gh0sTG0, а через selenium тоже зависает?

4

Re: AHK: chrome.ahk внезапно зависает при выполнении команд.

Malcev
Через selenium не пробовал, т.к. сейчас его не стоит (да и переписывать код под селениум... я слишком мало в нем разобрался, почти сразу свалил на chrome.ahk).

5 (изменено: Gh0sTG0, 2018-12-04 01:12:23)

Re: AHK: chrome.ahk внезапно зависает при выполнении команд.

MandarinKa02
1) Ранее, столкнувшись с подобной проблемой я слегка модифицировал код (тогда помогло):

FlipFlapper := 0
			while !this.responses[ID]
			{
				FlipFlapper += 1
				Sleep, 50
				If (FlipFlapper > 400)
				{
					throw Exception("CaptainResponses")
					return
				}
			}

В том месте у меня трай стоит, и его кэтч пишет в файлик датувремя сработки и перезапускает работу. Регулярно в файлике обнаруживаю новые датувремя.
2) PageInst.Call("Target.closeTarget", {targetId: id}, "False") сделал. PPS сделал. Вроде пока работает (правда точно не ясно, т.к. бывали у него и раньше просветления, когда он много раз срабатывал без проблем).

6

Re: AHK: chrome.ahk внезапно зависает при выполнении команд.

Попробуйте.
Из плюсов у него есть одно преимущество - встроенная обработка JSON.
Из-за этого получение исходной  страницы в разы быстрее.
Из минусов - придется выдумывать велосипед для некоторых операций, которые апи селениума не поддерживает.

7 (изменено: Gh0sTG0, 2018-12-04 11:34:11)

Re: AHK: chrome.ahk внезапно зависает при выполнении команд.

Upd: Опять сижу любуюсь на А...
PS Придумал другую штуку: взять адреса из "Chrome.GetPageList()", загнать их в array и потом for A, B from array прокрутить в новой вкладке (одной, не закрывая ее). Потом позакрывать все. Пойду попробую реализовать.

8 (изменено: MandarinKa02, 2018-12-04 02:43:52)

Re: AHK: chrome.ahk внезапно зависает при выполнении команд.

Можете скинуть рабочий пример, где происходит подобное? А ж интересно стало, где прокол.

9 (изменено: Gh0sTG0, 2018-12-04 12:19:11)

Re: AHK: chrome.ahk внезапно зависает при выполнении команд.

MandarinKa02 микрооффтоп xD :

+ открыть спойлер

Понимаю, возможно будет чутка смешно... от нечего делать в свободное время пилю себе коллекцию обоев xD . (добавляю в закладки/теперь уже просто в файл строками).
Сейчас дошел до того, что прохожусь по Favourites deviantart'a: взял н-ное количество картинок (с которых начал), глянул в каких favourites они находятся(добавил в закладки). Потом я пошел в разнос и сейчас у меня в закладках куча (реально большая) favourites, из которых я скриптом ahk вытаскиваю ссылки на галлереи пользователей и закидываю эти ссылки в файл xD .
Скорее сейчас этим занимаюсь ибо интересно допиливать напильником скрипт, как то втянулся xD .

Хром запущен с ярлыка в режим отладки, вот как выглядит объект в ярлыке:

"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" " --remote-debugging-port=9222"

Собственно, код:

+ открыть спойлер

#Include Chrome.ahk
Gogogo = 1
Added = 0

^F1::
{
PageInst := Chrome.GetPage(1)
	;ToolTip, F
	Sleep 100
	A := Chrome.GetPageList()
	Sleep 200
	;ToolTip, G
	for vKey, oPage in A
	{
		vUrl := oPage.url
		bmCheck := InStr(vUrl, "https://www.deviantart.com",,, 1)
		if (bmCheck = 1)
		{
			id := oPage.id
			;PageInst.Call("Target.activateTarget", {targetId: id})
			Fl = 1
			Break
		}
	}
	Try
		PageInst.Disconnect()
	;ToolTip, H
	Sleep 100
	if (Fl = 0)
	{
		Sleep 100
		SoundPlay, da/finish.wav, Wait
		ToolTip, %Added%
		Return
	}

	Try
		PageInst := Chrome.GetPageBy("id", id)

	Catch, e
	{
		A := e.Message
		MsgBox, %A%
		Return
	}
	;ToolTip, G

	Sleep 100
	While (Gogogo = 1)
	{
		MouseGetPos, A, B
		MouseMove, A+10, B+10
		Sleep 200
		MouseMove, A, B
		Sleep 50 ;Дергаем мышкой чтобы комп не заснул и монитор не погас.
		Try
			numEl := PageInst.Evaluate("document.getElementsByClassName('torpedo-thumb-link').length;").Value
		Catch e
		{
			A := e.Message
			Try
				PageInst.Disconnect()
			Sleep 1000
			Gosub, ^F1
			Return
		}
		Sleep 100

		Loop %numEl%
		{
			if (nume <> 0)
			{
				Tooltip, %curP% / %alP% - %A_Index% / %numEl% / %Added%
			} Else {
				Tooltip, Last - %A_Index% / %numEl% / %Added%
			}
			Sleep 50
			lnk := "document.getElementsByClassName('torpedo-thumb-link')[" . A_Index - 1 . "].href;"
			Try
				El := PageInst.Evaluate(lnk).Value
			Catch e
			{
				A := e.Message
				Sleep 100
				Try
					PageInst.Disconnect()
				Sleep 1000
				Gosub, ^F1
				Return
			}
			Sleep 50
			NewStr := SubStr(El, 1 , InStr(El, "/",,, 4))
			NewStr2 = %NewStr%gallery/
			MyFile = da\daList.txt
			FileRead, filetext, %MyFile%
			res := RegExMatch(filetext, "m`a)^\Q" . NewStr2 . "\E$")
			If (res = 0)
			{
				FileAppend, % (filetext="" ? "" : "`n") . NewStr2, %MyFile%
				Sleep, 50
			}
		}
		Sleep 100
	    nxtIs := PageInst.Evaluate("document.getElementsByClassName('next')[0].children[0].className;").Value
	    if (nxtIs <> "disabled")
	    {
	    	Sleep 100
			nxt := PageInst.Evaluate("document.getElementsByClassName('next')[0].children[0].href;").Value
			Sleep 100
			PageInst.Call("Page.navigate", {"url": nxt})
			Sleep 100
			Try
				PageInst.WaitForLoad()
			Catch, e
			{
				A:=e.Message
				Sleep 5000
			}
		}
		Fl = 0
		if (nxtIs = "disabled")
    	{
    		ToolTip A
    		Sleep 3000
    		Try
    			PageInst.Call("Target.closeTarget", {targetId: id}, "False")
    		Catch, e
    		{
    			A := e.Message
    			MsgBox, %A%
    			Return
    		}
    		;A
			Sleep 3000
    		ToolTip, B
			;Try
			;	PageInst.Disconnect()
    		Sleep 1000
    		;ToolTip, C
			if (Gogogo = 0)
			{
				SoundPlay, da/finish.wav, Wait
				Reload
				Return
			}
			;ToolTip, D
			Gosub, ^F1
			Return
    	}
		If (Gogogo = 0)
		{
			Sleep 100
			Menu, Tray, Icon, da/da_faviconFav.ico
			Sleep 500
			Gogogo = 1

			SoundPlay, da/finish.wav, Wait
			Reload
			Return
		}
	}
	

Return
}

PS Gogogo общая переменная, там дальше еще есть ^f2 которая делает его =0.
PPS сейчас смотрю, и явственно вижу, что код стоило бы хорошенько так почистить от следов предыдущих версий Чем я завтра и займусь.
PPPS я уже слегка модифицировал chrome.ahk, в моей версии:

Call(DomainAndMethod, Params:="", WaitForResponse:=True)
		{
			if !this.Connected
				throw Exception("Not connected to tab")
			
			; Use a temporary variable for ID in case more calls are made
			; before we receive a response.
			ID := this.ID += 1
			
			; Wait for the response
			this.responses[ID] := False
			
			this.ws.Send(Chrome.Jxon_Dump({"id": ID
			, "params": Params ? Params : {}
			, "method": DomainAndMethod}))
			
			if !WaitForResponse
				return

			FlipFlapper := 0
			while !this.responses[ID]
			{
				FlipFlapper += 1
				Sleep, 50
				If (FlipFlapper > 400)
				{
					throw Exception("CaptainResponses")
					return
				}
			}
			
			; Get the response, check if it's an error
			response := this.responses.Delete(ID)
			if (response.error)
				throw Exception("Chrome indicated error in response",, Chrome.Jxon_Dump(response.error))
			
			return response.result
		}
		
		/*
			Run some JavaScript on the page. For example:
			
			PageInst.Evaluate("alert(""I can't believe it's not IE!"");")
			PageInst.Evaluate("document.getElementsByTagName('button')[0].click();")
		*/
		Evaluate(JS)
		{
			Try
				response := this.Call("Runtime.evaluate",
				( LTrim Join
				{
					"expression": JS,
					"objectGroup": "console",
					"includeCommandLineAPI": Chrome.Jxon_True(),
					"silent": Chrome.Jxon_False(),
					"returnByValue": Chrome.Jxon_False(),
					"userGesture": Chrome.Jxon_True(),
					"awaitPromise": Chrome.Jxon_False()
				}
				))
			Catch e
			{
				throw Exception(e.Message)
				Return
			}
			
			if (response.exceptionDetails)
				throw Exception(response.result.description,, Chrome.Jxon_Dump(response.exceptionDetails))
			
			return response.result
		}
		
		/*
			Waits for the page's readyState to match the DesiredState.
			
			DesiredState - The state to wait for the page's ReadyState to match
			Interval     - How often it should check whether the state matches
		*/
		WaitForLoad(DesiredState:="complete", Interval:=100)
		{
			FlipFlapper := 0
			while this.Evaluate("document.readyState").value != DesiredState
			{
				FlipFlapper += 1
				Sleep, Interval
				If (FlipFlapper > 400)
				{
					throw Exception("CaptainWaitForLoad")
					return
				}
			}
		}

PS Ниже прилепил архив с нужными файлами. Источником работы являются любые папки Favourites с девиантарта:

+ открыть спойлер

чтобы без рекламы - рандом с главной страницы: https://www.deviantart.com/nelwynnphoen … 21661/wlop
https://www.deviantart.com/lizard2002/f … ollections
https://www.deviantart.com/illusion-e/f … -s-Kingdom но не факт, что именно на них проявится, т.к. я потом возвращаю только что закрытую вкладку, прожимаю кнопку и все срабатывает...


Upd: Сильно переделал скрипт, как писал выше, пока вроде работает без нареканий.

Post's attachments

vaas.7z 192.04 kb, 5 downloads since 2018-12-04 

You don't have the permssions to download the attachments of this post.

10

Re: AHK: chrome.ahk внезапно зависает при выполнении команд.

Сам по себе скрипт chrome.ahk не стабильный. Та же функция Call().

Call(DomainAndMethod, Params:="", WaitForResponse:=True)
{
	...
	this.responses[ID] := False
	while !this.responses[ID] ;А если браузер решит оборвать соединение? в таком случае переменная this.Connected будет false, но цикл этого не обработает
		Sleep, 50
	...
}

При отправке данных в браузер(в алгоритме A-B). Происходит следующее:

A
event Message
event Message
event Message
event Error
event Close
B

Всё как бы работает, но пугает тот момент, что браузер отправляет сигнал об ошибке.(на уровне сокетов)

А вот, когда скрипт стопорится на том цикле, что мы выше обсуждали. То лог выглядит также, но без события Close.
Или скрипт не обрабатывает(упустил его или еще чет, многопоточности не хватает:) ) или же сам ActiveX, что более вероятно.
У меня при таком раскладе в некоторых случаях сверху еще и ошибка вылазит о проблеме с websocket'ами.
Что-то вроде такого:
https://artkiev.com/all/b19/javascript-hide-error_r7mmzs3a6h8a.jpg


Значит, решение предлагаю следующее:
находим такую функцию

/*
	Internal function triggered when the script receives a message on
	the WebSocket connected to the page.
*/
Event(EventName, Event)

И меняем в ней такое условие:

else if (EventName == "Error")
{
	this.ws.close()
	throw Exception("Websocket Error!")
}

У меня вроде как, да заработало.

+ offtop

Да и вообще, метод общения с браузером косячный. Не думаю, что было бы правильно использовать ActiveX для таких целей.
Ведь помимо websocket'ов, выделяется память для целого браузера. А там и Flash'и и пр.(поправьте, если не прав)
Было бы лучше, если бы автор написал websocket с нуля.

11

Re: AHK: chrome.ahk внезапно зависает при выполнении команд.

1) Sleep 50 в коде я уже поправил, там поставил счетчик, который считает ~20 секунд и кидает ошибку.
2) попробовал сделать, но я сам по себе вебсокет еррор вроде не ловил еще