Русский
Русский
English
Статистика
Реклама

Как я html-парсер на php писал, и что из этого вышло. Заключительная часть

Здравствуйте.
Представляю вам заключительную главу цикла. В ней пойдет речь о реализации самого парсера, его модулей, вроде функции анализа, построения стека и dom дерева. Помимо этого поговорим и об обработке комментариев. Как оказалось, комментарии могут обрабатываться по разному. Напишем свой поиск элементов, подробнее поговорим о поиске по классам и идентификаторам. И многое другое!

Введение


Если вы не знакомы с устройством html парсеров и не прочитали предыдущею главу, рекомендую почитать.Я обновил в ней картинки, так что теперь воспринимать информацию там приятнее.

В этой статье будет введен новый ряд терминов:

  • Цепочка последовательность любых символов.
  • Состояние условие, от которого будет зависеть дальнейшая обработка цепочки парсером.
  • Токен массив, содержащий информацию о теге, комментарии или тексте. Также токен часто называют Словом.
  • Стек массив, содержащий токены.
  • Разграничительный символ символ, после которого следующая цепочка обрабатывается как новая цепочка.
  • Алфавит список символов, которые имеют первостепенную важность для парсера.

Если термины из списка вам не понятны, не волнуйтесь: в контексте все станет ясно.

Исходный код доступен на github.

Главные переменные парсера


Перед тем как писать парсер, следует определится с главными переменными, чтобы потом отталкиваться от них при дальнейшем написании.
А их будет четыре:

  1. $__SOURCE_TEXT Содержит в себе текст исходного документа.
  2. $__DOM Содержит в себе полученный в результате парсинга массив с dom деревом.
  3. $__ENABLE_COMMENTS Означает, включена ли функция отображения комментариев или нет.
  4. $__ESCAPE_SYMBOLS Массив со специальными символами и пробелом.
  5. $__MANDATORY_OPEN_ELEMENTS Массив из четырех ячеек, обозначающие наличие обязательных открывающих тегов в документе.
  6. $__MANDATORY_CLOSE_ELEMENTS Массив из трёх ячеек, обозначающие наличие обязательных закрывающих тегов в документе.

Класс парсера и его конструктор


Для того, чтобы потом было легче добавлять функционал, напишем класс парсера. В начале там будет функция отправки запросов, но постепенно туда будет записываться новый функционал.

Класс парсера


Эта часть кода взята из функции анализа, дальше в статье вы увидите, где она будет находиться.

Вы могли заметить, что в проверке не участвуют теги <tbody> и <colgroup>. Они не являются обязательными, более того, их вставка может понадобится несколько раз в документе, поэтому их наличие и вставка будут проверяться динамически, во время выполнения функции вставки тегов.

После того, как мы разобрались со способом нахождения обязательных тегов в документе, нужно написать функцию, которая будет их вставлять по мере надобности. Так как с условиями вставки обязательных тегов мы разобрались, давайте поговорим об алгоритме вставки <tbody> и <colgroup>. Все будет работать очень просто: так как эти теги встречаются в документе только в теге <table>, то сначала функция будет проверять, есть ли такой тег в документе или нет. Если да, то она начинает цикл, в котором будут происходить следующие действия: сначала, функция должна будет проверить наличие тега <colgroup> в таблице. Если он есть, то добавлять еще один такой же тег бессмысленно. Если тег <colgroup> закрыт, то алгоритм начинает заново проверять наличие этого тега где-либо еще в таблице. Параллельно с этим функция также будет проверять наличие контента в таблице. Если контент в таблице присутствует и находится в тегах <tbody> или <thead>, то вставлять <tbody> смысла нет. Если же нет, то алгоритм вставит этот тег в нужное место в документе. Вот и все, давайте приступать к коду.

Функция вставки тегов


