|
Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Скриптовые языки администрирования Windows » VBS/WSH/JS - [решено] Парсинг html-страницы |
|
|
VBS/WSH/JS - [решено] Парсинг html-страницы
|
Ветеран Сообщения: 1639 |
Профиль | Отправить PM | Цитировать
Приветствую!
Возникла необходимость отслеживать на сайте фифы доступность билетов. Есть список интересующих матчей, которые нужно мониторить. Алгоритм придумал следующий: 1. Формирую массив MatchName, состоящий из названий необходимых для отслеживания матчей: - Матч 01 - Россия : Саудовская Аравия - Москва «Лужники» - Матч 07 - Аргентина : Исландия - Москва «Спартак» - Матч 11 - Германия : Мексика - Москва «Лужники» 2. Поочередно получаю в NodeList дивы с классом "header" (див внутри первого столбец таблицы) и заглядываю внутрь каждого (через innerText), сверяя название текущего матча с первым элементом массива MatchName: <div class="header" ng-bind="product.productName">Матч 01 - Россия : Саудовская Аравия - Москва «Лужники»</div> Ключевое - это определить класс "class="categoryBox zeroAvailability" - т.е. если этот класс НЕ "zeroAvailability", то далее кидается алерт. 4. Аналогично пройтись по остальным элементам массива MatchName. Ну в общем, я начал: Option Explicit Const READYSTATE_COMPLETE = 4 Const TimeOut = 10000 Const link = "https://tickets.fifa.com/Services/ADService.html?lang=ru" Dim objNodeList, i, j Dim MatchName(2) ' массив из искомых названий матчей MatchName(0) = "Матч 01 - Россия : Саудовская Аравия - Москва «Лужники»" MatchName(1) = "Матч 07 - Аргентина : Исландия - Москва «Спартак»" MatchName(2) = "Матч 11 - Германия : Мексика - Москва «Лужники»" With WScript.CreateObject("InternetExplorer.Application") .Visible = False .Navigate(link) Do WScript.Sleep TimeOut ' ожидаем загрузку страницы Loop Until Not .Busy And .ReadyState = READYSTATE_COMPLETE objNodeList = .document.getElementsByClassName("header") ' получаем в NodeList все элементы с указанным классом For i = 0 to 2 Step 1 For j = 0 to objNodeList.length Step 1 ' !!! Ошибка: "Требуется объект '[object HTMLCollection]' ' ... Next Next Set objNodeList = Nothing .Quit End With WScript.Quit 0 Вопросы следующие: 1. Понять не могу в чем ошибка. objNodeList - это NodeList, который представляет собой массив из Element'ов. Почему я не могу получить длину этого массива? 2. Вопрос касательно общего алгоритма... Может быть как-то задачу попроще можно решить или логика моя пойдет? 3. Если возможно, то подскажите, пожалуйста, каким образом можно перемещаться по соседним div'ам (из пункта 3. алгоритма)? Спасибо! |
|
Отправлено: 16:55, 07-05-2018 |
Ветеран Сообщения: 27449
|
Профиль | Отправить PM | Цитировать Цитата The_Immortal:
Цитата The_Immortal:
Цитата The_Immortal:
|
|||
Отправлено: 17:12, 07-05-2018 | #2 |
Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети. Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля. |
Ветеран Сообщения: 1639
|
Профиль | Отправить PM | Цитировать Iska, опять я туплю на таком элементарном... Спасибо!
А Вы не могли бы подсказать каким образом можно сразу по имени класса обратиться к дочерним элементам коллекции этой? К примеру, имеется такая html-структура: +
Но возникает ошибка на второй строке... |
Последний раз редактировалось The_Immortal, 07-05-2018 в 19:06. Отправлено: 18:50, 07-05-2018 | #3 |
Ветеран Сообщения: 27449
|
Профиль | Отправить PM | Цитировать Цитата The_Immortal:
Цитата The_Immortal:
Цитата The_Immortal:
|
|||
Отправлено: 19:10, 07-05-2018 | #4 |
Ветеран Сообщения: 1639
|
Профиль | Отправить PM | Цитировать Iska,
Цитата Iska:
Нашел вот такую тему - там обращаются к ребенку через childNodes: У меня же ругается почему-то... Нету такого метода-свойства =/ Или ключевое в getElementById? Т.е. у getElementById имеется свойство childNodes, а у getElementsByClassName вдруг такого свойства не оказалось? А где можно найти список всех их методов и свойств? А на FirstChild, кстати, также ругается. |
||
Последний раз редактировалось The_Immortal, 07-05-2018 в 20:13. Отправлено: 19:14, 07-05-2018 | #5 |
Ветеран Сообщения: 1639
|
Профиль | Отправить PM | Цитировать Iska, получается, что, используя VBS, обратиться к детям вообще никак нельзя через getElementsByClassName ? Тогда какой от него вообще прок, если нельзя заглянуть внутрь объекта, который возвращает данный метод??
Блин, ну и каким языком распарсить это? Если взять тот же PS, то там та же песня наверняка вылезет. P.S. Неужели никто никогда не парсил HTML через VBS? :D |
Последний раз редактировалось The_Immortal, 08-05-2018 в 21:50. Отправлено: 21:43, 08-05-2018 | #6 |
Ветеран Сообщения: 27449
|
Профиль | Отправить PM | Цитировать The_Immortal, всё можно, язык тут вовсе не при чём, надо просто документацию копать. Проблема в том, что практически вся вменяемая документация, ранее бывшая на сайтах Microsoft, почила в бозе, а та, что появилась — выглядит как сущее издевательство. У меня, конечно, есть и отдельные документации, но их надо либо искать по сусекам, либо освобождать место для разворачивания локальной справки MSDN. Так что проще взять и тупо воспользоваться каким-либо браузером объектов на соответствующей библиотеке типов.
Цитата The_Immortal:
Можно даже далеко не ходить, а просто двигаться маленькими шажками: WScript.Echo 1, TypeName(.document.getElementsByClassName("row rowBox rowBoxEven")) WScript.Echo 2, .document.getElementsByClassName("row rowBox rowBoxEven").length WScript.Echo 3, TypeName(.document.getElementsByClassName("row rowBox rowBoxEven").item(0)) WScript.Echo 4, .document.getElementsByClassName("row rowBox rowBoxEven").item(0).hasChildNodes() WScript.Echo 5, TypeName(.document.getElementsByClassName("row rowBox rowBoxEven").item(0).childNodes) WScript.Echo 6, .document.getElementsByClassName("row rowBox rowBoxEven").item(0).childNodes.length WScript.Echo 7, TypeName(.document.getElementsByClassName("row rowBox rowBoxEven").item(0).childNodes.item(0)) WScript.Echo 8, .document.getElementsByClassName("row rowBox rowBoxEven").item(0).childNodes.item(0).nodeName WScript.Echo 9, TypeName(.document.getElementsByClassName("row rowBox rowBoxEven").item(0).childNodes.item(1)) WScript.Echo 10, .document.getElementsByClassName("row rowBox rowBoxEven").item(0).childNodes.item(1).nodeName Цитата:
Хорошо также смотреть внутрь результирующего сгенерированного html посредством Инспектора/Проводника DOM (F12), разумеется, под IE, и под конкретно той версией IE, под которой будет работать скрипт (у меня Проводник DOM не работает, отваливается). Возвращаясь к этому: Цитата The_Immortal:
Цитата The_Immortal:
|
||||
Отправлено: 00:51, 09-05-2018 | #7 |
Ветеран Сообщения: 1639
|
Профиль | Отправить PM | Цитировать Iska,
Цитата Iska:
И, кстати, ведь абсолютно эквивалентно Правильно понимаю? Да и child'ы мне похоже вообще не нужны: Цитата Iska:
UPD: что-то я зашел в тупик... Option Explicit Const READYSTATE_COMPLETE = 4 Const TimeOut = 10000 Const link = "https://tickets.fifa.com/Services/ADService.html?lang=ru" Dim MatchList,CurMatch, i, Match CurMatch = 0 Dim MatchName(2) MatchName(0) = "Матч 01 - Россия : Саудовская Аравия - Москва «Лужники»" MatchName(1) = "Матч 07 - Аргентина : Исландия - Москва «Спартак»" MatchName(2) = "Матч 11 - Германия : Мексика - Москва «Лужники»" With WScript.CreateObject("InternetExplorer.Application") .Visible = False .Navigate link Do WScript.Sleep TimeOut Loop Until Not .Busy And .ReadyState = READYSTATE_COMPLETE Set MatchList = .document.getElementsByClassName("header") ' получаем названия всех матчей в один список For i = 0 to 2 Step 1 ' перебираем массив MatchName, где содержатся названия искомых матчей For each Match in MatchList ' берём каждую ноду коллекции (списка) матчей If (MatchName(i) = Match.innerText) Then ' если матч совпал, то ... 'For i = 0 to 3 Step 1 ' проходимся по 4-ым "pull-left" 'WScript.Echo .document.getElementsByClassName(Match.parentNode.parentNode.parentNode.className)(???).getElementsByClassName("pull-left")(i).childNodes(0).className 'Next 'WScript.Echo Match.NextSibling.NextSibling.NextSibling.className End If CurMatch = CurMatch + 1 ' фиксируем какой по счету был матч Next Next Set MatchList = Nothing .Quit End With WScript.Quit 0 Сначала я подумал, что проблему с прыжком на нужное можно решить так: For i = 0 to 3 Step 1 ' проходимся по 4-ым "pull-left" WScript.Echo .document.getElementsByClassName(Match.parentNode.parentNode.parentNode.className)(???).getElementsByClassName("pull-left")(i).childNodes(0).className Next Класса родительских два и они разные: <div class="row rowBox rowBoxOdd" ...> ... </div> <div class="row rowBox rowBoxEven" ...> ... </div> Ну и второй (более, наверное, правильный) подход - позицинироваться относительно текущего элемента: Но сиё вообще не робит Продублирую HTML-код (упрощенный): +
<div class="row rowBox rowBoxEven"> <div class="col-sm-3 col-xs-12"> <div class="row"> <div class="header">Матч 01 - Россия : Саудовская Аравия - Москва «Лужники»</div> </div> <div class="row"> <div class="col-lg-3 col-md-3 col-sm-3 col-xs-3"> <div>Матч 1</div> </div> <div class="col-lg-3 col-md-3 col-sm-3 col-xs-3 ng-hide"> <div>Матчи 1</div> </div> <div class="col-lg-3 col-md-3 col-sm-3 col-xs-3"> <div> 14 ИЮН 18:00</div> </div> </div> </div> <div class="col-sm-9 col-xs-12"> <div class="pull-left"> <div class="categoryBox zeroAvailability">CAT 1</div> </div> <div class="pull-left"> <div class="categoryBox zeroAvailability">CAT 2</div> </div> <div class="pull-left"> <div class="categoryBox zeroAvailability">CAT 3</div> </div> <div class="pull-left"> <div class="categoryBox zeroAvailability">CAT 4</div> </div> </div> </div> Я нахожусь вот тут: А мне надо вот сюда: <div class="pull-left"> <div class="categoryBox zeroAvailability">CAT 1</div> </div> <div class="pull-left"> <div class="categoryBox zeroAvailability">CAT 2</div> </div> <div class="pull-left"> <div class="categoryBox zeroAvailability">CAT 3</div> </div> <div class="pull-left"> <div class="categoryBox zeroAvailability">CAT 4</div> </div> |
||
Последний раз редактировалось The_Immortal, 09-05-2018 в 05:15. Отправлено: 01:48, 09-05-2018 | #8 |
Старожил Сообщения: 250
|
Профиль | Отправить PM | Цитировать попробуйте то же только в повершел -
$s = new-object -com 'internetexplorer.application' $s.visible = $true $target_url = 'https://tickets.ifa.com/Services/ADService.html?lang=ru' $s.navigate2($target_url) $s.ReadyState # 4 $s.Busy # False # $s.document | get-member # ... a lot of output ... $doc = $s.document # $doc # $m1 = $doc.documentElement.getElementsByClassName('header') <# $m1 | get-member TypeName: System.__ComObject#{3050f50c-98b5-11cf-bb82-00aa00bdce0b} Name MemberType Definition ---- ---------- ---------- addBehavior Method int addBehavior (string, Variant) addFilter Method void addFilter (IUnknown) ... сокращено ... #> $e1 = $m1[1] $e1.nodeName # DIV $e1.textContent # Матч 02 - Египет : Уругвай - Екатеринбург $e2 = $e1.parentNode $e2.innerHTML # <div class="header" ng-bind="product.productName">Матч 02 -Египет : Уругвай - Екатеринбург</div> $e3 = $e2.parentNode $e4 = $e3.NextSibling.NextSibling $e4.textContent # CAT 1 # CAT 2 # CAT 3 # CAT 4 $m2 = $e4.getElementsByClassName('categoryBox') $m2[1] $m2[1].innerHTML # CAT 2 $m2[1].outerHTML # <div class="categoryBox zeroAvailability" ng-bind="cat.categoryName" ng-class="cat.availabilityColor">CAT 2</div> $m2[1].getAttribute('ng-class') # cat.availabilityColor # для поиска "Низкая доступность": # $m2 | where-object { $_.getAttribute('ng-class') -match '.*Zero.*' } |
Последний раз редактировалось Serguei Kouzmine, 09-05-2018 в 07:33. Отправлено: 06:57, 09-05-2018 | #9 |
Ветеран Сообщения: 1639
|
Профиль | Отправить PM | Цитировать Serguei Kouzmine, большое спасибо за труд, но я там почти ничего не понимаю Я вообще на финишной прямой и осталось только разобраться каким образом получить className перемещаясь через NextSibling...
Локализую проблему. HTML-код ещё раз: +
<div class="row rowBox rowBoxEven"> <div class="col-sm-3 col-xs-12"> <div class="row"> <div class="header">Матч 01 - Россия : Саудовская Аравия - Москва «Лужники»</div> </div> <div class="row"> <div class="col-lg-3 col-md-3 col-sm-3 col-xs-3"> <div>Матч 1</div> </div> <div class="col-lg-3 col-md-3 col-sm-3 col-xs-3 ng-hide"> <div>Матчи 1</div> </div> <div class="col-lg-3 col-md-3 col-sm-3 col-xs-3"> <div> 14 ИЮН 18:00</div> </div> </div> </div> <div class="col-sm-9 col-xs-12"> <div class="pull-left"> <div class="categoryBox zeroAvailability">CAT 1</div> </div> <div class="pull-left"> <div class="categoryBox zeroAvailability">CAT 2</div> </div> <div class="pull-left"> <div class="categoryBox zeroAvailability">CAT 3</div> </div> <div class="pull-left"> <div class="categoryBox zeroAvailability">CAT 4</div> </div> </div> </div> Для теста выполняю вот такое: , ожидая перейти просто на следующий div (<div class="row">) и извлечь имя класса этого div'а, но получаю ошибку о том, что объект Match.NextSibling не поддерживает свойство NextSibling.className. Тогда я пробую так: , на что получаю сначала вывод [object Text], а после сразу же ошибку: Цитата:
|
|
Последний раз редактировалось The_Immortal, 10-05-2018 в 03:03. Отправлено: 16:48, 09-05-2018 | #10 |
|
Участник сейчас на форуме | Участник вне форума | Автор темы | Сообщение прикреплено |
| |||||
Название темы | Автор | Информация о форуме | Ответов | Последнее сообщение | |
PowerShell - Парсинг HTML, Parser HTML | dosperados | Скриптовые языки администрирования Windows | 6 | 15-04-2016 08:46 | |
CMD/BAT - Парсинг HTML | Smasher | Скриптовые языки администрирования Windows | 14 | 25-09-2012 20:45 | |
[решено] Парсинг страницы с редиректом (PHP) | Luzuk | Вебмастеру | 3 | 16-03-2012 18:06 | |
Отображение HTML страницы в окне | assch | AutoIt | 3 | 10-08-2009 14:58 | |
Медиа - автозапуск html страницы с CD | WChek | Хочу все знать | 38 | 09-06-2008 15:23 |
|