Универсальный парсер контента php. Чтение файла в PHP. Выбираем оптимальный вариант. Как парсить зашифрованные данные


призывник 20 октября 2013 в 17:33

Парсер на PHP – это просто

  • PHP ,
  • Программирование

Вебмастеры часто сталкиваются с такой проблемой, когда нужно взять с какого-либо сайта определенную информацию и перенести ее на другой. Можно сначала сохранить информацию на промежуточный носитель, а уже с него загрузить куда-либо, но подобный подход не всегда удобен. В некоторых случаях гораздо быстрее залить парсер на сам сайт, поддерживающий PHP и запустить его удаленно, чтобы он автоматически спарсил информацию и загрузил ее в базу данных ресурса.
Среди уже готовых решений имеются популярные вроде Content Downloader и ZennoPoster, они конечно очень удобны и понятны любому человеку, даже незнакомому с программированием, однако имеют некоторые минусы. К примеру, они платные и не обладают достаточной гибкостью, которую можно вдохнуть в обычный php скрипт. Тем более, что разработка сложного парсера на них нисколько не уступает по времени написанию аналога на php.
Еще есть такая бесплатная вещь как iMacros – скриптовый язык, который может эмулировать действия пользователя в браузере, но тоже не везде такой подход работает лучшим образом.

Многие думают, что программирование, и уж тем более написание парсеров, – очень сложное занятие. На самом деле php – один из самых простых языков, изучить который можно на достаточном уровне за пару недель или месяц.
Парсеры тоже просты в написании, именно поэтому начинающие программисты пишут именно их, чтобы освоить язык.
Первое, что приходит на ум человеку, который решил написать подобный скрипт, - нужно использовать функции для работы со строками (strpos, substr и аналогичные) или регулярные выражения. Это совершенно верно, однако есть один нюанс. Если парсеров нужно будет писать много, то придется разрабатывать свою библиотеку, чтобы не переписывать сто раз одни и те же конструкции, но на это уйдет тонна времени, а учитывая то, что уже существуют аналогичные библиотеки, такое занятие и вовсе оказывается бессмысленным.
Идеальным вариантом для новичка станет изучение библиотеки PHP Simple HTML DOM Parser. Как можно догадаться из названия, она очень проста в освоении. Рассмотрим базовый код:

$html = file_get_html("http://www.yandex.ru");
$a_links = $html->find("a");