Как вы видите, кода слишком много, и если мы задумаемся написать под каждый такой тег такие условия(а их больше десятка), то конечная функция по размерам будет как сам парсер. Так что с этим нужно разобраться. Вместо написания одних и тех же условий для каждого такого тега, лучше написать одну гибкую функцию сразу для всех. Она значительно облегчит навигацию по коду, но будет гораздо сложнее метода разработки условий под каждый тег отдельно. Перед тем как показать код, давайте спроектируем алгоритм ее работы. Для начала, нужно определится с тем, где именно функция будет выполняться. Будет лучше, если функция будет выполнятся перед началом работы рекурсии, чтобы потом не было проблем с зависимостями в массиве dom дерева. Поэтому функция будет выполняться сразу после работы функции построения стека. Так как тегов с необязательными закрывающими тегами много, стоит сделать массив со всеми такими тегами, а также с тегами подуровня(<ul>, <ol>), и с тегами, перед которыми нужно ставить закрывающий тег(<li>, <dd>, <dt> и д.р).

После того, как мы разобрались с основными моментами, стоит поговорит о самом алгоритме работы функции. Сначала функция будет брать токен. Далее она проверяет, была ли функция вызвана собой же, или она выполняется впервые. Если она вызвана собой же, значит токен в данный момент находится в подуровне и дальнейшие элементы стоит обрабатывать только в контексте подуровня. Если нет, значит это первый вызов функции, и токены нужно обрабатывать уже без контекста.

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

В принципе, это все. Остались только некоторые различия в обработке в контексте подуровня и в бесконтекстной обработке. Но они не слишком сильно отличаются, так что понять различия можно будет при просмотре кода.

Caption и colgroup


Теперь давайте поговорим про теги с иными условиями, благо их всего два <caption> и <colgroup>. В спецификации сказано, что закрывающий тег <caption> можно опустить только если за ним следует пробельный символ. Но так как в нашем парсере пробельные символы опускаются, мы условимся, что в теге <caption> не допускается наличие любых других тегов. С <colgroup> несколько иначе. Спецификация говорит, что закрывающий тег <colgroup> может быть опущен если после него нету пробельного символа или комментария. Но тут ситуация неоднозначная, так как наш парсер пропускает все пробельные символы после тегов. Так что мы условимся, что в <colgroup> могут быть только теги <col> и как только парсер найдет другой тег, он сразу же поставит перед ним закрывающий тег.

Раз закончили, давайте смотреть на код.

Функция вставки закрывающий тегов


Эта функция проверяет, является ли тег одиночным. Если да, то выводит true.

Функция для пропуска пробелов


Но что там по комментариям? Возможно вы спросите меня. Я не стал включать комментарии в эту функцию, банально потому, что это функция обработки тегов, когда у комментариев свой собственный синтаксис, и их нужно обрабатывать отдельной функцией. Об этом пойдет речь дальше.

Так, а теперь построение стека


Как строится стек я уже говорил ранее в первой главе. Так что нам осталось только реализовать этот алгоритм.

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

<!--<-->

Если подумали, то посмотрите, как этот комментарий обрабатывает браузер и редактор.
Вот как видит комментарий браузер:

<!---->

Как будто там и не было ничего. При этом, "-->" выносится как текст, а не комментарий.
А вот как видит его редактор:

<!--<-->

Результат выглядит так же, как исходный пример. И назревает вопрос: как это обрабатывать? Я решил обрабатывать так же, как и редактор.

А как будем обрабатывать теги <script> и <style>? Все просто. У нас будет переменная, которая в случаи, если был найден любой из этих тегов, будет игнорировать последующие цепочки ровно до того момента, пока не будет найден закрывающий тег. При этом, любые ошибки, найденные внутри тега, будут также игнорироваться.

Теперь стоит поговорить о дополнительных функциях к этому алгоритму. Их будет немного.

Функция для обработки комментариев


Пропускает все символы, указанные в параметрах функции в виде массива и выводит в результате строку без этих символов.

С дополнительными функциями разобрались. Давайте писать код.

Функция построения стека


Что ж, раз со всем разобрались, давайте приступать к коду.

Функция построения DOM дерева


Отлично, класс написали. Теперь давайте поговорим про тонкости поиска.

Сначала давайте поговорим про то, как найти определенный элемент по счету. Он может быть первый, второй, или пятый. Для этого добавим дополнительную переменную
$point
. Она отображает, на каком найденном элементе по счету находится поиск. Если мы указали в аргументах функции после элемента, который нам нужно найти число n, то поиск будет искать ровно до того момента, пока найденный элемент не будет по счету n-ым. При этом счетчик будет увеличиваться когда будет найден указанный в аргументах функции элемент. Ну и конечно, в результате поиска будет только этот элемент и его подмассив, если он присутствует.

