php parse html domdocument
PHP – How to Parse Html DOM with DOMDocument
Domdocument
The domdocument class of Php is a very handy one that can be used for a number of tasks like parsing xml, html and creating xml. It is documented here.
In this tutorial we are going to see how to use this class to parse html content. The need to parse html happens when are you are for example writing scrapers, or similar data extraction scripts.
Sample html
The following is the sample html file that we are going to use with DomDocument.
1. Loading the html
So the first thing to do would be to construct a domdocument object and load the html content in it. Lets see how to do that.
Now that the html is loaded, its time to see how nodes and child elements can be accessed.
2. Get an element by its html id
This will get hold of a node/element by using its ID.
Getting the value/html of a node
The «nodeValue» attribute of an node shall give its value but strip all html inside it. For example
The second method is to use the saveHTML function, that gets out the exact html inside that particular node.
Note that the function saveHTML is called on the dom object and the node object is passed as a parameter. The saveHTML function will provide the whole html (outer html) of the node including the node’s own html tags as well.
Another function called C14N does the same thing more quickly
To get just the inner html take the following approach. It adds up the html of all of the child nodes.
The function get_inner_html gets the inner html of the html element. Note that we used the saveXML function instead of the saveHTML function. The property «childNodes» provides the child nodes of an element. These are the direct children.
3. Getting elements by tagname
This will get elements by tag name.
The function getElementsByTagName returns an object of type DomNodeList that can be read as an array of objects of type DomNode. Another way to fetch the nodes of the NodeList is by using the item function.
The item function takes the index of the item to be fetched. The length attribute of the DomNodeList gives the number of objects found.
4. Get the attributes of an element
Every DomNode has an attribute called «attributes» that is a collection of all the html attributes of that node.
Here is a quick example
To get a particular attribute using its name, use the «getNamedItem» function on the attributes object.
5. Children of a node
A DomNode has the following properties that provide access to its children
1. childNodes
2. firstChild
3. lastChild
Checking if child nodes exist
The hasChildNodes function can be used to check if a node has any children at all.
Quick example
6. Comparing 2 elements for equality
It might be needed to check if the element in 1 variable is the same as the element in another variable. The function «isSameNode» is used for this. The function is called on one node, and the other node is passed as the parameter. If the nodes are same, then boolean true is returned.
Conclusion
The above examples showed how Domdocument can be used to access elements in an html document in an object oriented manner. Domdocument can not only parse html but also create/modify html and xml. In later articles we shall see how to do that.
15 thoughts on “ PHP – How to Parse Html DOM with DOMDocument ”
Great article! I would be very interested to read about create/modify html nodes.
Hi, I have a question. As I’m not sure the HTML standards are always respected when I parse a page, I’d like to retrieve a tag with a specific id and classes.
Something like:
Hello there
in other words : span#myId.class1.class2
Thanks, great tutorial. It helped me.
Thanks. Great Tutorial. But can you please add the outputs of the code as well.
Many thanks, got i finally working because of your example
This is an old article, but I’m just getting started… In any case I think you are missing a “$” in front of the variable in your code above if(!mango_div).. Atleast I did. Thanks
Thanks Silver, your get_inner_html function has saved me a lot of time. Really great article.
above text not working in windows 7. it occurring this error
Catchable fatal error: Object of class DOMElement could not be converted to string in /var/www/websites/shabbonacreekrv/shabbonacreekrv.com/www/html/vehicle.php on line 65
Great article! I would be very interested to read about create/modify html nodes.
Hello I am getting Following error :
Warning: domdocument::domdocument() expects parameter 2….
Fatal error: Call to undefined method domdocument::loadHTML()
I am using php 5.2.x + WAMP
php_domxml extension is enebled.
Thanks, great tutorial!
Thanks for the tut. Would be helpful if you included the code (as you have) + the return values of your echo statements!
thanks for the feedback, shall update the post soon.
Thanks, this helped me a lot (was just looking for a nice DOCDocument example)!
Искусство парсинга или DOM своими руками
Привет, Хабр! Недавно я задался идеей создать простой язык разметки наподобие markdown, который отлично подходил бы для моих задач, а именно — быстрого написания лекций с форматированием и возможностью вставки математических формул «на лету», с применением одной лишь клавиатуры. Чтобы перевести текст, написанный в таком формате, в более понятную форму, например, документ LibreOffice Writer, нужен синтаксический анализатор, проще говоря — парсер. Поскольку я привык делать велосипеды, то направился в поисковые системы с запросами «parser example», «html to DOM», «how to parse html» и др. К моему разочарованию, на всех найденных ресурсах либо приводились элементарные примеры типа калькулятора Страуструпа с рекурсивным спуском, либо использовались готовые решения, такие как flex, bison, llvm и yacc. Библиотек, предназначенных для парсинга строго определённых языков, нашлось ещё больше (gumbo, jsoup, rapidjson, инструменты Qt и др.) Ни то, ни другое не входило в мои планы по написанию парсера своей разметки на C++ с использованием лишь стандартной библиотеки, поэтому моим источником знаний об искусстве парсинга вместо электронных ресурсов стали методички технических институтов. О том, как взять текст и построить из него AST (абстрактное синтаксическое дерево), о некоторых подводных камнях, на которые я натыкался в процессе, о возможных ошибках я сегодня и расскажу.
Сразу оговорюсь, — если ваша цель — свой скриптовый язык или что ещё сложнее, этой статьи будет недостаточно для его реализации. В идеале нужно на отлично знать теорию автоматов и дискретные структуры. Но в качестве отправной точки можно пока ограничиться и моим опытом, которым я щедро поделюсь под катом. Это не совсем то, что я задумывал изначально, зато идеально подходит для примера. Парсить мы будем HTML, как простой и всем знакомый язык.
Прежде всего, парсинг, или синтаксический разбор — не синоним полного процесса превращения текста в объектную модель. Сам процесс состоит из двух этапов:
Здесь одно выражение определено через три других, следующих одно за другим. Их, в свою очередь, тоже необходимо представить через «третьи» выражения и т.д.
Когда же остановиться?
Описание синтаксиса любого языка в формальных грамматиках состоит из двух типов лексем: терминалов и нетерминалов. Нетерминалы — выражения, требующие определения:
Терминалы самодостаточны, их не нужно определять. Выше приведённые примеры можно записать так:
где «+», «*», «/» — терминалы.
Выделить из грамматики терминалы нужно сразу, можно даже выписать их в отдельный список внизу основных определений, — они пригодятся позже.
Полное описание БНФ доступно в Википедии здесь и здесь. Составление грамматики языка — важная стадия создания языка, не терпящая легкомыслия. Одна ошибка в ней может привести к полностью нерабочему коду, который придётся переписывать с нуля. Поэтому, прежде чем делать следующий шаг, убедитесь, что в составленной грамматике не осталось спорных моментов. Если у вас два монитора, будет удобно на всё оставшееся время работы занять документом с грамматикой один монитор, чтобы иметь возможность быстро перемещаться глазами на него, когда будете кодить. Поверьте, так придётся делать постоянно. Вот составленная мной грамматика HTML5 в форме БНФ:
Когда грамматика готова, можно приступать к лексическому анализатору (другое название лексического разборщика, т.к. помимо разбора, он выявляет в документе лексические ошибки). На первый взгляд всё просто: поглощать символы, записывать в буфер и при обнаружении ключевого терминала определять полученную лексему как токен с определённым типом, так? Да, только тип токена здесь имеет большее значение, чем символ. Сейчас поясню. Само собой, процедура disassemble(ifsteam &file) должна содержать цикл, читающий по одному символу из входного потока и отправляющий его в процедуру process(const char &c), где этот символ обрабатывается. Кажется, что процедуре process нужно содержать switch©, где на каждый ключевой символ определены свои функции в зависимости от текущего типа токена. На самом деле всё наоборот: лучше с помощью switch проверять именно тип токена, а функции определять для символов. Более того, текущий токен чаще всего имеет неопределённый тип, один из многих. Например, после открытия угловой скобки может идти: открывающий, закрывающий, пустой теги, а также комментарий в стиле HTML или макро тег (сценарий PHP, заключённый в » «. И для всех таких объединений нужен свой case. Как такое реализовать? С помощью битовых флагов. Пусть задано конечное число типов токена (чем больше — тем лучше, так как задача лексического анализатора — оставить как можно меньше работы синтаксическому). Для каждого типа задано уникальное число степени двойки (1, 2, 4, 8 и т.д). Тогда в двоичном формате они будут выглядеть так: 0001, 0010, 0100 и т.д., и при побитовом сложении любого числа любых типов получится уникальное число. Если текстовое описание сложно для понимания, приведу код. Вот определение типов:
Урезанная процедура process:
Проверяем с помощью switch тип ожидаемого токена (или токенов), а внутри каждого case определяем процедуры для каждого из ключевых терминалов. Функций не так много, все выполняют простые действия: либо добавление символа к буферу, либо слив буфера в очередной токен, либо смену ожидаемого типа токена (токенов), либо выброс исключения. Определить нужную процедуру легко по написанной выше грамматике при помощи текстового редактора с возможностью поиска. Просто ищем все включения ожидаемого токена (токенов) в определения других выражений, затем включения этих выражений в «третьи» и т.д. Вот пример для открывающего тега в текстовом редакторе gedit:
Вначале ориентироваться в грамматике сложно, но со временем и опытом она становится не сложнее деления столбиком. А вот и процедура disassemble:
Первому ожидаемому токену очевидно необходимо задать тип TEXT, а в конце добавить токен типа END с любым текстом (или пустой, как здесь).
Для примера я взял один из своих шаблонов HTML-документа с комментарием, добавил к нему псевдо-скрипт PHP, обработал лексером и вывел список токенов в формате «[ » «: ]». Вот что получилось:
Теперь мы готовы приступить ко второй части — построению синтаксического дерева. Поскольку наши теги имеют аттрибуты, то узлы дерева кроме связи с другими узлами будут содержать массивы пар ключ-значение. Получившаяся конструкция сможет полноправно называться объектной моделью документа DOM, упомянутой в заголовке статьи.
Сколько нужно классов для реализации всех свойств HTML-элементов?
В идеале — по одному классу для каждого элемента, чтобы можно было определять для них каскадные таблицы стилей, но мы ограничимся тремя — пустым тегом «Node», унаследованным от него блоком «Block» (контент, заключённый между двумя парными тегами) и унаследованным от него корнем дерева «Root». Также определим в парсере массив тегов, которые могут содержать текст, такие, как
Вот и всё! Если вы всё сделали правильно, полученное дерево можно вывести на экран:
Однако, хотя полученное дерево действительно можно назвать DOM, до полноценных jQuery, Jsoup, beautifulsoup или Gumbo нашему парсеру далеко, в частности потому, что он не может правильно обрабатывать текст, расположенный между парными тегами и
PHP HTML DOM парсер с jQuery подобными селекторами
Добрый день, уважаемые хабровчане. В данном посте речь пойдет о совместном проекте S. C. Chen и John Schlick под названием PHP Simple HTML DOM Parser (ссылки на sourceforge).
Идея проекта — создать инструмент позволяющий работать с html кодом используя jQuery подобные селекторы. Оригинальная идея принадлежит Jose Solorzano’s и реализована для php четвертой версии. Данный же проект является более усовершенствованной версией базирующейся на php5+.
В обзоре будут представлены краткие выдержки из официального мануала, а также пример реализации парсера для twitter. Справедливости ради, следует указать, что похожий пост уже присутствует на habrahabr, но на мой взгляд, содержит слишком малое количество информации. Кого заинтересовала данная тема, добро пожаловать под кат.
Получение html кода страницы
Товарищ Fedcomp дал полезный комментарий насчет file_get_contents и 404 ответа. Оригинальный скрипт при запросе к 404 странице не возвращает ничего. Чтобы исправить ситуацию, я добавил проверку на get_headers. Доработанный скрипт можно взять тут.
Поиск элемента по имени тега
Модификация html элементов
Получение текстового содержания элемента (plaintext)
Целью статьи не является предоставить исчерпывающую документацию по данному скрипту, подробное описание всех возможностей вы можете найти в официальном мануале, если у сообщества возникнет желание, я с удовольствием переведу весь мануал на русский язык, пока же приведу обещанный в начале статьи пример парсера для twitter.
Пример парсера сообщений из twitter
Вывод сообщений
Благодарю за внимание. Надеюсь, получилось не очень тяжеловесно и легко для восприятия.
Класс DOMDocument
Введение
Представляет все содержимое HTML- или XML-документа; служит корнем дерева документа.
Обзор классов
Свойства
Объявление типа документа, соответствующее этому документу.
Удобный атрибут, предоставляющий прямой доступ к дочернему узлу, как к элементу документа.
Кодировка документа, как указано в объявлении XML. Этот атрибут отсутствует в последней спецификации DOM Level 3, но является единственным способом манипулирования кодировкой XML-документа в этой реализации.
Проприетарное свойство. Включает режим восстановления, то есть пытается разобрать некорректно составленные (non-well formed) документы. Этот атрибут не является частью спецификации DOM и специфичен для libxml.
Установите в true для загрузки внешних элементов из объявления типа документа. Может быть полезным при включении элементов с символьными данными в XML-документ.
Патентованное свойство. Указывает, заменять или нет элементы документа. Этот атрибут не является частью спецификации DOM и специфичен для libxml.
Включение замещения объекта может облегчить атаки на внешний объект XML (XXE).
Атрибут, определяющий, как часть XML-объявления, кодировку эту документа. Имеет значение null в случаях, когда атрибут не задан, либо значение неизвестно, если, например, документ создан в памяти.
Атрибут, определяющий, как часть XML-объявления, номер версии этого документа. Если объявления в документе нет, но есть поддержка всех особенностей «XML», значение равно «1.0».
Примечания
Модуль DOM использует кодировку UTF-8. Используйте utf8_encode() и utf8_decode() для работы с текстами в кодировке ISO-8859-1 или iconv для других кодировок.
При использовании json_encode() для объекта DOMDocument будет получен результат кодирования пустого объекта.
Смотрите также
Содержание
User Contributed Notes 17 notes
Showing a quick example of how to use this class, just so that new users can get a quick start without having to figure it all out by themself. ( At the day of posting, this documentation just got added and is lacking examples. )
// Set the content type to be XML, so that the browser will recognise it as XML.
header ( «content-type: application/xml; charset=ISO-8859-15» );
For those landing here and checking for encoding issue with utf-8 characteres, it’s pretty easy to correct it, without adding any additional output tag to your html.
We’ll be utilizing: mb_convert_encoding
Thanks to the user who shared: SmartDOMDocument in previous comments, I got the idea of solving it. However I truly wish that he shared the method instead of giving a link.
Anyway coming back to the solution, you can simply use:
//turning off some errors
libxml_use_internal_errors ( true );
// do whatever you want to do with this code now
?>
I hope it solves the issue for someone! If you need my help or service to fix your code, you can reach me on nabtron.com or contact me at the email mentioned with this comment.
Here’s a small function I wrote to get all page links using the DOMDocument which will hopefully be of use to others
// Create a new DOM Document to hold our webpage structure
$xml = new DOMDocument ();
// Empty array to hold all links to return
$links = array();
For anyone else who has been having issues with formatOuput not working, here is a work-around:
rather than just doing something like:
You may need to save all or part of a DOMDocument as an XHTML-friendly string, something compliant with both XML and HTML 4. Here’s the DOMDocument class extended with a saveXHTML method:
/**
* XHTML Document
*
* Represents an entire XHTML DOM document; serves as the root of the document tree.
*/
class XHTMLDocument extends DOMDocument <
?>
This hasn’t been benchmarked, but is probably significantly slower than saveXML or saveHTML and should be used sparingly.
A nice and simple node 2 array I wrote, worth a try 😉
For using safely with script nodes when parsing, best option is extending DOMDocument, keeping script tags while DOMDocument process and rearrange them just after saveHTML function is called. Here is my custom class.
Easy function for basic output of XML file via DOM parsing
Look out for the following gotcha when loading XML from a string:
It’s set to the current working directory. If you want to manually set documentURI to something other than the CWD, do so AFTER the call to loadXML().
This function may help to debug current dom element:
Instance of DOMNodeList, node list:
Item #0, XPath: /library/book[1]
Fahrenheit 451
R. Bradbury
Item #4, XPath: /library/book[5]
The Moon Is a Harsh Mistress
R. A. Heinlein
It’s possible to use in object style to retrieve information, as:
# First you load a XML in a DomDocument variable.
# Then, you get the ArrayNodes from the DomDocument.
So here it is: SmartDOMDocument. You can find it at http://beerpla.net/projects/smartdomdocument/
Currently, the main highlights are:
Парсер PHP XML DOM
Для чтения и изменения HTML и XML лучше всего подходит библиотека DOM, поскольку она автоматически создается вместе с некоторыми версиями PHP.
Парсер XML DOM
Парсер Dom очень хорошо справляется как с XML, так и с HTML-документами. Парсер XML DOM является встроенным в PHP.
Парсер Dom перемещается на основе дерева, а перед доступом к данным он загружает данные в объект dom и обновляет данные в веб-браузере.
XML-данные: пример древовидной структуры
Чтобы понять, как DOM просматривает XML-данные, давайте проанализируем следующий пример кода:
Пример
Данные XML, с точки зрения DOM, имеют древовидную структуру:
Свойства DOMDocument
Следующие свойства могут помочь вам найти информацию о вашем XML-документе:
Свойство | Описание |
---|---|
actualEncoding | Не рекомендуется. Это свойство только для чтения, представляющее кодировку документа. |
config | Не рекомендуется. Когда вызывается DOMDocument :: normalizeDocument (), применяется это свойство конфигурации. |
doctype | Представляет объявление типа документа, связанное с документом. |
documentElement | Предоставляет прямой доступ к дочерним узлам в документе. |
documentURI | Представляет расположение документа. Возвращает NULL, если местоположение не найдено. |
encoding | Представляет кодировку документа, указанную в объявлении XML. |
formatOutput | Помогает организовать вывод с необходимыми пробелами и отступами. |
implementation | Представляет объект DOMImplementation, который управляет документом. |
preserveWhiteSpace | Указывает не удалять лишние пробелы. |
recover | Собственный. Включает режим восстановления. Этот атрибут взят не из документации DOM, а из libxml. |
resolveExternals | Если установлено значение TRUE, этот атрибут загружает внешние сущности из объявления doctype. Это удобно для добавления символов в документы XML. |
standalone | Не рекомендуется. Указывает, является ли документ автономным. То же, что xmlStandalone. |
strictErrorChecking | Отображает DOMException при обнаружении ошибок. |
replaceEntities | Собственный. Указывает, следует ли заменять объекты. Он не является частью спецификации DOM и является уникальным для libxml. |
validateOnParse | Используется для загрузки и проверки на соответствие DTD. |
version | Не рекомендуется. Представляет версию XML. То же, что и xmlVersion. |
xmlEncoding | Указывает кодировку XML-документа. NULL, если кодировка не найдена. |
xmlStandalone | Указывает, является ли XML-документ автономным. FALSE, если эта информация не найдена. |
xmlVersion | Указывает номер версии XML-документа. Если объявление не найдено, но документ поддерживает XML, версия 1.0. |
XML-файл
Приведенный ниже XML-файл file.xml будет использоваться в нашем примере:
Пример
Как загрузить и вывести данные XML
Ниже приведен сценарий, который нам нужно будет использовать для инициализации анализатора XML:
Пример
Результат выполнения кода:
Вот шаги этого примера кода:
Примечание: Используя функцию saveXML(), мы помещаем внутренние данные XML в строку данных. После этого он будет готов к отображению.
Если вы выберете в окне браузера «Просмотр исходного кода», то увидите следующий HTML-код:
В приведенном выше примере создается объект DOMDocument и загружается в него XML из файла note.xml.
Затем функция saveXML() помещает внутренний XML-документ в строку, чтобы мы могли его вывести.
Выполнение циклов в файлах XML
Чтобы инициализировать синтаксический анализатор PHP XML, получить доступ к данным и затем выполнить итерацию, вы должны применить цикл foreach:
Пример
Вот результат, который мы получаем в таком случае:
Примечание: Обратите внимание, что в нашем примере между каждым элементом есть пустые текстовые узлы. Когда создается XML, он часто содержит пробелы между узлами. Парсер XML DOM рассматривает их как обычные элементы, и если вы о них не знаете, они иногда вызывают проблемы.
Как создать документ PHP DOMDocument, содержащий HTML
Давайте научимся создавать PHP DOMDocuments для изменения HTML-скрипта. В следующем примере кода показано, как создать документ PHP DOMDocument, содержащий HTML: