Парсинг сайтов с помощью PHP

Опубликовано 30 декабря 2022 в 17:16 (Обновлено 9 января 2024 в 14:12)

Время чтения: 17 мин

В этой статье мы подробно остановимся на парсинге веб-ресурсов с помощью языка программирования PHP.

PHP парсинг
PHP парсинг

Что такое парсинг

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

Происходит от английского слова parse - разобрать, разбор.

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

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

Что такое JSON

JSON означает JavaScript Object Notation (нотация объектов JavaScript). JSON - это стандартный облегченный формат обмена данными, который быстро и легко анализировать и генерировать.

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

  • Объект (Object): Определяется как набор пар ключ/значение (т.е. key:value). Каждый объект начинается с левой фигурной скобки { и заканчивается правой фигурной скобкой }. Несколько пар ключ/значение разделены запятой ,.
  • Массив (Array): Определяется как упорядоченный список значений. Массив начинается с левой скобки [ и заканчивается правой скобкой ]. Значения разделены запятой ,.

В JSON ключами всегда являются строки, а значением может быть строка, число, true или false, null или даже объект или массив. Строки должны быть заключены в двойные кавычки " и могут содержать экранирующие символы, такие как \n, \t и \. JSON объект может выглядеть так:

{
    "book": {
        "name": "Harry Potter and the Goblet of Fire",
        "author": "J. K. Rowling",
        "year": 2000,
        "genre": "Fantasy Fiction",
        "bestseller": true
    }
}

В то время как пример массива JSON будет выглядеть примерно так:

{
    "fruits": [
        "Apple",
        "Banana",
        "Strawberry",
        "Mango"
    ]
}
Формат обмена данными - это текстовый формат, который используется для обмена данными между различными платформами и операционными системами. JSON является наиболее популярным и легковесным форматом обмена данными для веб-приложений.

Структуры данных JSON очень похожи на массивы PHP. PHP имеет встроенные функции для кодирования и декодирования данных JSON. Этими функциями являются json_encode() и json_decode() соответственно. Обе функции работают только с строковыми данными в кодировке UTF-8.

Проверка ресурса HTTP

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

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

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

Чаще всего они будут пытаться загрузить ресурс, используя что-то вроде file_get_contents:

<?php

$resourceUrl = 'http://example.com/img/large-image-34.jpg';

$resourceExists = false;
if(file_get_contents($resourceUrl) !== false){
    $resourceExists = true;
}

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

Использование cURL

Одна из замечательных особенностей cURL заключается в том, что она имеет опцию CURLOPT_NOBODY, которая позволяет вам отправлять HEAD запрос:

Метод HEAD идентичен GET за исключением того, что сервер НЕ ДОЛЖЕН возвращать тело сообщения в ответе. Метаинформация, содержащаяся в заголовках HTTP в ответ на запрос HEAD ДОЛЖНА быть идентична информации, отправленной в ответ на запрос GET.

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

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

<?php

$resourceUrl = 'http://example.com/vid/large-video.mp4';
$resourceExists = false;

$ch = curl_init($resourceUrl);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_exec($ch);
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

// 200 = OK
if($statusCode == '200'){
    $resourceExists = true;
}

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

Кодирование JSON данных

В PHP функция json_encode() используется для кодирования значения в формат JSON.

Кодируемое значение может быть любым типом данных PHP, кроме ресурса, например, базы данных или дескриптора файла. В приведенном ниже примере показано, как кодировать ассоциативный массив PHP в объект JSON:

<?php
// ассоциативный массив
$marks = array("Peter"=>65, "Harry"=>80, "John"=>78, "Clark"=>90);
 
echo json_encode($marks);
?>

Вывод вышеприведенного примера будет выглядеть следующим образом:

{"Peter":65,"Harry":80,"John":78,"Clark":90}

Точно так же вы можете закодировать индексированный массив PHP в массив JSON, например так:

<?php
// индексированный массив
$colors = array("Red", "Green", "Blue", "Orange", "Yellow");
 
echo json_encode($colors);
?>

Вывод вышеприведенного примера будет выглядеть следующим образом:

["Red","Green","Blue","Orange","Yellow"]