Раз со всем разобрались, давайте напишем поиск только по тегу, а потом уже по классу и идентификатору.

Функция поиска только по тегу


Поиск дочерних элементов


Сразу стоит сказать, что все найденные элементы для парсера являются дочерний элементами. То есть, если вы хотите найти в определенном элементе определенный дочерний элемент, сначала вам нужно сказать парсеру, в каком элементе вы хотите начать поиск. Если вы не хотите этого делать, вам стоит воспользоваться аргументом функции поиска для нахождения определенного элемента, тогда вам не придется использовать дополнительную функцию поиска дочернего элемента для указания элемента, где именно нужно вести поиск.

В целом, это все. Ничего сложного в написании класса нет.

Класс дочернего элемента


Тесты


Вот мы и написали парсер! Теперь давайте проверим его в тестах. Тесты будут не только на производительность, но и на правильность выполнения. Давайте смотреть!

Правильность выполнение


Мы сделаем три теста на правильность, а также один дополнительный на хорошего верстальщика. Первый будет для проверки того, как парсер добавляет недостающие теги, второй будет на правильность удаления лишних, а третий на правильную обработку тегов, закрывающий тег которым не обязательно нужен. Последний тест можно считать бесполезным, он скорее просто интересен сам по себе. Начнем с первого теста.

Тест на недостающие теги


Для теста возьмем вот такой html:

Код
<!DOCTYPE html><html><head><link rel="stylesheet" href="1"><link rel="stylesheet" href="2"><link rel="stylesheet" href="3"><link rel="stylesheet' href="4></head><body><div>0<div id = 'somebody'>Привет!<style>once told me, the world is gonna roll me</style><!-- А где </div>?--></div></body></html>


Как видно в примере, одного тега не хватает. Давайте посмотрим, какой результат выведет наш парсер:

Вывод
Array([0] => Array(    [is_closing] =>     [is_singleton] => 1    [pointer] => 15    [tag] => !DOCTYPE    [html] => 1)[1] => Array(    [is_closing] =>     [is_singleton] =>     [pointer] => 23    [tag] => html    [0] => Array        (            [0] => Array                (                    [is_closing] =>                     [is_singleton] =>                     [pointer] => 32                    [tag] => head                    [0] => Array                        (                            [0] => Array                                (                                    [is_closing] =>                                     [is_singleton] => 1                                    [pointer] => 68                                    [tag] => link                                    [rel] => stylesheet                                    [href] => 1                                )                            [1] => Array                                (                                    [is_closing] =>                                     [is_singleton] => 1                                    [pointer] => 104                                    [tag] => link                                    [rel] => stylesheet                                    [href] => 2                                )                            [2] => Array                                (                                    [is_closing] =>                                     [is_singleton] => 1                                    [pointer] => 140                                    [tag] => link                                    [rel] => stylesheet                                    [href] => 3                                )                            [3] => Array                                (                                    [is_closing] =>                                     [is_singleton] => 1                                    [pointer] => 167                                    [tag] => link                                    [rel] => stylesheet                                )                            [4] => Array                                (                                    [is_closing] => 1                                    [is_singleton] =>                                     [pointer] => 177                                    [tag] => head                                )                        )                )            [1] => Array                (                    [is_closing] =>                     [is_singleton] =>                     [pointer] => 186                    [tag] => body                    [0] => Array                        (                            [0] => Array                                (                                    [is_closing] =>                                     [is_singleton] =>                                     [pointer] => 195                                    [tag] => div                                    [0] => Array                                        (                                            [0] => Array                                                (                                                    [tag] => __TEXT                                                    [0] => 0                                                )                                            [1] => Array                                                (                                                    [is_closing] =>                                                     [is_singleton] =>                                                     [pointer] => 227                                                    [tag] => div                                                    [id] => Array                                                        (                                                            [0] => somebody                                                        )                                                    [0] => Array                                                        (                                                            [0] => Array                                                                (                                                                    [tag] => __TEXT                                                                    [0] => Привет!                                                                )                                                            [1] => Array                                                                (                                                                    [tag] => __COMMENT                                                                    [0] => <!-- А гле </div>?-->                                                                )                                                            [2] => Array                                                                (                                                                    [is_closing] => 1                                                                    [is_singleton] =>                                                                     [pointer] => 348                                                                    [tag] => div                                                                )                                                        )                                                )                                            [2] => Array                                                (                                                    [tag] => div //А вот и он                                                    [is_closing] => 1                                                )                                        )                                )                            [1] => Array                                (                                    [is_closing] => 1                                    [is_singleton] =>                                     [pointer] => 358                                    [tag] => body                                )                        )                )            [2] => Array                (                    [is_closing] => 1                    [is_singleton] =>                     [pointer] => 367                    [tag] => html                )        )))


Отлично, парсер правильно обработал страницу.

Теперь давайте посмотрим на работу парсера, когда тегов больше, чем нужно.
Возьмем вот такой html:

Код
<!DOCTYPE html><html><head><link rel="stylesheet" href="1"><link rel="stylesheet" href="2"><link rel="stylesheet" href="3"><link rel="stylesheet"></head><body><div></span></span></span></span></span></span></span></span><div id = 'somebody'>Привет!<style>once told me, the world is gonna roll me</style></span></span></span></span></span></span></span></span></div></body></html>


В этом html, как видно, верстальщик немного переборщил с элементами. Впрочем, неважно. Давайте посмотрим, как парсер обработает это:

Вывод
Array([0] => Array(    [is_closing] =>     [is_singleton] => 1    [pointer] => 15    [tag] => !DOCTYPE    [html] => 1)[1] => Array(    [is_closing] =>     [is_singleton] =>     [pointer] => 23    [tag] => html    [0] => Array        (            [0] => Array                (                    [is_closing] =>                     [is_singleton] =>                     [pointer] => 32                    [tag] => head                    [0] => Array                        (                            [0] => Array                                (                                    [is_closing] =>                                     [is_singleton] => 1                                    [pointer] => 68                                    [tag] => link                                    [rel] => stylesheet                                    [href] => 1                                )                            [1] => Array                                (                                    [is_closing] =>                                     [is_singleton] => 1                                    [pointer] => 104                                    [tag] => link                                    [rel] => stylesheet                                    [href] => 2                                )                            [2] => Array                                (                                    [is_closing] =>                                     [is_singleton] => 1                                    [pointer] => 140                                    [tag] => link                                    [rel] => stylesheet                                    [href] => 3                                )                            [3] => Array                                (                                    [is_closing] =>                                     [is_singleton] => 1                                    [pointer] => 167                                    [tag] => link                                    [rel] => stylesheet                                )                            [4] => Array                                (                                    [is_closing] => 1                                    [is_singleton] =>                                     [pointer] => 177                                    [tag] => head                                )                        )                )            [1] => Array                (                    [is_closing] =>                     [is_singleton] =>                     [pointer] => 186                    [tag] => body                    [0] => Array                        (                            [0] => Array                                (                                    [is_closing] =>                                     [is_singleton] =>                                     [pointer] => 195                                    [tag] => div                                    [0] => Array                                        (                                            [0] => Array                                                (                                                    [is_closing] =>                                                     [is_singleton] =>                                                     [pointer] => 481                                                    [tag] => div                                                    [id] => Array                                                        (                                                            [0] => somebody                                                        )                                                    [0] => Array                                                        (                                                            [0] => Array                                                                (                                                                    [tag] => __TEXT                                                                    [0] => Привет!                                                                )                                                            [1] => Array                                                                (                                                                    [is_closing] => 1                                                                    [is_singleton] =>                                                                     [pointer] => 831                                                                    [tag] => div                                                                )                                                        )                                                )                                            [1] => Array                                                (                                                    [tag] => div                                                    [is_closing] => 1                                                )                                        )                                )                            [1] => Array                                (                                    [is_closing] => 1                                    [is_singleton] =>                                     [pointer] => 841                                    [tag] => body                                )                        )                )            [2] => Array                (                    [is_closing] => 1                    [is_singleton] =>                     [pointer] => 850                    [tag] => html                )        )))


Чисто, аккуратно и по красоте. Что ж, раз так, давайте приступим к следующему тесту.

Тест на хорошего верстальщика


Наверное, самый интересный тест. Навряд ли конечно кто-нибудь будет так писать, но проверить нужно.
Для этого теста возьмем вот такой html:

Код
<!DOCTYPE html><html>  <head>    <link rel="stylesheet" href="1">    <link rel="stylesheet" href="2">    <link rel="stylesheet" href="3">    <link rel="stylesheet">  </head>  <body>    <div>      <div><span></div><p></span></p>      <div id = 'somebody'>        Привет!        <style>once told me, the world is gonna roll me</style>    </div>  </body></html>


А теперь давайте посмотрим на вывод парсера:

Вывод
Array([0] => Array([is_closing] => [is_singleton] => 1[pointer] => 15[tag] => !DOCTYPE[html] => 1)[1] => Array([is_closing] => [is_singleton] => [pointer] => 23[tag] => html[0] => Array([0] => Array([is_closing] => [is_singleton] => [pointer] => 33[tag] => head[0] => Array    (        [0] => Array            (                [is_closing] =>                 [is_singleton] => 1                [pointer] => 71                [tag] => link                [rel] => stylesheet                [href] => 1            )        [1] => Array            (                [is_closing] =>                 [is_singleton] => 1                [pointer] => 109                [tag] => link                [rel] => stylesheet                [href] => 2            )        [2] => Array            (                [is_closing] =>                 [is_singleton] => 1                [pointer] => 147                [tag] => link                [rel] => stylesheet                [href] => 3            )        [3] => Array            (                [is_closing] =>                 [is_singleton] => 1                [pointer] => 176                [tag] => link                [rel] => stylesheet            )        [4] => Array            (                [is_closing] => 1                [is_singleton] =>                 [pointer] => 187                [tag] => head            )    ))[1] => Array([is_closing] => [is_singleton] => [pointer] => 197[tag] => body[0] => Array    (        [0] => Array            (                [is_closing] =>                 [is_singleton] =>                 [pointer] => 208                [tag] => div                [0] => Array                    (                        [0] => Array                            (                                [is_closing] =>                                 [is_singleton] =>                                 [pointer] => 221                                [tag] => div                                [0] => Array                                    (                                        [0] => Array                                            (                                                [is_closing] =>                                                 [is_singleton] =>                                                 [pointer] => 227                                                [tag] => span                                                [0] => Array                                                    (                                                        [0] => Array                                                            (                                                                [tag] => span                                                                [is_closing] => 1                                                            )                                                    )                                            )                                        [1] => Array                                            (                                                [is_closing] => 1                                                [is_singleton] =>                                                 [pointer] => 233                                                [tag] => div                                            )                                    )                            )                        [1] => Array                            (                                [is_closing] =>                                 [is_singleton] =>                                 [pointer] => 236                                [tag] => p                                [0] => Array                                    (                                        [0] => Array                                            (                                                [is_closing] => 1                                                [is_singleton] =>                                                 [pointer] => 247                                                [tag] => p                                            )                                    )                            )                        [2] => Array                            (                                [is_closing] =>                                 [is_singleton] =>                                 [pointer] => 276                                [tag] => div                                [id] => Array                                    (                                        [0] => somebody                                    )                                [0] => Array                                    (                                        [0] => Array                                            (                                                [tag] => __TEXT                                                [0] =>         Привет!                                            )                                        [1] => Array                                            (                                                [is_closing] => 1                                                [is_singleton] =>                                                 [pointer] => 376                                                [tag] => div                                            )                                    )                            )                        [3] => Array                            (                                [tag] => div                                [is_closing] => 1                            )                    )            )        [1] => Array            (                [is_closing] => 1                [is_singleton] =>                 [pointer] => 387                [tag] => body            )    ))[2] => Array([is_closing] => 1[is_singleton] => [pointer] => 396[tag] => html))))


Наверное, это правильный результат выполнение. Наверное.

Тесты на необязательные теги


После того, как разобрались с основным механизмом исправления ошибок в парсере, давайте поговорим про дополнительный. Для этого я возьму такой код:

Код
<table><caption>37547 TEE Electric Powered Rail Car Train Functions (Abbreviated)<colgroup><col><col><col><thead><tr>  <th>Function  <th>Control Unit  <th>Central Station<tbody><tr>  <td>Headlights  <td>  <td><tr>  <td>Interior Lights  <td>  <td><tr>  <td>Electric locomotive operating sounds  <td>  <td><tr>  <td>Engineers cab lighting  <td>  <td><tr>  <td>Station Announcements - Swiss  <td>  <td></table>


Давайте посмотрим на результат:

Результат
[0] => Array([tag] => !DOCTYPE[html] => 1[is_singleton] => 1)[1] => Array([tag] => html[is_singleton] => [is_closing] => [0] => Array([0] => Array([tag] => head[is_singleton] => [is_closing] => [0] => Array([0] => Array([tag] => head[is_singleton] => [is_closing] => 1)))[1] => Array([tag] => body[is_singleton] => [is_closing] => [0] => Array([0] => Array([is_closing] => [is_singleton] => [pointer] => 7[tag] => table[0] => Array(    [0] => Array        (            [is_closing] =>             [is_singleton] =>             [pointer] => 18            [tag] => caption            [0] => Array                (                    [0] => Array                        (                            [tag] => __TEXT                            [0] => 37547 TEE Electric Powered Rail Car Train Functions (Abbreviated)                        )                    [1] => Array                        (                            [tag] => caption                            [is_closing] => 1                        )                )        )    [1] => Array        (            [is_closing] =>             [is_singleton] =>             [pointer] => 95            [tag] => colgroup            [0] => Array                (                    [0] => Array                        (                            [is_closing] =>                             [is_singleton] => 1                            [pointer] => 100                            [tag] => col                        )                    [1] => Array                        (                            [is_closing] =>                             [is_singleton] => 1                            [pointer] => 105                            [tag] => col                        )                    [2] => Array                        (                            [is_closing] =>                             [is_singleton] => 1                            [pointer] => 110                            [tag] => col                        )                    [3] => Array                        (                            [tag] => colgroup                            [is_closing] => 1                        )                )        )    [2] => Array        (            [is_closing] =>             [is_singleton] =>             [pointer] => 119            [tag] => thead            [0] => Array                (                    [0] => Array                        (                            [is_closing] =>                             [is_singleton] =>                             [pointer] => 125                            [tag] => tr                            [0] => Array                                (                                    [0] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 133                                            [tag] => th                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] => Function                                                        )                                                    [1] => Array                                                        (                                                            [tag] => th                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [1] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 149                                            [tag] => th                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] => Control Unit                                                        )                                                    [1] => Array                                                        (                                                            [tag] => th                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [2] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 169                                            [tag] => th                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] => Central Station                                                        )                                                    [1] => Array                                                        (                                                            [tag] => th                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [3] => Array                                        (                                            [tag] => tr                                            [is_closing] => 1                                        )                                )                        )                    [1] => Array                        (                            [tag] => thead                            [is_closing] => 1                        )                )        )    [3] => Array        (            [is_closing] =>             [is_singleton] =>             [pointer] => 193            [tag] => tbody            [0] => Array                (                    [0] => Array                        (                            [is_closing] =>                             [is_singleton] =>                             [pointer] => 199                            [tag] => tr                            [0] => Array                                (                                    [0] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 207                                            [tag] => td                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] => Headlights                                                        )                                                    [1] => Array                                                        (                                                            [tag] => td                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [1] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 225                                            [tag] => td                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] =>                                                         )                                                    [1] => Array                                                        (                                                            [tag] => td                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [2] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 236                                            [tag] => td                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] =>                                                         )                                                    [1] => Array                                                        (                                                            [tag] => td                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [3] => Array                                        (                                            [tag] => tr                                            [is_closing] => 1                                        )                                )                        )                    [1] => Array                        (                            [is_closing] =>                             [is_singleton] =>                             [pointer] => 245                            [tag] => tr                            [0] => Array                                (                                    [0] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 253                                            [tag] => td                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] => Interior Lights                                                        )                                                    [1] => Array                                                        (                                                            [tag] => td                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [1] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 276                                            [tag] => td                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] =>                                                         )                                                    [1] => Array                                                        (                                                            [tag] => td                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [2] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 287                                            [tag] => td                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] =>                                                         )                                                    [1] => Array                                                        (                                                            [tag] => td                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [3] => Array                                        (                                            [tag] => tr                                            [is_closing] => 1                                        )                                )                        )                    [2] => Array                        (                            [is_closing] =>                             [is_singleton] =>                             [pointer] => 296                            [tag] => tr                            [0] => Array                                (                                    [0] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 304                                            [tag] => td                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] => Electric locomotive operating sounds                                                        )                                                    [1] => Array                                                        (                                                            [tag] => td                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [1] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 348                                            [tag] => td                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] =>                                                         )                                                    [1] => Array                                                        (                                                            [tag] => td                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [2] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 359                                            [tag] => td                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] =>                                                         )                                                    [1] => Array                                                        (                                                            [tag] => td                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [3] => Array                                        (                                            [tag] => tr                                            [is_closing] => 1                                        )                                )                        )                    [3] => Array                        (                            [is_closing] =>                             [is_singleton] =>                             [pointer] => 368                            [tag] => tr                            [0] => Array                                (                                    [0] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 376                                            [tag] => td                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] => Engineers cab lighting                                                        )                                                    [1] => Array                                                        (                                                            [tag] => td                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [1] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 409                                            [tag] => td                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => td                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [2] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 417                                            [tag] => td                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] =>                                                         )                                                    [1] => Array                                                        (                                                            [tag] => td                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [3] => Array                                        (                                            [tag] => tr                                            [is_closing] => 1                                        )                                )                        )                    [4] => Array                        (                            [is_closing] =>                             [is_singleton] =>                             [pointer] => 426                            [tag] => tr                            [0] => Array                                (                                    [0] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 434                                            [tag] => td                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] => Station Announcements - Swiss                                                        )                                                    [1] => Array                                                        (                                                            [tag] => td                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [1] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 471                                            [tag] => td                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => td                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [2] => Array                                        (                                            [is_closing] =>                                             [is_singleton] =>                                             [pointer] => 479                                            [tag] => td                                            [0] => Array                                                (                                                    [0] => Array                                                        (                                                            [tag] => __TEXT                                                            [0] =>                                                         )                                                    [1] => Array                                                        (                                                            [tag] => td                                                            [is_closing] => 1                                                        )                                                )                                        )                                    [3] => Array                                        (                                            [tag] => tr                                            [is_closing] => 1                                        )                                )                        )                    [5] => Array                        (                            [tag] => tbody                            [is_closing] => 1                        )                )        )    [4] => Array        (            [is_closing] => 1            [is_singleton] =>             [pointer] => 492            [tag] => table        )))[1] => Array([tag] => body[is_closing] => 1)))[2] => Array([tag] => html[is_closing] => 1))))