Первая строка создает объект страницы, источником которой в данном случае является Яндекс, и записывает в переменную $html, которая имеет несколько функций, например find. Find – ищет элемент по какому-либо параметру, например find (‘a’) – вернет массив всех ссылок страницы. Find(‘#myid’) – вернет массив элементов, id которых равен "myid".
Доступ к параметру href первой попавшейся ссылки осуществляется так:

Echo $a_links[ 0 ]->href;

Более подробно можно посмотреть на сайте:
simplehtmldom.sourceforge.net

Библиотека, как уже было сказано выше, очень проста и лучше всего подходит для начинающего программиста, плюс ко всему она работает достаточно быстро и не сильно требовательна к ресурсам сервера.
Есть у этой библиотеки один минус – далеко не все страницы ей оказываются по зубам. Если какой-либо элемент не отображается, но точно известно, что он там есть, лучше воспользоваться библиотекой DOM (Document Object Model). Она хороша во всем, кроме скорости разработки и понятности.

$doc = new DOMDocument();
$doc->loadHTML ($data);
$searchNodes = $doc->getElementsByTagName("a");
echo $searchNodes[ 0 ]->getAttribute("href");

Этот скрипт создает сначала объект типа DOM, при этом в переменной $data должен находиться код страницы. Затем находит все теги a (ссылки), с помощью вызова $doc->getElementsByTagName, затем записывает их в массив $searchNodes. Доступ к параметру href первой ссылки на странице осуществляется с помощью вызова $searchNodes[ 0 ]->getAttribute("href").
В итоге скрипт получается более громоздкий, и писать его уже не так удобно, но иногда приходится использовать именно эту библиотеку.

Теги: php, парсер, программирование

Задача спарсить и обработать необходимую информацию со стороннего сайта встает перед веб-разработчиком довольно часто и по самым разнообразным причинам: таким образом можно заполнять свой проект контентом, динамически подгружать какую-то информацию и так далее.

В таких случаях перед программистом встает вопрос: какую из десятков библиотек выбрать? В этой статье мы постарались рассмотреть самые популярные варианты и выбрать из них лучший.

Регулярные выражения

Даже не смотря на то, что «регулярки» - это первое, что приходит на ум, использовать их для настоящих проектов не стоит.

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

Вместо «допиливания» своего регулярного выражения при каждом малейшем изменении кода рекомендуем использовать инструменты ниже - это и проще, и удобнее, и надежнее.

XPath и DOM

htmlSQL

Если вы не используете PHP, то можете ознакомится с кратким списком похожих инструментов для других языков программирования.

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

Способов сделать это существует уйма – например, имеется мощная программа, предназначение которой парсить сайты, называется content downloader . Среди минусов ее то, что она десктопная, то есть, работать с ней придется либо со своего компьютера, либо с удаленного сервера. Само собой программа платная, так что придется еще и заплатить какую-то сумму денег, чтобы использовать ее (имеется несколько типов лицензий).

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

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

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

Что для этого требуется? Основные знания php, то есть умение работать с данными, хорошее владение синтаксисом, и опыт работы с библиотекой cURL .

Как же выдрать нужные данные со страницы? Сначала обязательно следует скачать саму страницу, например, с помощью библиотеки cURL, хотя можно воспользоваться и стандартной функцией file_get_contents, если хостинг поддерживает удаленное подключение через fopen. cURL к слову очень мощный инструмент для составления POST, GET запросов, использования прокси и вообще всего, чего только душе угодно, плюс установлен на любом хостинге практически.

Теперь данные нужно обработать, тут следует выбрать, каким образом выдирать информацию со страницы. Можно воспользоваться стандартными функциями php, вроде strpos, substr и т.д., но это настолько криво, что лучше об этом даже не думать.

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

Благо, что существуют уже готовые библиотеки, которые позволяют сосредоточиться непосредственно на работе со страницей, как с DOM (Document Object Model).

$doc = new DOMDocument(); $doc->loadHTML ($data);

Первая строчка создает объект, а вторая создает из обычных string данных (в которых должно находиться содержимое страницы) создает DOM.

$searchNodes = $doc->getElementsByTagName("a");

Теперь в переменной $searchNodes находится массив из найденных тегов "a".

Foreach ($searchNodes as $cur) { echo $cur->getAttribute("href"); }

А этот код выведет все значения полей href (обычно это адрес, куда попадает пользователь после нажатия на ссылку).

Более подробно с данной мощной библиотекой можно ознакомиться в официальной документации.

Но если вы хотите еще проще и удобней, то обратите внимание на библиотеку PHP Simple HTML DOM Parser. Она очень удобна и проста в освоении, разобраться, что к чему можно буквально за 10-15 минут, однако, с некоторыми типами данных она работает не слишком хорошо.

Существуют еще библиотеки, но эти две наиболее удобны и просты в освоении.


Для того, чтобы спарсить страницу сайта (то есть разобрать ее HTML код), ее для начала следует получить. А затем уже полученный код можно разобрать с помощью регулярных выражений и, либо каким-то образом его проанализировать, либо сохранить в базу данных, либо и то, и другое.

Получение страниц сайтов с помощью file_get_contents

Итак, для начала давайте поучимся получать страницы сайтов в переменную PHP. Это делается с помощью функции file_get_contents , которая чаще всего используется для получения данных из файла, однако, может быть использована для получения страницы сайта - если передать ей параметром не путь к файлу, а url страницы сайта.

Учтите, что эта функция не идеальна и существует более мощный аналог - библиотека CURL , которая позволяет работать с куками, с заголовками, позволяет отправлять формы и переходить по редиректам. Все это file_get_contents делать не умеет, однако для начала нам сойдет и она, а работу с CURL мы разберем в следующем уроке.

Итак, давайте для примера получим главную страницу моего сайта и выведем ее на экран (сделайте это):

Что вы получите в результате: у себя на экране вы увидите страницу моего сайта, однако, скорее всего без CSS стилей и картинок (будут ли работать CSS и картинки - зависит от сайта, почему так - разберем попозже).

Давайте теперь выведем не страницу сайта, а ее исходный код. Запишем его в переменную $str и выведем на экран с помощью var_dump :

Учтите, что var_dump должен быть настроен корректно в конфигурации PHP (см. предыдущий урок для этого). Корректно - это значит вы должны видеть теги и не должно быть ограничения на длину строки (код страницы сайта может быть очень большим и желательно видеть его весь).

Итак, если все сделано хорошо, и вы видите исходный код страницы сайта - самое время приступить к его парсингу с помощью регулярных выражений .

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

Должна быть включена директива allow_url_fopen http://php.net/manual/ru/filesystem.configuration.php#ini.allow-url-fopen

Парсинг с помощью регулярных выражений

При попытке разобрать HTML код с помощью регулярных выражений вас будут ждать некоторые подводные камни. Их наличие чаще всего связано с тем, что регулярные выражения не предназначены для разбора тегов - для этого есть более продвинутые инструменты, например библиотека phpQuery, которую мы будем разбирать в следующих уроках.

Однако, уметь использовать регулярные выражения для парсинга тоже важно - во-первых, регулярки это простой (если вы их уже знаете - то простой) и популярный инструмент для парсинга, во-вторых, регулярки работают на порядок быстрее, чем любые библиотеки (часто это критично), ну, и в-третьих, даже при использовании специальных библиотек нужда в регулярках все равно есть.

Подводные камни

Первая неожиданность, которая ожидает вас при использовании preg_match и preg_match_all - это то, что они работают только для тегов, целиком расположенных на одной строке (то есть, в них нету нажатого энтера). Если попытаться спарсить многострочный тег - у вас ничего не получится, пока вы не включите однострочный режим с помощью модификатора s . Вот таким образом:

Вторая неожиданность ждет вас, когда вы попробуете поработать с кириллицей - в этом случае нужно не забыть написать модификатор u (u маленькое, не путать с большим), вот так:

Какие еще подводные камни вас ждут - будем разбирать постепенно в течении данного урока.

Попробуем разобрать теги

Пусть мы каким-то образом (например, через file_get_contents ) получили HTML код сайта. Вот он:

Это заголовок тайтл Это основное содержимое страницы.

Давайте займемся его разбором. Для начала давайте получим содержимое тега , тега <head>, и тега <body>.</p> <p>Итак, получим содержимое тега <title> (в переменной <b>$str </b> хранится HTML код, который мы разбираем):</p> <p> <?php preg_match_all("#<title>(.+?)#su", $str, $res); var_dump($res); ?>

Содержимое :

(.+?)#su", $str, $res); var_dump($res); ?>

Содержимое :

(.+?)#su", $str, $res); var_dump($res); ?>

В общем-то ничего сложного нет, только обратите внимание на то, что как уголки тегов, так и слеш от закрывающего тега экранировать не надо (последнее верно, если ограничителем регулярки является не слеш /, а, например, решетка #, как у нас сейчас).

Однако, на самом деле наши регулярки не идеальны. При некоторых условиях они просто откажутся работать . Вы должны быть готовы к этому - сайты, которые вы будете парсить - разные (часто они еще и устаревшие), и то, что хорошо работает на одном сайте, вполне может перестать работать на другом.

Что же у нас не так? На самом деле тег - такой же тег, как и остальные и в нем вполне могут быть атрибуты. Чаще всего это атрибут class , но могут быть и другие (например, onload для выполнения JavaScript).

Итак, перепишем регулярку с учетом атрибутов:

(.+?)#su", $str, $res); var_dump($res); ?>

Но и здесь мы ошиблись, при чем ошибок несколько. Первая - следует ставить не плюс + , а звездочку * , так как плюс предполагает наличия хотя бы одного символа - но ведь атрибутов в теге может и не быть - и в этом случае между названием тега body и уголком не будет никаких символов - и наша регулярка спасует (не понятно, что я тут написал - учите регулярки).

Поправим эту проблему и вернемся к дальнейшему обсуждению:

(.+?)#su", $str, $res); var_dump($res); ?>

Вторая проблема следующая: если внутри будут другие теги (а так оно и будет в реальной жизни) - то наша регулярка зацепит лишнего. Например, рассмотрим такой код:

Это заголовок тайтл

Регулярка найдет не , как ожидалось, а

Абзац{

} - потому что мы не ограничили ей жадность. Сделаем это: место напишем - в этом случае будет все хорошо.

Но более хорошим вариантом будет написать вместо точки конструкцию [^>] (не закрывающий уголок ), вот так - ]*?> - в этом случае мы полностью застрахуем себя от проблем такого рода, так как регулярка никогда не сможет выйти за тег.

Получение блока по id

Давайте рассмотрим следующий код:

Это заголовок тайтл

Контент
Еще див

Напишем регулярку, которая получит содержимое блока с id, равным content .

Итак, попытка номер один (не совсем корректная):

#(.+?)

#su

Что здесь не так? Проблема с пробелами - ведь между названием тега и атрибутом может быть сколько угодно пробелов, так же, как и вокруг равно в атрибутах.

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

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

Давайте поправим нашу регулярку:

#

(.+?)
#su

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

Кроме того, перед закрывающем уголком тега тоже могут быть пробелы (а могут и не быть) - учтем и это:

#(.+?)

#su

Итак, уже лучше, но еще далеко не идеал - ведь вокруг атрибута id могут быть и другие атрибуты, например так:

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

#

(.+?)
#su

Обратите внимание, что после

стоит регулярка .+? , а перед > стоит регулярка .*? - это не ошибка, так и задумано, ведь после
обязательно должен идти пробел (то есть хотя бы один символ точно будет), а перед > может вообще не быть других атрибутов (кроме нашего id) и пробела тоже может не быть.

Регулярка стала еще более хорошей, но есть проблема: лучше не использовать точку в блоках типа .*? - мы вполне можем хватануть лишнего выйдя за наш тег (помните пример выше с body?). Лучше все-таки использовать [^>] - это гарантия безопасности:

#

]+? id\s*?=\s*?"content" [^>]*? >(.+?)
#su