Вы также можете заставить функцию json_encode() возвращать индексированный массив PHP как объект JSON, используя опцию JSON_FORCE_OBJECT, как показано в примере ниже:

<?php
// индексированный массив
$colors = array("Red", "Green", "Blue", "Orange");
 
echo json_encode($colors, JSON_FORCE_OBJECT);
?>

Вывод вышеприведенного примера будет выглядеть следующим образом:

{"0":"Red","1":"Green","2":"Blue","3":"Orange"}

Как вы можете видеть в приведенных выше примерах, неассоциативный массив может быть закодирован как массив или объект. Однако ассоциативный массив всегда кодируется как объект.

Декодирование JSON данных

Декодирование данных JSON так же просто, как и их кодирование. Вы можете использовать функцию PHP json_decode() для преобразования строки в кодировке JSON в соответствующий тип данных PHP. В следующем примере показано, как декодировать или преобразовать объект JSON в объект PHP.

<?php
// сохранение данных JSON в переменной PHP
$json = '{"Peter":65,"Harry":80,"John":78,"Clark":90}';
 
var_dump(json_decode($json));
?>

Вывод вышеприведенного примера будет выглядеть примерно так:

object(stdClass)#1 (4) { ["Peter"]=> int(65) ["Harry"]=> int(80) ["John"]=> int(78) ["Clark"]=> int(90) }

По умолчанию функция json_decode() возвращает объект. Однако можно дополнительно указать второй параметр $assoc, который принимает булевое значение, при котором при установке в качестве true JSON объекты декодируются в ассоциативные массивы. По умолчанию оно равно false. Приведем пример:

<?php
// сохранение данных JSON в переменной PHP
$json = '{"Peter":65,"Harry":80,"John":78,"Clark":90}';
 
var_dump(json_decode($json, true));
?>

Вывод вышеприведенного примера будет выглядеть примерно так:

array(4) { ["Peter"]=> int(65) ["Harry"]=> int(80) ["John"]=> int(78) ["Clark"]=> int(90) }

Теперь рассмотрим пример, который покажет, как декодировать JSON-данные и получить доступ к отдельным элементам JSON-объекта или массива в PHP.

<?php
// присвоение строки в кодировке JSON переменной PHP
$json = '{"Peter":65,"Harry":80,"John":78,"Clark":90}';
 
// декодировать JSON данные в ассоциативный массив PHP
$arr = json_decode($json, true);
// доступ к значениям из ассоциативного массива
echo $arr["Peter"];  // вывод: 65
echo $arr["Harry"];  // вывод: 80
echo $arr["John"];   // вывод: 78
echo $arr["Clark"];  // вывод: 90
 
// декодировать JSON данные в объект PHP
$obj = json_decode($json);
// доступ к значениям из возвращенного объекта
echo $obj->Peter;   // вывод: 65
echo $obj->Harry;   // вывод: 80
echo $obj->John;    // вывод: 78
echo $obj->Clark;   // вывод: 90
?>

Также можно перебирать декодированные данные, используя цикл foreach():

<?php
// присвоение строки в кодировке JSON переменной PHP
$json = '{"Peter":65,"Harry":80,"John":78,"Clark":90}';
 
// декодировать JSON данные в ассоциативный массив PHP
$arr = json_decode($json, true);
 
// цикл по ассоциативному массиву
foreach($arr as $key=>$value){
    echo $key . "=>" . $value . "<br>";
}
echo "<hr>";
// декодировать JSON данные в объект PHP
$obj = json_decode($json);
 
// перебираем объект в цикле
foreach($obj as $key=>$value){
    echo $key . "=>" . $value . "<br>";
}
?>

Извлечение вложенных данных

Объекты и массивы JSON также могут быть вложенными.

Объект JSON может произвольно содержать другие объекты JSON, массивы, вложенные массивы, массивы объектов JSON и т.д.

В следующем примере показано, как декодировать вложенный объект JSON и вывести все его значения в PHP. Весь блок кода содержит комментарии.

<?php
// Определение рекурсивной функции для извлечения вложенных значений
function printValues($arr) {
    global $count;
    global $values;
    
    // проверяем массив ли на входе
    if(!is_array($arr)){
        die("ERROR: Input is not an array");
    }
    
    /*
    Проходим по массиву, если значение само является массивом, рекурсивно вызываем функцию, иначе добавляем найденное значение в массив выходных элементов и увеличиваем счетчик на 1 для каждого найденного значения
    */
    foreach($arr as $key=>$value){
        if(is_array($value)){
            printValues($value);
        } else{
            $values[] = $value;
            $count++;
        }
    }
    
    // возвращаем суммарное количество и значения, найденные в массиве
    return array('total' => $count, 'values' => $values);
}
 
// присваиваем переменной PHP строку в кодировке JSON
$json = '{
    "book": {
        "name": "Harry Potter and the Goblet of Fire",
        "author": "J. K. Rowling",
        "year": 2000,
        "characters": ["Harry Potter", "Hermione Granger", "Ron Weasley"],
        "genre": "Fantasy Fiction",
        "price": {
            "paperback": "$10.40", "hardcover": "$20.32", "kindle": "4.11"
        }
    }
}';
// декодирование данных JSON в формате ассоциативного массива PHP
$arr = json_decode($json, true);
 
// Вызываем функцию и выводим все значения
$result = printValues($arr);
echo "<h3>" . $result["total"] . " value(s) found: </h3>";
echo implode("<br>", $result["values"]);
 
echo "<hr>";
 
// Выводим одиночные значения
echo $arr["book"]["author"] . "<br>";  // Output: J. K. Rowling
echo $arr["book"]["characters"][0] . "<br>";  // Output: Harry Potter
echo $arr["book"]["price"]["hardcover"];  // Output: $20.32
?>

Передача массивов в JSON и JS

Функция PHP json_encode преобразует переданные ей данные в строку JSON, которая затем может быть выведена в переменную JavaScript. В этом топике мы поработаем с одноуровневыми массивами, а в следующем материале мы разберем работы json_encode с многомерными массивами и скалярными значениями.

Функция PHP json_encode возвращает строку, содержащую JSON-эквивалент переданного ей значения, как показано на примере массива с числовым индексом:

<?php
$ar = array('apple', 'orange', 'banana', 'strawberry');
echo json_encode($ar); // ["apple","orange","banana","strawberry"]
?>

Вы можете передать строку JSON, выведенную json_encode, в переменную JavaScript следующим образом:

<script type="text/javascript">
// pass PHP variable declared above to JavaScript variable
var ar = <?php echo json_encode($ar) ?>;
</script>

Массив PHP с числовым индексом преобразуется в литерал массива в строке JSON. Опция JSON_FORCE_OBJECT может быть использована, если вы хотите, чтобы массив был выведен в виде объекта:

<?php
echo json_encode($ar, JSON_FORCE_OBJECT);
// {"0":"apple","1":"orange","2":"banana","3":"strawberry"} 
?>

Обратите внимание, что строка JSON не содержит пробелов, что может затруднить ее чтение. Для форматирования вывода JSON можно использовать опцию JSON_PRETTY_PRINT. Это продемонстрировано в примере с ассоциативным массивом ниже.

Функция json_encode также предоставляет другие возможности, которые перечислены и продемонстрированы в официальном руководстве PHP.

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

<?php
$ar = array('apple', 'orange', 1, false, null, true, 3 + 5);
?>
<script type="text/javascript">
var ar = <?php echo json_encode($ar) ?>;
// ["apple","orange",1,false,null,true,8];
// access 4th element in array
alert( ar[3] ); // false
</script>

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

В другом примере показан вывод ассоциативного массива PHP в JavaScript с помощью json_encode. Обратите внимание, что ассоциативный массив PHP становится объектным литералом в JavaScript:

<?php
$book = array(
    "title" => "JavaScript: The Definitive Guide",
    "author" => "David Flanagan",
    "edition" => 6
);
?>
<script type="text/javascript">
var book = <?php echo json_encode($book, JSON_PRETTY_PRINT) ?>;
/* var book = {
    "title": "JavaScript: The Definitive Guide",
    "author": "David Flanagan",
    "edition": 6
}; */
alert(book.title);
</script>

Мы используем опцию JSON_PRETTY_PRINT в качестве второго аргумента json_encode для отображения вывода в удобочитаемом формате.

Для доступа к свойствам объекта можно использовать точечный синтаксис, как показано в приведенном выше alert-е, или синтаксис квадратных скобок: book['title'].

Что насчет JSON.parse?

Возможно, вы заметили, что JSON.parse от JavaScript не был применен к результату в этом примере. Хотя не всегда необходимо прогонять результаты json_encode через парсер на стороне JavaScript, но возможно вы захотите это сделать. Мы больше раскроем тему о том, когда и как использовать JSON.parse в следующих топиках.

Преобразование в массивы

Преобразование объектов в массивы с помощью JSON Decode в PHP.

Преобразование объекта в массив в PHP упрощает доступ к данным из набора объектов. Большинство API выдают объект в качестве ответа.

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

Этот быстрый пример выполняет преобразование объекта в массив в PHP за один шаг. Он создает набор объектов и устанавливает их свойства.

Для преобразования используется функция JSON encode() decode(). Функция json_decode() передает булево значение true для получения выходного массива.

<?php
$object = new StdClass();
$object->id = 5678;
$object->name = "William";
$object->department = "CSE";
$object->designation = "Engineer";

$result = json_encode($object);
// converts object $result to array
$output = json_decode($result, true);

print "<pre>";
print_r($result);
?>

После "декодирования" выходной массив выводится в браузер. На скриншоте ниже показан вывод этой программы.

Справка PHP

Из официальной документации:

json_decode — Декодирует строку JSON

json_decode(
    string $json,
    ?bool $associative = null,
    int $depth = 512,
    int $flags = 0
): mixed

Принимает закодированную в JSON строку и преобразует её в переменную PHP.

Примечание. Подробнее про параметры функции см. в документации PHP.

Различные способы преобразования объекта PHP в массив

При преобразовании объекта в массив пары свойств объекта 'имя:значение' образуют ассоциативный массив.

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

Существует два способа преобразования объекта в массив в PHP.

  1. Приведение типа объекта к массиву.
  2. Кодирование и декодирование свойств объекта в массив элементов.

Приведение типов является простым методом преобразования типа входных данных. Второй метод применяет json_decode() к данному объекту. В качестве второго параметра он передает булево true для получения выходных данных в формате массива.

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

Преобразование объекта PHP в массив с помощью приведения типов

Это альтернативный метод преобразования типа объекта в массив. В приведенном ниже примере используется тот же входной объект.

Он заменяет преобразование JSON encode decode через оператор приведения типов. На выходе получится то же самое, что мы видели выше.

Синтаксис приведения типов в PHP показан ниже. Он добавляет целевой тип данных, заключенный в круглые скобки.

$output = (target-data-type) $input

В итоге:

<?php
$object = new StdClass();
$object->id = 5678;
$object->name = "William";
$object->department = "CSE";
$object->destination = "Engineer";

print"<pre>";
print_r( (array) $object );
?>

Рекурсивное преобразование объекта в массив

В этом примере используется входной объект с глубиной = 3. Он добавляет дополнительные свойства на вложенном уровне на разной глубине. Набор иерархических объектов устанавливается в качестве входных данных для процесса преобразования.

Эта программа определяет пользовательскую функцию для преобразования объекта PHP в массив. Она выполняет преобразование рекурсивно на каждом уровне входного объекта.

<?php
$object = new StdClass();
$object->id = 5678;
$object->name = "William";

$object->address = new stdClass();
$object->address->email = "William@gmail.com";

$object->address->billing = new stdClass();
$object->address->billing->zipcode = 9950;

$object->address->shipping = new stdClass();
$object->address->shipping->zipcode = 1234;

$object->address->state = "South Carolina";
$object->address->city = "Columbia";
$object->address->country = "US";

function objectToArray($object)
{
    foreach ($object as $k => $obj) {
        if (is_object($obj)) {
            $object->$k = objectToArray($obj);
        } else {
            $object->$k = $obj;
        }
    }
    return (array) $object;
}

$result = objectToArray($object);

print "<pre>";
print_r($result);
?>

Это вывод рекурсивного объекта PHP для программы преобразования массива, приведенной выше.

Преобразование объекта класса PHP в массив

В этом примере создается пакет объектов класса PHP. Конструктор класса устанавливает свойства объекта во время создания экземпляра.

Затем экземпляр класса Student кодируется для подготовки данных типа объекта. Функция json_encode() подготавливает объект JSON для предоставления его для декодирования, json_decode() преобразует объект PHP в массив.

<?php
class student
{
    public function __construct($id, $name, $state, $city, $country)
    {
        $this->id = $id;
        $this->name = $name;
        $this->state = $state;
        $this->city = $city;
        $this->country = $country;
    }
}

$student = new student("5678", "William", "South Carolina", "Columbia", "US");
$result = json_encode($student);
$output = json_decode($result, true);
print "<pre>";
print_r($output);
?>

Проверка is_object() перед преобразованием

Хорошей практикой программирования является проверка доступности данных перед обработкой. В этом примере применяется проверка is_object перед преобразованием объекта PHP в массив.

Этот метод проверяет, является ли входной файл объектом. PHP включает эксклюзивные функции для проверки наличия данных и их типов. Например, isset(), empty(), is_array() и т.д.

<?php

class student
{

    public function __construct($id, $name, $state, $city, $country)
    {
        $this->id = $id;
        $this->name = $name;
        $this->state = $state;
        $this->city = $city;
        $this->country = $country;
    }
}
$student= new student("5678", "William", "South Carolina", "Columbia", "US");

print "<pre>";
if (is_object($student)) {
    echo "Input Object:" . '<br>';
    $result = json_encode($student);
    print_r($result);
    $studentArray = json_decode($result, true);
}

if(!empty($studentArray) && is_array($studentArray)) {
    echo "<br><br>Output Array:" . '<br>';
    print_r($studentArray);
}
?>

Преобразование приватного, защищенного объекта класса

Приведенная ниже программа определяет класс с приватными и защищенными свойствами. PHP-код инстанцирует класс и создает связку объектов.

Справка. Инстанцирование (англ. instantiation) — создание экземпляра класса. В отличие от слова «создание», применяется не к объекту, а к классу.

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

При использовании метода приведения типа индекс выходного массива частного свойства содержит префикс имени класса. После преобразования индекс массива имеет префикс * для protected свойств.

<?php
class Student
{
    public $name;
    private $id;
    protected $email;
    
    public function __construct()
    {
        $this->name ="William";
        $this->id = 5678;
        $this->email = "william@gmail.com";
    }
}

print "<pre>";
$student = new Student;
$result = json_encode($student);
$output1 = json_decode($result, true);
print "<br/>Using JSON decode:<br/>";
print_r($output1);

$output2 = new Student;
print "<br/><br/>Using Type casting:<br/>";
print_r( (array) $output2 );
?>

Этот скриншот вывода показывает разницу в индексе массива. Они создаются из приватных и защищенных свойств экземпляра класса.

Доступ к свойствам объекта с помощью числовых ключей

Эта программа включает ассоциативный массив данных о студентах. Она также содержит значения с числовыми ключами.

При преобразовании этого массива в объект ключи ассоциативного массива используются для доступа к значениям свойств объекта. Существуют исключения для доступа к свойствам, если у них нет имени.

В приведенном ниже коде показано, как получить доступ к объектам с числовыми ключами. Ключ заключен в фигурные скобки {} для получения значения.

<?php
$inputArray = array(
    'name' => 'William',
    'email' => 'William@gmail.com',
    'phone' => '12345678',
    'REG5678'
);

$student = (object) array(
    'name' => 'William',
    'email' => 'William@gmail.com',
    'phone' => '12345678',
    'REG5678'
);
echo '<pre>' . print_r($student, true) . '</pre>';
echo '<br />' . $student->name;
echo '<br />' . $student->email;
echo '<br />' . $student->phone;
echo '<br />' . $student->{0};
?>

Мы рассмотрели различные способы преобразования объекта PHP в массив. Базовое приведение типов в PHP обеспечило преобразование объекта, за исключением нескольких особых случаев.

Процесс PHP JSON encode decode выполнил преобразование с помощью одной строки кода. Он принимает объекты класса и преобразует их свойства в список массивов.

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

Добавить комментарий

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

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.