1 (изменено: The_Immortal, 2018-05-07 20:06:15)

Тема: VBS: парсинг html-страницы

Приветствую!

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

Алгоритм придумал следующий:

1. Формирую массив MatchName, состоящий из названий необходимых для отслеживания матчей:
- Матч 01 - Россия : Саудовская Аравия - Москва «Лужники»
- Матч 07 - Аргентина : Исландия - Москва «Спартак»
- Матч 11 - Германия : Мексика - Москва «Лужники»

2. Поочередно получаю в NodeList дивы с классом "header" (див внутри первого столбец таблицы) и заглядываю внутрь каждого (через innerText), сверяя название текущего матча с первым элементом массива MatchName:

<div class="header" ng-bind="product.productName">Матч 01 - Россия : Саудовская Аравия - Москва «Лужники»</div>

3. Если название совпало, то каким-то образом перехожу к соседнему диву "col-sm-9 col-xs-12" (второй таблицы) и также каким-то образом изымаю имя класса внутреннго дива для всех 4 квадратов.

Ключевое - это определить класс "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
	
	Set objNodeList = .document.getElementsByClassName("header")	' получаем в NodeList все элементы с указанным классом

	For i = 0 to 2 Step 1
		For j = 0 to objNodeList.length Step 1	
			' ...
		Next		
			
	Next	

	Set objNodeList = Nothing
	
	.Quit
End With

WScript.Quit 0

Вопросы следующие:

1. Вопрос касательно общего алгоритма... Может быть как-то задачу попроще можно решить или логика моя пойдет?

2. Если возможно, то подскажите, пожалуйста, каким образом можно перемещаться по соседним div'ам (из пункта 3. алгоритма)?

Спасибо!




UPD: господа, обрисовываю проблему более узко. Не могли бы вы подсказать каким образом можно сразу по имени класса обратиться к дочерним элементам коллекции NodeList?

К примеру, имеется такая html-структура:

<div class="row rowBox rowBoxEven" ng-class="{'rowBoxOdd':$odd, 'rowBoxEven':$even}" ng-repeat="product in AD.filteredList track by product.productId">
            <div class="col-sm-3 col-xs-12">
                <div class="row">
                    <div class="header" ng-bind="product.productName">Матч 01 - Россия : Саудовская Аравия - Москва «Лужники»</div>
                </div>
                <div class="row">
                    <div class="col-lg-3 col-md-3 col-sm-3 col-xs-3" ng-show="product.productTypeCode==AD.productTypeEnum.IMT">
                        <div>Матч 1</div>
                    </div>
                    <div class="col-lg-3 col-md-3 col-sm-3 col-xs-3 ng-hide" ng-show="product.productTypeCode==AD.productTypeEnum.VST">
                        <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" ng-show="cat.availability!==-1" ng-repeat="cat in product.categories track by cat.categoryId" ng-if="(AD.showSpecialTypes &amp;&amp; cat.accessibility) || !cat.accessibility">
                    <div class="categoryBox zeroAvailability" ng-class="cat.availabilityColor" ng-bind="cat.categoryName">CAT 1</div>
                </div><!----><!----><!----><div class="pull-left" ng-show="cat.availability!==-1" ng-repeat="cat in product.categories track by cat.categoryId" ng-if="(AD.showSpecialTypes &amp;&amp; cat.accessibility) || !cat.accessibility">
                    <div class="categoryBox zeroAvailability" ng-class="cat.availabilityColor" ng-bind="cat.categoryName">CAT 2</div>
                </div><!----><!----><!----><div class="pull-left" ng-show="cat.availability!==-1" ng-repeat="cat in product.categories track by cat.categoryId" ng-if="(AD.showSpecialTypes &amp;&amp; cat.accessibility) || !cat.accessibility">
                    <div class="categoryBox zeroAvailability" ng-class="cat.availabilityColor" ng-bind="cat.categoryName">CAT 3</div>
                </div><!----><!----><!----><div class="pull-left" ng-show="cat.availability!==-1" ng-repeat="cat in product.categories track by cat.categoryId" ng-if="(AD.showSpecialTypes &amp;&amp; cat.accessibility) || !cat.accessibility">
                    <div class="categoryBox zeroAvailability" ng-class="cat.availabilityColor" ng-bind="cat.categoryName">CAT 4</div>
                </div><!----><!----><!----><!----><!----><!----><!----><!----><!----><!---->
            </div>
        </div>

