Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   [решено] Парсинг html-страницы (http://forum.oszone.net/showthread.php?t=334713)

The_Immortal 07-05-2018 16:55 2812482

Парсинг 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
       
        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. алгоритма)?

Спасибо!

Iska 07-05-2018 17:12 2812487

Цитата:

Цитата The_Immortal
.Navigate(link) »

Скобки не нужны.

Цитата:

Цитата The_Immortal
objNodeList = .document.getElementsByClassName("header") »

Set objNodeList = …

Цитата:

Цитата The_Immortal
objNodeList - это NodeList, который представляет собой массив из Element'ов. »

Вообще-то, нет. Это не массив, это коллекция.

The_Immortal 07-05-2018 18:50 2812501

Iska, опять я туплю на таком элементарном... Спасибо!

А Вы не могли бы подсказать каким образом можно сразу по имени класса обратиться к дочерним элементам коллекции этой?

К примеру, имеется такая html-структура:
+
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")

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

Iska 07-05-2018 19:10 2812503

Цитата:

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

Правильно — у возвращаемого класса нет такого метода.

Цитата:

Цитата The_Immortal
Далее я хочу сразу прыгнуть на div class="header" »

Ну, а банально — .FirstChild.FirstChild.FirstChild, не? Ну, и, по-хорошему потом ещё проверить, что класс полученного элемента — header.

Цитата:

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

Опять же — .FirstChild.NextSibling.FirstChild.NextSibling.NextSibling. Далее ко второму, третьему и четвёртому двигаться посредством нужного количества .NextSibling от первого.

The_Immortal 07-05-2018 19:14 2812504

Iska,
Цитата:

Цитата Iska
Ну, а банально — .FirstChild.FirstChild.FirstChild, не? »

А если бы вложенность необходимого div'а была бы на 1000-ом уровне, например? :) Я к тому, что по идее должен быть способ как обратиться сразу к i-тому ребенку.

Нашел вот такую тему - там обращаются к ребенку через childNodes:
Код:

WScript.Echo .document.getElementsByClassName("row rowBox rowBoxEven").childNodes(3).className
У меня же ругается почему-то... Нету такого метода-свойства =/

Или ключевое в getElementById? Т.е. у getElementById имеется свойство childNodes, а у getElementsByClassName вдруг такого свойства не оказалось? А где можно найти список всех их методов и свойств?

А на FirstChild, кстати, также ругается.

The_Immortal 08-05-2018 21:43 2812675

Iska, получается, что, используя VBS, обратиться к детям вообще никак нельзя через getElementsByClassName ? Тогда какой от него вообще прок, если нельзя заглянуть внутрь объекта, который возвращает данный метод??

Блин, ну и каким языком распарсить это? Если взять тот же PS, то там та же песня наверняка вылезет.

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

Iska 09-05-2018 00:51 2812698

The_Immortal, всё можно, язык тут вовсе не при чём, надо просто документацию копать. Проблема в том, что практически вся вменяемая документация, ранее бывшая на сайтах Microsoft, почила в бозе, а та, что появилась — выглядит как сущее издевательство. У меня, конечно, есть и отдельные документации, но их надо либо искать по сусекам, либо освобождать место для разворачивания локальной справки MSDN. Так что проще взять и тупо воспользоваться каким-либо браузером объектов на соответствующей библиотеке типов.

Цитата:

Цитата The_Immortal
Код:

WScript.Echo .document.getElementsByClassName("row rowBox rowBoxEven").childNodes(3).className
У меня же ругается почему-то... Нету такого метода-свойства =/ »

Ругается потому, что класс HTMLElementCollection (.document.getElementsByClassName("row rowBox rowBoxEven")) действительно не содержит свойства .childNodes. Данный класс содержит методы .item, .namedItem, свойство .length и т.д. Вам нужно сначала выбрать из полученной коллекции отдельный элемент, используя указанные методы, проверить его тип, и вот этот отдельный элемент уже может содержать свойства .childNodes, .firstChild, .nextSibling, .previousSibling и т.п.

Можно даже далеко не ходить, а просто двигаться маленькими шажками:
Код:

        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

Цитата:

Код:

1 DispHTMLElementCollection
2 32
3 HTMLDivElement
4 -1
5 DispDOMChildrenCollection
6 5
7 DispHTMLDOMTextNode
8 #text
9 HTMLDivElement
10 DIV


и т.д. — глыбже, глыбже и глыбже. Потом оставляете из этой простыни только то, что на самом деле нужно.

Хорошо также смотреть внутрь результирующего сгенерированного html посредством Инспектора/Проводника DOM (F12), разумеется, под IE, и под конкретно той версией IE, под которой будет работать скрипт (у меня Проводник DOM не работает, отваливается).

Возвращаясь к этому:
Цитата:

Цитата The_Immortal
Далее я хочу сразу прыгнуть на 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")

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

Это ровно так, как Вам посоветовали на форуме SCI. Только действовать следует точно так же, как я писал выше: Вы получили методом .getElementsByClassName("row rowBox rowBoxEven") коллекцию типа HTMLElementCollection — проверьте её длину, если она не нулевая — либо перебирайте все её члены (item'ы) и обращайтесь к потребному item'у, либо, если количество item'ов всегда неизменно и точно знаете номер — просто сразу обращайтесь к потребному item'у по номеру. И только получив из HTMLElementCollection конкретный item — выполняете для него (а не для самой HTMLElementCollection) метод .getElementsByClassName("header").

Цитата:

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

И не раз ;).

The_Immortal 09-05-2018 01:48 2812700

Iska,
Цитата:

Цитата Iska
И только получив из HTMLElementCollection конкретный item — выполняете для него (а не для самой HTMLElementCollection) метод .getElementsByClassName("header"). »

Ну вот только оказалось, что обращаться нужно опять-таки к конкретному члену? Т.е. .getElementsByClassName("header").item(0) . Верно?

И, кстати,
Код:

.document.getElementsByClassName("row rowBox rowBoxEven").item(0)
ведь абсолютно эквивалентно
Код:

.document.getElementsByClassName("row rowBox rowBoxEven")(0)
Правильно понимаю?

Да и child'ы мне похоже вообще не нужны:
Цитата:

Цитата Iska
если количество item'ов всегда неизменно и точно знаете номер — просто сразу обращайтесь к потребному item'у по номеру »



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

Я всё-таки решил делать так, как задумал ранее. Получаю через класс "header" колекцию, состоящую из названий матчей. Далее произвожу сравнение элементов коллекций с искомым массивом. Если совпадение обнаружено, то ... Вот тут конкретный тупик. Мне надо каким-то образом внутри этого блока (где находится div "header") прыгнуть на div'ы "pull-left" (их четыре) и анализровать название классов их дочерей.

Сначала я подумал, что проблему с прыжком на нужное можно решить так:
Код:

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>

Какая в текущий момент нода по счёту из обрабатываемого списка коллекции и какому конкретно классу из этих двух она относится? Фиг его знает! Да, я там выше оформил счётчик CurMatch = CurMatch + 1, но он ничем не поможет тут.

Ну и второй (более, наверное, правильный) подход - позицинироваться относительно текущего элемента:
Код:

WScript.Echo Match.NextSibling.NextSibling.NextSibling.className
Но сиё вообще не робит :(
Продублирую 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="header">Матч 01 - Россия : Саудовская Аравия - Москва «Лужники»</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>

Не могли бы Вы мне подсказать через пожалуйста в чем моя ошибка теперь?

Serguei Kouzmine 09-05-2018 06:57 2812717

попробуйте то же только в повершел -
Код:


$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.*' }


The_Immortal 09-05-2018 16:48 2812809

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>

Я на этом объекте (Match - см. выше):
Код:

<div class="header">Матч 01 - Россия : Саудовская Аравия - Москва «Лужники»</div>
Для теста выполняю вот такое:
Код:

WScript.Echo Match.NextSibling.className
, ожидая перейти просто на следующий div (<div class="row">) и извлечь имя класса этого div'а, но получаю ошибку о том, что объект Match.NextSibling не поддерживает свойство NextSibling.className. Тогда я пробую так:
Код:

WScript.Echo (Match.NextSibling).className
, на что получаю сначала вывод [object Text], а после сразу же ошибку:
Цитата:

Требуется объект: 'WScript.Echo(...)'
В общем, ерунда какая-то... По логике мне должно было вернуться имя класса следующего div'а, т.е. просто "row" :(

Serguei Kouzmine 09-05-2018 23:11 2812870

опишите пожалнйста еще раз текстом задачу кот решаете

WScript это что то о чем некоторым хочется поскоее забыть - продираться через дебри вашего кода чтобы выяснить objective честно не сильно хота. но может быть получится написать с нуля

The_Immortal 09-05-2018 23:42 2812876

Serguei Kouzmine,
Цитата:

Цитата Serguei Kouzmine
опишите пожалнйста еще раз текстом задачу кот решаете »

Вот отсюда со слов "Локализую проблему".

Serguei Kouzmine 10-05-2018 00:02 2812877

да вы шутите! - сядьте посидите подумайте и опишите задачу кот вы решаете.

Код:

# based on: http://forum.oszone.net/thread-334713.html
# objective:
# associate the titles of the matches with the presence of the column
# other than the
# "class="categoryBox zeroAvailability"
# which indicates e.g. lowAvailability

$ie = new-object -com 'internetexplorer.application'
$ie.visible = $true
$target_url = 'https://tickets.fifa.com/Services/ADService.html?lang=ru'
$ie.navigate2($target_url)
# wait for the page to loads
while (($ie.Busy -eq $true ) -or ($ie.ReadyState -ne 4)) { # 4 a.k.a. READYSTATE_COMPLETE
  start-sleep 100
}
$debug =  $false
$documentElement = $ie.document.documentElement

# https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName
# $m1 is likely HTMLCollection
$m1 = $documentElement.getElementsByClassName('header')
if ($debug) {
  $m1.item(1)
}

# limit the work to few first nodes
$cnt = 0
$max_items = 100

if ($m1.length -lt $max_items ){
  $max_items = $m1.length - 1
}

1..$m1.length | foreach-object {

 if ($cnt -ge $max_items ) {
  if ($ie -ne  $null) {
    $ie.quit()
    $ie = $null
    return
  }
 } else {
  $cnt = $_
  if ($debug ){
    write-output $cnt
  }
  $e1 = $m1.item($cnt)

  # write-output ( 'Node text: ' + $e1.textContent )
  if ($debug ){
    write-output ( 'Node name: ' + $e1.nodeName ) # DIV
    write-output ( 'Node text: ' + $e1.textContent )
  }
  $e2 = $e1.parentNode
  if ($debug ){
    $e2.innerHTML
    # <div class="header" ng-bind="product.productName">???? 02 -?????? : ??????? - ????????????</div>
  }

  $e3 = $e2.parentNode

  $e4 = $e3.NextSibling.NextSibling

  if ($debug ){
    $e4.textContent
    #    CAT 1
    #    CAT 2
    #    CAT 3
    #    CAT 4
  }

  $m2 = $e4.getElementsByClassName('categoryBox')
  if ($debug ){
    $m2[1].innerHTML
    # CAT 2
    $m2[1].outerHTML
    # <div class="categoryBox zeroAvailability" ng-bind="cat.categoryName" ng-class="cat.availabilityColor">CAT 2</div>
  }
  if ($debug) {
    write-output $m2[0].outerHTML
  }
  if ($debug) {
    $m2 | foreach-object {
      write-output ("class: " + $_.className)

      # write-output ("class: " + $_.getAttribute('class'))
      write-output ("ng-class: " + $_.getAttribute('ng-class'))
      write-output ("context: " + $_.textContent)
    }
  }
  <#  $_.className -match '.*(?:zeroAvailability|lowAvailability).*'  #>
  $m2 | where-object { $_.className -match '.*(?:lowAvailability).*' } |
    foreach-object {
      write-output ('Node2 HTML: ' + $_.outerHTML)
      write-output ('Node 2 context: ' + $e1.textContent)
      write-output ('Node1 text: ' + $e1.textContent )
    }
  }
}

запускаем получаем
Код:


PS > . .\fifa_tickets.ps1

Node2 HTML: <div class="categoryBox lowAvailability" ng-bind="cat.categoryName"
ng-class="cat.availabilityColor">CAT 1</div>
Node 2 context: Матч 46 - Панама : Тунис - Саранск
Node1 text: Матч 46 - Панама : Тунис - Саранск


The_Immortal 10-05-2018 01:38 2812881

Serguei Kouzmine, честно попытался разобрать эти закорючкиPowerShell'ьные премудрости, но тяжко... По-прежнему хочу добить своё :)
Вот то, что конкретно надо мне, сидит у Вас вот в этих строчках:

Код:

  $m1 = $documentElement.getElementsByClassName('header')

  $e1 = $m1.item($cnt)

  $e2 = $e1.parentNode

  $e3 = $e2.parentNode

  $e4 = $e3.NextSibling.NextSibling

  $m2 = $e4.getElementsByClassName('categoryBox')

Хоть убейте не могу понять как работает NextSibling... После последовательных обращений дважды к родителю $e3 представляет собой элемент <div class="col-sm-3 col-xs-12">, так? Далее Вы делаете два прыжка:
Код:

$e4 = $e3.NextSibling.NextSibling
- как и куда он прыгает? По идее же нужен один прыжок, чтобы с <div class="col-sm-3 col-xs-12"> перейти на <div class="col-sm-9 col-xs-12">, а у Вас их два почему-то! =|

Iska, Вы не могли помочь мне разобраться почему там требуется два прыжка а не один? Это не дает мне покоя.

Код:

<div class="row rowBox rowBoxEven">
        <div class="col-sm-3 col-xs-12"> !!! МЫ ВОТ ТУТ!!!
                ...
        </div>

        !!!!! ПРЫЖОК !!!!!

        <div class="col-sm-9 col-xs-12">  !!! ХОТИМ СЮДА!!!
                ...
        </div>
</div

Сколько прыжков там? Один же! А по факту надо два... Почему же, млин, их там два? Откуда???


Дабы мой вопрос был полностью понятен, я сделал демо, которое отражает суть проблемы - кликните и поймете мой затуп :) Почему после первого прыжка у нас имя класса "undefined"??? И откуда при этом тип объекта это Text? Там меж div'ами вообще текста как бы нету.

Serguei Kouzmine 11-05-2018 08:16 2813107

успокойтесь пожалуйста - по-моему это аргуляр не всегда то что видишь F12 есть то что он на самом деле рисует/методом проб и ош.

там просто в финальной версии эти отладочные строки типа
Код:

$obj.outerHTML
прочищены

The_Immortal 11-05-2018 17:13 2813228

Цитата:

Цитата Serguei Kouzmine
успокойтесь пожалуйста »

Нет, я не из тех :)

Короче, проблема там была в том, что меж див'ами сидят всякие пробелы, вот их свойство NextSibling-то и видит. Узрейте разницу: тыц и тыц. А вообще, в моём случае логичнее прыгать через свойство nextElementSibling: тыц ;)

Большое спасибо за помощь!

Iska 11-05-2018 17:55 2813239

Цитата:

Цитата The_Immortal
Короче, проблема там была в том, что меж див'ами сидят всякие пробелы, »

Угумс ;). TextNode'ы. А ещё, вероятно, их наличие зависит от используемой версии IE. Так же, как и свойство .nextElementSibling появляется только с 9-й версии IE.

The_Immortal 12-05-2018 02:10 2813314

Iska,
Цитата:

Цитата Iska
их наличие зависит от используемой версии IE »

А причем тут IE? Под разными браузерами будет одна и та же реакция.

Iska 12-05-2018 06:43 2813319

Цитата:

Цитата The_Immortal
А причем тут IE? »

При том, что раньше он не преображал whitespace'ы в TextNode'ы. Затем, с какой-то версии, начал это делать, и потому реальное состояние DOM теперь не соответствует видимым html-тэгам (да, теперь так, всё, о чём так долго говорили большевики в W3C, свершилось).

Если же Вы про IE вообще — так ведь мы пользуем его библиотеки для получения страницы и последующего разбора DOM.

Цитата:

Цитата The_Immortal
Под разными браузерами будет одна и та же реакция. »

Вообще-то — нет. И не только под разными браузерами, но даже под разными версиями одного и того же браузера может быть по-разному.

The_Immortal 12-05-2018 23:26 2813427

Iska,
Цитата:

Цитата Iska
Вообще-то — нет. И не только под разными браузерами, но даже под разными версиями одного и того же браузера может быть по-разному. »

Ну... Я прогнал вышеуказанный пример под 4-мя браузерами - вывод один и тот же :) Или Вы что-то другое имели в виду?

Iska 12-05-2018 23:34 2813430

The_Immortal, нынче все браузеры достаточно сблизились в своих трактовках «как оно должно быть». Попробуйте прогнать его под IE 6/7/8. Попробуйте прогнать свой код под IE 6/7/8. Кроме отсутствия свойства .nextElementSibling наверняка не будет и фантомных текстовых элементов.


Время: 22:40.

Время: 22:40.
© OSzone.net 2001-