Добавились как и закрывающие теги, вроде <colgroup> или <caption>, так и обязательные теги <html>, <head> и <body>.

Тесты производительности


Внимание! Все тесты производительности будут происходить с заранее скачанными документами.

Что ж, раз с этим разобрались, давайте приступать. Для теста возьмем мою первую публикацию, Как я html-парсер на php писал, и что из этого вышло. Будем искать название публикации, а также показатель плюсиков. Начнем сначала со второго.

Для того, чтобы найти этот показатель, я буду использовать такой код:

$some->find('.voting-wjt__counter')->children(0)->children(0)->plainText();

Такой код выводит результат выполнения в браузере за ~660ms.

Теперь давайте найдем название публикации. Оно находится почти в самом верху, так что это будет быстрее. Для поиска я буду использовать такой код:

$some->find('.post__title-text')->children(0)->plainText();

Такой текст находится тоже за ~660ms.

Заключение


Странно, но иногда исходный код из paste.bin не показывается. Если у вас такая же проблема, то обновите страницу.
Спасибо Denai и vdem за указания на теги с необязательными закрывающими тегами.
Спасибо за внимание!
Источник: habr.com
К списку статей
Опубликовано: 15.08.2020 18:06:03
0

Сейчас читают

Комментариев (0)
Имя
Электронная почта

Php

Алгоритмы

Html

Парсер

Синтаксический анализатор

Html5

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru