CoderCastrov logo
CoderCastrov
Веб-разработка

Знакомство с парсингом веб-страниц и его реализация с использованием PHP

Знакомство с парсингом веб-страниц и его реализация с использованием PHP
просмотров
7 мин чтение
#Веб-разработка

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

Что такое парсинг веб-страниц?

Вкратце, парсинг веб-страниц - это процесс извлечения данных с веб-сайта.


Зачем нужен парсинг веб-страниц?

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

Как это реализовать?

Хорошо, чтобы реализовать парсинг веб-страниц, на самом деле мы можем использовать различные языки программирования, такие как Nodejs, Python, PHP и другие. Но здесь я буду использовать язык программирования PHP, поэтому нам понадобятся некоторые предварительные условия:

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

Мы будем извлекать данные об аниме и отображать их на создаваемом нами веб-сайте с другим дизайном. Давайте начнем!

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

GitHub - ariakm25/simple-php-starter: Простой стартовый шаблон для разработки проектов на PHP.

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

github.com

или клонируйте его с помощью git в командной строке:

git clone [https://github.com/ariakm25/simple-php-starter.git](https://github.com/ariakm25/simple-php-starter.git)

После загрузки проекта выполните следующую команду в папке проекта:

composer install

В этом проекте есть следующая структура папок:

- assets
- src 
  - Controllers
  - Helpers
  - Routes
  - Services
  - Views
  • Папка assets используется для размещения файлов ресурсов, таких как иконки, изображения, CSS, JavaScript и т. д.
  • Папка Controllers используется для размещения файлов контроллеров, которые содержат код для обработки данных и возврата запросов.
  • Папка Helpers используется для размещения файлов, содержащих повторно используемый код функций.
  • Папка Routes содержит файл Web.php, который содержит код для определения маршрута или URL страницы, к которой можно получить доступ.
  • Папка Services содержит файлы, предоставляющие данные для обработки в контроллере.
  • Папка Views содержит файлы для отображения пользовательского интерфейса.

Сначала создайте файл IndexController.php в папке Controllers и файл MALService.php в папке Services, которые затем заполним кодом для парсинга данных, которые мы хотим отобразить.

Содержимое папок Controller и Services

Затем в файле src/Routes/Web.php заполните следующим образом:

На строке 11 мы добавляем маршрут GET '/ ', что означает, что мы можем получить доступ к веб-сайту по URL / (например, domain.com**/**), и добавляем обработчик метода index в класс IndexController для этого маршрута.

Затем в файле IndexController.php заполните кодом ниже:

На строке 11 мы создаем ассоциативный массив с именем $args, который заполняется 'data' в качестве ключа и 'Hello World' в качестве значения. Затем на строке 12 метод index возвращает функцию render, которая включает файл index.php, находящийся в папке src/Views, и извлекает ассоциативный массив переменных $args, преобразуя ключи в переменные, чтобы мы могли получить значение 'Hello World' из ключа, преобразованного в переменную $data.

Затем в файле src/Views/index.php заполните кодом ниже:

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

php -S localhost:8080

После выполнения этой команды просто откройте URL http://localhost:8080/ в браузере. Если все прошло успешно, вы увидите следующее:

Отображение запущенного веб-сайта

Далее мы создадим сервис для парсинга данных с MyAnimeList. Мы будем использовать пакет с названием voku/simple_html_dom, который упростит извлечение и манипулирование HTML DOM, полученным с целевого веб-сайта, чтобы получить данные или значения, которые мы хотим получить. Чтобы добавить этот пакет в проект, выполните следующую команду в интерфейсе командной строки:

composer require voku/simple_html_dom

После установки пакета продолжим, добавив код в файл src/Services/MALService.php

<?phpnamespace App\Services;use voku\helper\HtmlDomParser;class MALService{
  // Базовый URL целевого веб-сайта
  private $baseTarget = 'https://myanimelist.net';  private function init($path)  {    $curl = curl_init($this->baseTarget . $path);    curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);    curl_setopt(
      $curl, 
      CURLOPT_USERAGENT, 
      'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13).  Gecko/20080311 Firefox/2.0.0.13'
    );    $html = curl_exec($curl);    curl_close($curl);    return HtmlDomParser::str_get_html($html);  }
}

В этом классе мы создаем метод init, который используется для получения всего HTML страницы целевого веб-сайта с использованием cURL на основе предоставленного пути в параметре функции. Метод возвращает абстрактный класс HtmlDomParser, чтобы мы могли манипулировать полученным HTML DOM с целевого веб-сайта.

Затем мы создаем новый публичный метод с именем getCurrentAnimeSeason()

public function getCurrentAnimeSeason() {  // Получаем HTML с url [https://myanimelist.net/anime/season](https://myanimelist.net/anime/season)
  $html = $this->init('/anime/season');  // Парсим HTML}

Для выполнения парсинга или извлечения HTML можно использовать следующий подход:

Сначала мы получим обертку div из данных, которые мы хотим получить, путем ввода селектора ID в функцию findOne() в HtmlDomParser.

Поиск селектора обертки div
public function getCurrentAnimeSeason() {  // Получаем HTML с url [https://myanimelist.net/anime/season](https://myanimelist.net/anime/season)
  $html = $this->init('/anime/season');  // Парсим HTML
  $wrapper = $html->findOne('#contentWrapper');}

Затем, чтобы получить название сезона, мы должны получить элемент anchor, который является child элементом элемента h1. Для этого мы можем написать селектор класса .season_nav и символ > для указания, что мы выберем селектор child после него, и это будет выглядеть так:

public function getCurrentAnimeSeason() {  // Получаем HTML с url [https://myanimelist.net/anime/season](https://myanimelist.net/anime/season)
  $html = $this->init('/anime/season');  // Парсим HTML
  $wrapper = $html->findOne('#contentWrapper');
  
  $data['seasonName'] = $wrapper->findOne('.season_nav > a')->innerText();}
Список типов аниме

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

Поиск селектора типа аниме
public function getCurrentAnimeSeason() {  // Получаем HTML с url [https://myanimelist.net/anime/season](https://myanimelist.net/anime/season)
  $html = $this->init('/anime/season');  // Парсим HTML
  $wrapper = $html->findOne('#contentWrapper');
  
  $data['seasonName'] = $wrapper->findOne('.season_nav > a')->innerText();_  // Получаем список типов аниме текущего сезона_  foreach ($wrapper->findMulti('.js-categories-seasonal > .seasonal-anime-list.js-seasonal-anime-list') as $index => $animeType) {    $typeName = $animeType->findOne('.anime-header')->innerText();    $data['list'][$index] = [      'typeName' => $typeName,      'animes' => []    ];  }}

На данный момент мы получили массив данных, содержащий типы аниме. Затем мы снова выполним цикл, чтобы получить данные аниме по типу и добавить их в массив 'animes'.

Парсинг данных аниме

Вот результат парсинга HTML для получения данных аниме:

public function getCurrentAnimeSeason(){  $html = $this->init('/anime/season');  $wrapper = $html->findOne('#contentWrapper');  $data['seasonName'] = $wrapper->findOne('.season_nav > a')->innerText();_  // Получаем список типов аниме текущего сезона  _foreach ($wrapper->findMulti('.js-categories-seasonal > .seasonal-anime-list.js-seasonal-anime-list') as $index => $animeType) {    $typeName = $animeType->findOne('.anime-header')->innerText();    $data['list'][$index] = [      'typeName' => $typeName,      'animes' => []    ];_    // Получаем список аниме для каждого типа    _foreach ($animeType->findMulti('.seasonal-anime.js-seasonal-anime') as $anime) {_      // Получаем жанры аниме.        _$genres = [];
      foreach ($anime->findMulti('.genres-inner > .genre') as $genre)     
      {
        $genreName = $genre->findOne('a')->innerText();
        _// Пропускаем 18+ аниме        _if (strtolower($genreName) == 'hentai') continue 2;
          $genres[] = $genreName;
      }_      // Получаем изображение аниме      _$image = $anime->findOne('.image > a > img')->getAttribute('data-src');
      $image = $image != null ? $image : $anime->findOne('.image > a > img')->getAttribute('src');_      // Данные аниме      _$data['list'][$index]['animes'][] = [        'title' => $anime->findOne('.h2_anime_title > a')->innerText(),        'url' => $anime->findOne('.h2_anime_title > a')->getAttribute('href'),        'image' => $image,        'score' => strip_tags($anime->findOne('.score.score-label')->innerText()),        'member' => strip_tags($anime->findOne('.member.fl-r')->innerText()),        'producer' => $anime->findOne('.producer > a')->innerText(),        'eps' => $anime->findOne('.eps > a > span')->innerText(),        'source' => $anime->findOne('.source')->innerText(),        'genres' => $genres      ];    }  }  return $data;}

Вот содержимое файла MALService.php

Затем давайте вызовем этот сервис в IndexController.php, а затем проверим данные, которые мы распарсили, в формате ответа JSON:

<?phpnamespace App\Controllers;use App\Helpers\View;use App\Services\MALService;class IndexController{  private $MALService;  public function __construct()  {    $this->MALService = new MALService();  }  public function index()  {    $args['data'] = $this->MALService->getCurrentAnimeSeason();    header('Content-Type: application/json');    echo json_encode($args['data'], JSON_PRETTY_PRINT);    die();_    // return View::render('index', $args);_  }
  public function notFound()  {    return View::render('404');  }}

Вот данные, которые мы распарсили и преобразовали в формат JSON:

Данные JSON, полученные при парсинге

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

Проект можно посмотреть в репозитории Github по следующей ссылке:

GitHub - ariakm25/anime_season_scraper

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

github.com

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

Хорошо, это все, что я хотел рассказать в этой статье. Извините, если я сделал какие-либо ошибки, пожалуйста, исправьте меня в комментариях.

Спасибо, надеюсь, что это будет полезно!

10518122 — Ариа Крисна Мурти Программа Системной Информации Факультет Техники и Компьютерных Наук Университет Компьютерных Наук Индонезии

Aria Krisna Murti - Medium

Читайте тексты от Aria Krisna Murti на Medium. Студент программы Системная информатика.

medium.com