Следующая проблема: кавычки-то в атрибутах могут быть как одинарными, так и двойными (их даже может вообще не быть, если значение атрибута - одно слово, но этот случай редкий - не будем его учитывать, если вам встретится такой сайт - проще написать регулярку специально для него). Итак, учтем это:

#]+?id\s*?=\s*? ["\"] content ["\"] [^>]*?>(.+?)

#su

Обратите внимание на то, что одинарная кавычка заэкранирована - мы это делаем, так как внешние кавычки от строки PHP у нас тоже одинарные, вот тут:

В общем-то регулярка достаточно хороша, но иногда идут дальше и делают так, чтобы первая кавычка от тега совпадала со второй (исключаем вариант id="content"). В этом случае делают так - первая кавычка ложится в карман, а вторая кавычка указывается карманом, чтобы совпадала с первой:

#]+?id\s*?=\s*? (["\"]) content \1 [^>]*?>(.+?)

#su

Для нашей задачи это особо не нужно (можно быть точно уверенным, что такое id="content" - врядли где-то будет), но есть атрибуты, где это существенно. Например, в таком случае:

- в атрибуте title вполне может затесаться одинарная кавычка и регулярка title\s*?=\s*?["\"](.+?)["\"] вытянет текст "Рассказ о д " - потому что поиск ведется до первой кавычки.

А вот регулярка title\s*?=\s*?(["\"])(.+?)\1 будет корректно обрабатывать

и даже
.

Проблема вложенных блоков

В нашей регулярке есть еще одна проблема - она не может работать с вложенными блоками. Например, если внутри дива #content есть еще один див - регулярка найдет текст до первого закрывающего

, а не для закрывающего дива для #content. Пример проблемного кода:

Это заголовок тайтл

Див внутри контента
Контент

Наша регулярка вытянет только

Див внутри контента
- остановится на первом же
. Что делать в этом случае?

Что делать в этом случае? Во-первых, к этому случаю всегда нужно быть готовым - даже если на исследуемых страницах сайта нет вложенных блоков - они вполне могут быть и на других страницах или появиться потом (если сайт парсится не один раз, а периодически).

Ну, а что делать - нужно просто привязываться не к

, а к тому, что стоит под нашим блоком (в нашем случае под контентом). В приведенном ниже коде под ним стоит


2024 © uzbek-seks.ru.