Что нового

HtmlSelector - Обработка Html используя XPath и CSS селекторы

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
AutoIt: 3.3.6.1 - 3.3.12.0 (x86)
Версия: 0.3

Категория: Строки, Данные, Интернет

Описание: Библиотека позволяет получить элементы Html используя XPath и CSS селекторы. Основано на HtmlAgilityPack и Htmlayout соответственно.

Требования:
* Для XPath селектора требуется .Net Framework версии 2.0.x или 4.0.x.
* Тестировалось под Win 7 x64/x86, Win XP x86.
* На виртуальной машине Win XP Pro x86, почему то XPath селектор не загружается.

Примечания:
* Синтаксис использования XPath
* Поддерживаемые CSS селекторы

Пример:
Код:
#include <GUIConstantsEx.au3>
#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>
#include <GUIListView.au3>
#include <HtmlSelector.au3>

Global $sHTML = '', $sURL = '', $aResult[1][5] = [[0]]
Global $fLoadHtml_XPath = True, $fLoadHtml_CSS = True

;Init all (XPath and CSS) selectors
Global $iHSEL_INIT = _HTMLSelector_Init($HSEL_INIT_ALLSEL)
Global $iHSEL_ERROR = @error

If Not $iHSEL_INIT And $iHSEL_ERROR = 3 Then
	MsgBox(16, 'Error', 'Unable to initialize HtmlSelector' & @CRLF & @CRLF & 'OK ==> EXIT')
	Exit
EndIf

$hGUI = GUICreate('HTMLSelector Example', 700, 600)

$iFirstCtrlID = GUICtrlCreateDummy() + 1

GUICtrlCreateLabel('Select from Html:', 20, 20)
$iSelect_Input = GUICtrlCreateInput('', 20, 40, 600, 20, BitOR($GUI_SS_DEFAULT_INPUT, $ES_NOHIDESEL))
GUICtrlSendMsg($iSelect_Input, $EM_SETCUEBANNER, 0, 'Example: //div[@id="mydiv"]')
$iSelect_Bttn = GUICtrlCreateButton('Select', 630, 40, 50, 20, $BS_DEFPUSHBUTTON)
GUICtrlSetState(-1, $GUI_FOCUS)

$iXPath_Radio = 0
$iCSS_Radio = 0

Switch $iHSEL_ERROR
	Case 0
		$iXPath_Radio = GUICtrlCreateRadio('XPath Selector', 30, 70)
		$iCSS_Radio = GUICtrlCreateRadio('CSS Selector', 150, 70)
		GUICtrlSetState($iXPath_Radio, $GUI_CHECKED)
	Case 1
		$iCSS_Radio = GUICtrlCreateRadio('CSS Selector', 30, 70)
		GUICtrlSetState($iCSS_Radio, $GUI_CHECKED)
	Case 2
		$iXPath_Radio = GUICtrlCreateRadio('XPath Selector', 30, 70)
		GUICtrlSetState($iXPath_Radio, $GUI_CHECKED)
EndSwitch

GUICtrlCreateLabel('Result:', 20, 100)
$iResult_LV = GUICtrlCreateListView('#|OuterHtml|InnerHtml|InnerText', 20, 120, 660, 200, _
	BitOR($LVS_SHOWSELALWAYS, $LVS_SINGLESEL, $LVS_NOSORTHEADER), BitOR($LVS_EX_GRIDLINES, $LVS_EX_FULLROWSELECT))

GUICtrlCreateLabel('Status:', 350, 100, 40, 20)
GUICtrlSetFont(-1, 9, 800)
$iStatus_Lbl = GUICtrlCreateLabel('', 400, 101, 280, 20)

$iGetAttribs_Bttn = GUICtrlCreateButton('Get Attributes', 600, 322, 80, 20)

GUICtrlCreateLabel('Html:', 20, 330)
$iHtml_Edit = GUICtrlCreateEdit('', 20, 350, 660, 210, BitOR($ES_WANTRETURN, $WS_VSCROLL, $ES_AUTOVSCROLL, $ES_NOHIDESEL, $ES_READONLY))
GUICtrlSetBkColor(-1, 0xFFFFFF)

$iLoadHtml_Bttn = GUICtrlCreateButton('Load html...', 20, 570, 80, 20)

$iLastCtrlID = GUICtrlCreateDummy() - 1

GUISetState(@SW_SHOW, $hGUI)

While 1
	$nMsg = GUIGetMsg()
	
	Switch $nMsg
		Case 0
			
		Case $GUI_EVENT_CLOSE
			GUIDelete($hGUI)
			Exit
		Case $iSelect_Bttn, $iXPath_Radio, $iCSS_Radio
			$sSelect = GUICtrlRead($iSelect_Input)
			$fIsXPath = (BitAND(GUICtrlRead($iXPath_Radio), $GUI_CHECKED) = $GUI_CHECKED)
			
			If $sHTML = '' Or $sSelect = '' Then
				ContinueLoop
			EndIf
			
			$fIsUTF8 = _Encoding_IsUTF8Format($sHTML)
			
			_StatusSet('Selecting...', 0x0000FF, 0)
			_CtrlsSetState($GUI_DISABLE)
			_GUICtrlListView_DeleteAllItems(GUICtrlGetHandle($iResult_LV))
			
			If $fIsXPath Then
				$aResult = _HtmlSelector_SelectByXPath($sHTML, $sSelect, -1, -1, $fLoadHtml_XPath)
				$fLoadHtml_XPath = False
			Else
				$aResult = _HtmlSelector_SelectByCSS($sHTML, $sSelect, -1, -1, $fLoadHtml_CSS)
				$fLoadHtml_CSS = False
			EndIf
			
			$iError = @error
			
			If $iError Then
				If $fIsXPath Then
					$iError = 'XPath.Sel.Err: ' & $iError
				Else
					$iError = 'CSS.Sel.Err: ' & $iError
				EndIf
				
				_StatusSet('Selection Error (' & $iError & ')', 0xFF0000)
				_CtrlsSetState($GUI_ENABLE)
				
				ContinueLoop
			EndIf
			
			For $i = 1 To $aResult[0][0]
				If $fIsUTF8 Or Not $fIsXPath Then
					$aResult[$i][$HSEL_RSLT_OUTERHTML] = BinaryToString(StringToBinary($aResult[$i][$HSEL_RSLT_OUTERHTML]), 4)
					$aResult[$i][$HSEL_RSLT_INNERHTML] = BinaryToString(StringToBinary($aResult[$i][$HSEL_RSLT_INNERHTML]), 4)
					$aResult[$i][$HSEL_RSLT_INNERTEXT] = BinaryToString(StringToBinary($aResult[$i][$HSEL_RSLT_INNERTEXT]), 4)
				EndIf
				
				$iIndex = _GUICtrlListView_InsertItem($iResult_LV, $i)
				_GUICtrlListView_AddSubItem($iResult_LV, $iIndex, $aResult[$i][$HSEL_RSLT_OUTERHTML], 1)
				_GUICtrlListView_AddSubItem($iResult_LV, $iIndex, $aResult[$i][$HSEL_RSLT_INNERHTML], 2)
				_GUICtrlListView_AddSubItem($iResult_LV, $iIndex, $aResult[$i][$HSEL_RSLT_INNERTEXT], 3)
			Next
			
			_GUICtrlListView_SetColumnWidth($iResult_LV, 0, -1)
			_GUICtrlListView_SetColumnWidth($iResult_LV, 1, 200)
			_GUICtrlListView_SetColumnWidth($iResult_LV, 2, 200)
			_GUICtrlListView_SetColumnWidth($iResult_LV, 3, 200)
			
			_StatusSet('Selected Items: ' & $aResult[0][0], 0x0000FF)
			_CtrlsSetState($GUI_ENABLE)
		Case $iGetAttribs_Bttn
			$aSelIndex = _GUICtrlListView_GetSelectedIndices($iResult_LV, True)
			
			If @error Or $aSelIndex[0] = 0 Then
				_StatusSet('No selected elements', 0xFF0000)
				ContinueLoop
			EndIf
			
			$aAttribs = $aResult[$aSelIndex[1] + 1][$HSEL_RSLT_ATTRIBS]
			
			If Not IsArray($aAttribs) Or $aAttribs[0][0] = 0 Then
				_StatusSet('Attributes not found', 0xFF0000)
				ContinueLoop
			EndIf
			
			$sAttribs = ''
			$sType = $aResult[$aSelIndex[1] + 1][$HSEL_RSLT_TYPE]
			
			For $i = 1 To $aAttribs[0][0]
				If $sAttribs Then
					$sAttribs &= @CRLF
				EndIf
				
				$sAttribs &= $aAttribs[$i][$HSEL_RSLTATTRB_NAME] & '=' & $aAttribs[$i][$HSEL_RSLTATTRB_VALUE]
			Next
			
			MsgBox(64, 'Attributes for ' & $sType & ' #' & $aSelIndex[1] + 1, $sAttribs, 0, $hGUI)
		Case $iLoadHtml_Bttn
			$sURL = InputBox('Load from URL', 'Enter URL to load Html from:', $sURL, '', -1, -1, Default, Default, 0, $hGUI)
			
			If StringRegExp($sURL, '^(?:https?://)?[^/\.]+\.[^\.]+') Then
				_StatusSet('Loading from URL (' & $sURL & ')', 0x0000FF, 0)
				_CtrlsSetState($GUI_DISABLE)
				_GUICtrlListView_DeleteAllItems(GUICtrlGetHandle($iResult_LV))
				
				If Not StringRegExp($sURL, '^https?://') Then
					$sURL = 'http://' & $sURL
				EndIf
				
				$sRead = BinaryToString(InetRead($sURL))
				
				If $sRead <> $sHTML Then
					$sHTML = $sRead
					
					$fLoadHtml_XPath = True
					$fLoadHtml_CSS = True
					
					GUICtrlSetData($iHtml_Edit, StringReplace(StringStripCR($sRead), @LF, @CRLF, 0, 2))
				EndIf
				
				_StatusSet('', 0x0000FF, 0)
				_CtrlsSetState($GUI_ENABLE)
			EndIf
	EndSwitch
WEnd

Func _Encoding_IsUTF8Format($sText, $iCheckASCIICode = False)
	Local $iAsc, $iExt, $iLen = StringLen($sText), $bLess128 = True
	
	For $i = 1 To $iLen
		$iAsc = Asc(StringMid($sText, $i, 1))
		
		If $iCheckASCIICode And $iAsc > 128 Then
			$bLess128 = False
		EndIf
		
		If Not BitAND($iAsc, 0x80) Then
			ContinueLoop
		ElseIf Not BitXOR(BitAND($iAsc, 0xE0), 0xC0) Then
			$iExt = 1
		ElseIf Not (BitXOR(BitAND($iAsc, 0xF0), 0xE0)) Then
			$iExt = 2
		ElseIf Not BitXOR(BitAND($iAsc, 0xF8), 0xF0) Then
			$iExt = 3
		Else
			Return False
		EndIf
		
		If $i + $iExt > $iLen Then
			Return False
		EndIf
		
		For $j = $i + 1 To $i + $iExt
			$iAsc = Asc(StringMid($sText, $j, 1))
			
			If BitXOR(BitAND($iAsc, 0xC0), 0x80) Then
				Return False
			EndIf
		Next
		
		$i += $iExt
	Next
	
	If $iCheckASCIICode Then
		Return ($bLess128 = False)
	EndIf
	
	Return True
EndFunc   ;==>_Encoding_IsUTF8Format

Func _StatusSet($sData, $nColor, $iTimer = 5000)
	GUICtrlSetColor($iStatus_Lbl, $nColor)
	GUICtrlSetData($iStatus_Lbl, $sData)
	
	If $iTimer Then
		AdlibRegister('_StatusClear', 5000)
	Else
		AdlibUnRegister('_StatusClear')
	EndIf
EndFunc

Func _StatusClear()
	AdlibUnRegister('_StatusClear')
	GUICtrlSetData($iStatus_Lbl, '')
EndFunc

Func _CtrlsSetState($iState)
	For $iID = $iFirstCtrlID To $iLastCtrlID
		If $iID <> $iStatus_Lbl And $iID <> $iStatus_Lbl - 1 Then
			GUICtrlSetState($iID, $iState)
		EndIf
	Next
EndFunc

Файл: HtmlSelector.zip

Снимок:


История версий:
v0.3
* Изменены примеры.
+ Добавлена функция _HtmlSelector_GetAttribute для получения определённых атрибутов.
+ Добавлены пользовательские константы для использования в массиве результата от _HtmlSelector_SelectBy* и для функции _HtmlSelector_Init
($HSEL_INIT_XPATHSEL, $HSEL_INIT_CSSSEL, $HSEL_INIT_ALLSEL)
($HSEL_RSLT_TYPE, $HSEL_RSLT_ATTRIBS, $HSEL_RSLT_OUTERHTML, $HSEL_RSLT_INNERHTML, $HSEL_RSLT_INNERTEXT)
($HSEL_RSLTATTRB_NAME, $HSEL_RSLTATTRB_VALUE).
+ Добавлен параметр $iFlag в функцию _HTMLSelector_Init (для подробностей см. описание функции).
+ Добавлены дополнительные параметры $iIndex и $iRetRslt в _HtmlSelector_SelectBy* для получения указанных данных с массива результата (для подробностей см. примеры и описание функции).
+ Добавлен дополнительный параметр $fLoadHtml в функцию _HtmlSelector_SelectBy* для определения надобности загрузки html каждый раз (для подробностей см. примеры и описание функции).
- Убран параметр $fStripScripts из функции _HtmlSelector_SelectByCSS (может быть сделано пользователем).
* _HtmlSelector_SelectByCSS теперь возвращает InnerText в элементе [N][4].
* Оптимизация скорости и памяти.

v0.2
* Исправлена проблема создания множества скрытых окон (для каждого вызова _HtmlSelector_SelectByCSS создавалось новое окно).
* Изменён код возврата ошибки для _HtmlSelector_SelectByCSS.

v0.1
* Первая публичная версия

Источник: autoit-script.ru
Автор(ы): G.Sandler (CreatoR)
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
Кто то пробовал эту штуку?
Мне также интересно как оно работает на Win XP (не виртуалка).

Небольшое обновление:

v0.2
* Исправлена проблема создания множества скрытых окон (для каждого вызова _HtmlSelector_SelectByCSS создавалось новое окно).
* Изменён код возврата ошибки для _HtmlSelector_SelectByCSS.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,323
CreatoR [?]
Кто то пробовал эту штуку?
Я пробовал. Результат: Opera (12.17) (Win7x32) начала зависать и жрать 25% ЦП. Перезагрузка не помогла, пришлось отъезжать назад. Надо было предупредить, что UDF регистрирует доп. библиотеки и пишет чего-то в реестр.
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
madmasles [?]
Результат: Opera (12.17) (Win7x32) начала зависать и жрать 25% ЦП
Не совсем понятно при чём тут опера...

Перезагрузка не помогла, пришлось отъезжать назад
Перезагрузка чего, и куда отъезжать? :smile:

Надо было предупредить, что UDF регистрирует доп. библиотеки и пишет чего-то в реестр
По поводу библиотек написано в первом сообщений (тем более это явно если они присутствуют в архиве), а по поводу реестра, так там просто регистрация .Net библиотеки.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,323

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,323
CreatoR [?]
А что происходило при убийстве процесса оперы?
Opera закрывалась через окно типа "окно не отвечает, убить процесс?", а при запуске (и при повторном, и после перезагрузки) опять кушала одно ядро полностью. Причин этого я не понимаю.

PS
Opera использую несколько лет, раньше таких проблем не было никогда. :shok:


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

Может, какое-нибудь расширение конфликтует?
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
madmasles [?]
при запуске (и при повторном, и после перезагрузки) опять кушала одно ядро полностью
Возможно какая то страница это делает, с библиотекой связи не может быть, она не трогает браузер.

Может, какое-нибудь расширение конфликтует?
А какие установлены?

Я бы хотел воспроизвести у себя эту проблему.
 

gloss

Ленивое кодило
Сообщения
155
Репутация
5
Win7(x64) Никаких нагрузок при использовании не было.
Захватил все что подошло, включая пару лишних, названия классов похожи.
Все верно, классы перепутал :whistle:
В программе
iWp0CqA.png
В браузере
d0c1Bpk.png
Полезная штуковина. :ok:
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
madmasles [?]
AdBlock и IP to Geolocation.
Поставил эти расширения, не смог воспроизвести.
Я уверен что это просто совпадение, библиотека никак не взаимодействует с браузером, тем более с оперой.

gloss [?]
Захватил все что подошло, включая пару лишних, названия классов похожи
В class можно указать несколько классов через пробел, видимо находит первый и считает его валидным.
div[@class="is-faded"] тоже найдёт эти узлы.
Можно адрес сайта и строку поиска где это происходит?
 

gloss

Ленивое кодило
Сообщения
155
Репутация
5
Перепутал классы. Вместо giveaway__row-inner-wrap скопировал giveaway__row-outer-wrap
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,323
CreatoR [?]
Я уверен что это просто совпадение
Я на 100% не уверен, но очень хочется, чтобы так и было. :smile:


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

CreatoR,
Проверил работу UDF на WinXP SP3 32 (на ней установлена точно такая же Opera, как и на Win 7 32). Все примеры отрабатывают отлично, никаких проблем с Opera. После этого проверил на Win 7 32 - результат аналогичный. ИМХО, вышеуказанные проблемы с Opera связаны только с ней и никак не связаны с работой UDF, извините, надо было мне проверить все несколько раз, а потом уже писать о проблемах.

За UDF спасибо! :thanks:
 
Автор
CreatoR

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,673
Репутация
2,486
Обновление:

v0.3
* Изменены примеры.
+ Добавлена функция _HtmlSelector_GetAttribute для получения определённых атрибутов.
+ Добавлены пользовательские константы для использования в массиве результата от _HtmlSelector_SelectBy* и для функции _HtmlSelector_Init
($HSEL_INIT_XPATHSEL, $HSEL_INIT_CSSSEL, $HSEL_INIT_ALLSEL)
($HSEL_RSLT_TYPE, $HSEL_RSLT_ATTRIBS, $HSEL_RSLT_OUTERHTML, $HSEL_RSLT_INNERHTML, $HSEL_RSLT_INNERTEXT)
($HSEL_RSLTATTRB_NAME, $HSEL_RSLTATTRB_VALUE).
+ Добавлен параметр $iFlag в функцию _HTMLSelector_Init (для подробностей см. описание функции).
+ Добавлены дополнительные параметры $iIndex и $iRetRslt в _HtmlSelector_SelectBy* для получения указанных данных с массива результата (для подробностей см. примеры и описание функции).
+ Добавлен дополнительный параметр $fLoadHtml в функцию _HtmlSelector_SelectBy* для определения надобности загрузки html каждый раз (для подробностей см. примеры и описание функции).
- Убран параметр $fStripScripts из функции _HtmlSelector_SelectByCSS (может быть сделано пользователем).
* _HtmlSelector_SelectByCSS теперь возвращает InnerText в элементе [N][4].
* Оптимизация скорости и памяти.
 
Верх