Моя текущая задача обратится к внутренностям следующих div'ов:

  • div class="header";

  • div class="pull-left" (последовательно ко всем 4-ым).

Я понимаю, что плясать я должен от родителя. Т.е. обращаюсь к корневому элементу:

Set objNodeList = .document.getElementsByClassName("row rowBox rowBoxEven")

Далее я хочу сразу прыгнуть на div class="header": div class="row rowBox rowBoxEven" -> div class="col-sm-3 col-xs-12" -> div class="row" -> div class="header". Но вот не могу допендрить как это сделать... Пробовал так:

Set objNodeList = .document.getElementsByClassName("row rowBox rowBoxEven")
Set child = objNodeList.getElementsByClassName("header")

Но возникает ошибка на второй строке...

2

Re: VBS: парсинг html-страницы

document.getElementsByClassName("row rowBox rowBoxEven")[0].getElementsByClassName("header")[0].innertext

3 (изменено: The_Immortal, 2018-05-08 22:50:57)

Re: VBS: парсинг html-страницы

Malcev, не-а - такая строка не воспринимается. Квадратные скобки, как я понял, недопустимы.

P.S. Неужели никто никогда не парсил HTML через VBS?

4

Re: VBS: парсинг html-страницы

Должны восприниматься.
https://www.w3schools.com/jsref/met_ele … ssname.asp

5 (изменено: The_Immortal, 2018-05-08 22:57:28)

Re: VBS: парсинг html-страницы

Malcev, в случае с VBS конкретные ноды указываются в круглых скобках, а если указать круглые скобки, то:

The_Immortal пишет:

возникает ошибка

6

Re: VBS: парсинг html-страницы

Приведите свой код, в котором возникает ошибка.

7 (изменено: The_Immortal, 2018-05-08 23:14:15)

Re: VBS: парсинг html-страницы

Malcev, да давайте далеко ходить не будем и слегка отпарсим главную страницу форума:

Option Explicit

Const READYSTATE_COMPLETE = 4 
Const TimeOut = 10000
Const link = "http://forum.script-coding.com"

With WScript.CreateObject("InternetExplorer.Application")
	.Visible = False
	.Navigate link
	
	Do
		WScript.Sleep TimeOut	' ожидаем загрузку страницы
	Loop Until Not .Busy And .ReadyState = READYSTATE_COMPLETE
	
	WScript.Echo .document.getElementsByClassName("item-subject")(0).innerText
	'WScript.Echo .document.getElementsByClassName("item-subject")[0].innerText

	.Quit
End With

WScript.Quit 0

Вывелся текст? Ну а теперь уберите комментарий и попробуйте запустить повторно:

https://content.screencast.com/users/The_Immortal/folders/Snagit/media/32d8bf71-e9c7-4f57-9af5-c0aba0d1e21e/05.08.2018-22.13.png

8

Re: VBS: парсинг html-страницы

Значит замените квадратные на круглые.
Так у меня с вашей ссылкой работает.

WScript.Echo .document.getElementsByClassName("row rowBox rowBoxEven")(0).getElementsByClassName("header")(0).innertext

9

Re: VBS: парсинг html-страницы

Malcev, хм, действительно, так всё работает. Спасибо! Пошел дальше мутить...

10

Re: VBS: парсинг html-страницы

В Chrome Developer Tools на вкладке Network видно, что страница перед показом результатов получает AJAX'ом все данные в JSON формате вот по этому URL: https://tickets.fifa.com/API/WCachedL1/ … encyId=RUB. Решил посмотреть, насколько пригоден ответ для парсинга. В массиве Data.Availability приведено наличие билетов для каждого матча и каждой категории зрителя. Каждый элемент масива содержит объект с 3 свойствами:

		{
			"p": "IMT01",
			"c": 37,
			"a": 0
		}

p - это ProductId, его можно найти в другом массиве выше Data.PRODUCTIMT,
c - это категория зрителя, их также можно найти в массиве Data.CATEGORIES,
a - по всей видимости, количество доступных билетов.
Сначала я был удивлен, когда в ответе нашел фрагмент "a":1, но все стало понятно, когда нашел категорию "c":18 - это объект с "CategoryId":18 в массиве Data.CATEGORIES.
Нас же интересуют ненулевые "a" для "c" с 14 по 16. Можно распарсить даже простой регуляркой.

Щт Уккщк Куыгьу Туче