Содержание

Пишем php парсер сайтов с нуля

Опубликовано: 13.02.2015 12:48

Просмотров: 58509

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

Парсер на php — раз плюнуть!

Приветствую вас, наши дорогие читатели. Сегодня решил написать сложную статью про парсеры (сбор информации со сторонних ресурсов).

Скажу сразу, что вам потребуется знание основ программирования на php. В противном случае почитайте теории. Я не буду рассказывать азы, а сразу полезу показывать всё на практике.

Шаг 1 — PHP Simple HTML DOM Parser

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

  1. Скачиваем нужную страницу сайта
  2. Разбираем её по элементы (div, table, img и прочее)
  3. В соответствии с логикой получим определённые данные.

Давайте же начнём написание нашего php парсера сайтов.

Для начала подключим нашу библиотеку с помощью следующей строки кода:

include 'simple_html_dom.php';

Шаг 2 — Скачиваем страничку

На этом этапе мы смогли подключить файл к проекту и теперь пришла пора скачать страничку для парсинга.

В нашей библе есть две функции для получения удалённой страницы сайта. Вот эти функции

  1. str_get_htm() — получает в качестве параметров обычную строку. Это полезно, если вы стянули страничку с помощью CURL или метода file_get_contents. Пример использования: 
    $seo = str_get_html('<html>Привет, наш любимый читатель блога SEO-Love.ru!</html>')

     

  2. file_get_html() — здесь же мы передаём в качестве параметра какой-то url, с которого нам потребуется скачать контент. 
  3. $seo = file_get_html('http://www.site.ru/');

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

$seo = file_get_html('http://www.site.ru/');
$seo->clear();

Шаг 3 — Ищем нужные элементы на странице

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

Большая часть функций поиска использует метод find(selector, [index]). Если не указывать индекс, то функция возвратит массив всех полученных элементов. В противном случае метод вернёт элемент с номером [index].

 Давайте же приведу вам первый пример. Спарсим мою страничку и найдём все картинки.

1

2

3

4

5

6

7

8

9

10

11

12

//подключили библиотеку
require_once 'simple_html_dom.php';
//скачали страничку
$page = file_get_html('http://xdan.ru');
//проверка нашли ли хотя бы 1 блок img и не пустая ли страница
if($page->innertext!='' and count($data->find('img'))){
  //для всех элементов найдём элементы img
  foreach($data->find('img') as $img){
    //выведем данный элемент
    echo $a->innertext;
  }
}

 

Если что-то пошло не так, то прошу отписаться в комментариях. Здесь очень кстати будет мой предыдущий материал Запутываем PHP-код без зазрения совести. Полезно для тех, кто программирует как ниндзя. Больше не отвлекаюсь, идём дальше.

Шаг 4 — Параметры поиска

Надеюсь все уже поняли, что в метод find() можно писать как теги (‘a’), так и id’шники (‘#id’), классы (‘.myclass’), комбинации из предыдущих элементов (‘div #id1 span .class’). Таким образом вы сможете найти любой элемент на странице.

Если метод поиска ничего не найдёт, то он возвратит пустой массив, который приведёт к конфликту. Для этого надо указывать проверку с помощью фукнции count(), которую я использовал выше в примере.

Также вы можете производить поиск по наличию атрибутов у искомого элемента. Пример:

//Найдём все изображения с шириной 300
$seo->find('img[width=300px]');
//Найдём изображения, у которых задана ширина
$seo->find('img[width]');
//Поиск по наличию нескольких классов
$seo->find('img[class=class1 class2]');//<img class="aclass1 class2"/>
//Ищем несколько тегов вместе
$seo->find('div, span, img, a');
//Поиск по вложенности.
//В div ищем все спаны, а в спанах ссылки
$html->find('div span a');

Замечу, что у каждого вложенного тега так же есть возможность поиска!

Есть много вариантов поиска по атрибутам. Перечислять не стану, для более полного руководства прошу пройти на сайт разработчиков 🙂

Обычный текст, без тегов и прочего, можно искать так find(‘text’). Комментарии аналогично find(‘comment’).

Шаг 5 — Поля элементов

Каждый найденный элемент имеет несколько структур:

  1. $seo->tag   Прочитает или запишет имя тега искомого элемента.
  2. $seo->outertext   Прочитает или запишет всю HTML-структуру элемента с ним включительно.
  3. $seo->innertext
      Прочитает или запишет внутреннюю HTML-структуру элемента.
  4. $seo->plaintext   Прочитает или запишет обычный текст в элементе. Запись в данное поле ничего не поменяет, хоть возможность изменения как бы присутствует.

Примеры:

$seo = str_get_html("<div>first word <b>second word</b></div>");
echo $seo; // получим <div>first word <b>second word</b></div>, т.е. всю структуру
$div = $seo->find("div", 0);
echo $div->tag; // Вернет: "div"
echo $div->outertext; // Получим <div>first word <b>second word</b></div>
echo $div->innertext; // Получим first word <b>second word</b>
echo $div->plaintext; // Получим first word second word 

Эта возможность очень просто позволяет бегать по DOM-дереву и перебирать его в зависимости от ваших нужд.

Если вы захотите затереть какой-либо элемент из дерева, то просто обнулить значение outertext, т.е. $div->outertext = «»; Можно поэксперементировать с удалением элементов.

P.S. Я обнаружил проблему с кодировками при очистке и всяческими манипуляциями с полем innertext. Пришлось использовать outertext и затем с помощью функции strip_tags удалял ненужные теги.

Шаг 6 — Дочерние элементы

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

  1. $seo->children ( [int $index] )   Возвращает N-ый дочерний элемент, иначе возвращает массив, состоящий из всех дочерних элементов.
  2. $seo->parent()   Возвращает родительский элемент искомого элемента.
  3. $seo->first_child()   Возвращает первый дочерний элемент искомого элемента, или NULL, если результат пустой
  4. $seo->last_child()   Возвращает последний дочерний элемент искомого элемента, или null, если результат пустой
  5. $seo->next_sibling()   Возвращает следующий родственный элемент искомого элемента, или null, если результат пустой
  6. $seo->prev_sibling()   Возвращает предыдущий родственный элемент искомого элемента, или null, если результат пустой

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

Шаг 7 — Практика

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

public function parser_rock_txt() {
        $i = 0;
        $new_songs = 0;
        //номер категории, чтобы хранить в базе. У меня Рок = 1
        $category = 1;
  		//Скачиваем страничку с сайта Rock-Txt.ru
        $data = file_get_html('http://rock-txt.ru/');
        //нашли хотя бы одну ссылку на песни по буквам (проходим навигацию)
        if (count($data->find('div.a-z a'))) {
            //пробежим по всей навигации
            foreach ($data->find('div.a-z a') as $a) {
                //Выводим букву, которую парсим
                echo ('Текущая буква - ' . $a->plaintext . '<br />');
                //нашли список всех исполнителей
                $data_vocalist = file_get_html("http://rock-txt.ru" . $a->href);
                //если есть хотя бы один исполнитель
                if (count($data_vocalist->find('#dle-content div.full-news a'))) {
                    foreach ($data_vocalist->find('#dle-content div.full-news a') as $vocalist) {
                        //приводим название исполнителя к нижнему регистру
                        $vocalist->plaintext = mb_strtolower((mb_convert_encoding(($vocalist->plaintext), 'utf-8', mb_detect_encoding(($vocalist->plaintext)))), 'UTF-8');
                        //получаем id исполнителя из моей базы
                        $id_vocalist = $this->songs_model->check_vocalist(trim($this->db->escape($vocalist->plaintext)), trim($this->db->escape($this->translit($vocalist->plaintext))), $category);
                        //Нашли все песни исполнителя
                        $data_songs = file_get_html($vocalist->href);
                        //если есть хотя бы одна песня такого исполнителя - идём дальше
                        if (count($data_songs->find('#dle-content div.left-news-band a'))) {
                            foreach ($data_songs->find('#dle-content div.left-news-band a') as $songs) {
                                //Получим название песни. Удалим название исполнителя.
                                $name_song = substr(preg_replace('/\s\s+/', ' ', $songs->plaintext), strlen(trim($vocalist->plaintext)) + 1);
                                $name_song = trim($name_song);
                                //приводим название песни в нижний регистр
                                $name_song = mb_strtolower((mb_convert_encoding(($name_song), 'utf-8', mb_detect_encoding(($name_song)))), 'UTF-8');
                                //Транслитизируем название песни (моя самописная функция)
                                $name_song_translit = $this->translit($name_song);
                                //Отсекаем все пустые названия
                                if ($name_song == '' || $name_song_translit == '')
                                    continue;   
                                //Проходим по всем страницам навигации (пейджер, постраничная навигация)
                                $num_page = 0;
                                foreach ($songs->find('div.navigation a') as $num) {
                                    //если число - сравниваем, а не нашли ли мы ещё одну страницу навигации
                                    if (is_int($num->plaintext)) {
                                        if ($num->plaintext > $num_page)
                                            $num_page = $num->plaintext;
                                    }
                                }
                                echo $num_page . '<br />';
                                //загрузим текст песни
                                $text_songs = file_get_html($songs->href);
                                if (count($text_songs->find('div.full-news-full div[id] p'))) {
                                    foreach ($text_songs->find('div.full-news-full div[id] p') as $text_song) {
                                        //очищаем всякие ненужны ссылки и спаны
                                        foreach ($text_song->find('span') as $span) {
                                            $span->outertext = '';
                                        }
                                        foreach ($text_song->find('a') as $a) {
                                            $a->href = '';
                                            $a->outertext = '';
                                        }
                                        //выводим исполнителя, песню и текст
                                        echo $name_song . '<br />';
                                        echo $songs->href . '<br />';
                                        echo $text_song->outertext . '<br />';
                                        $text_song->outertext = preg_replace("/(<br[^>]*>\s*)+/i", "<br />", $text_song->outertext, 1);
                                        //вставляю в мою базу текст песни и исполнителя (самописная функция)
                                        $result = $this->songs_model->check_song(trim($this->db->escape($name_song_translit)), trim($this->db->escape($name_song)), trim($this->db->escape($id_vocalist)), trim($this->db->escape_str(preg_replace("#(:?<br />){2,}#i", "<br />", strip_tags($text_song->outertext, '<br /><br><b><strong><p>')))));
                                        //если добавили - увеличим счётчик новых песен
                                        if ($result != -1) {
                                            $new_songs++;
                                        }
                                        $i++;
                                        //выйдем, тут всякие косяки бывают
                                        break;
                                    }
                                }
                                //теперь аналогично пробегаем по остальным страницам
                                if ($num_page > 0) {
                                    $text_songs = file_get_html($songs->href . 'page/' . $num_page);
                                    if (count($text_songs->find('div.full-news-full div[id] p'))) {
                                        foreach ($text_songs->find('div.full-news-full div[id] p') as $text_song) {
                                            foreach ($text_song->find('span') as $span) {
                                                $span->outertext = '';
                                            }
                                            foreach ($text_song->find('a') as $a) {
                                                $a->href = '';
                                                $a->outertext = '';
                                            }
                                            echo $name_song . '<br />';
                                            echo $songs->href . '<br />';
                                            echo $text_song->outertext . '<br />';
                                            $text_song->outertext = preg_replace("/(<br[^>]*>\s*)+/i", "<br />", $text_song->outertext, 1);
                                            $result = $this->songs_model->check_song(trim($this->db->escape($name_song_translit)), trim($this->db->escape($name_song)), trim($this->db->escape($id_vocalist)), trim($this->db->escape_str(preg_replace("#(:?<br />){2,}#i", "<br />", strip_tags($text_song->outertext, '<br /><br><b><strong><p>')))));
                                            if ($result != -1) {
                                                $new_songs++;
                                            }
                                            $i++;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return "<br />Парсер сайта rock-txt.ru завершён. Спарсено песен всего " . $i . ", из них новых " . $new_songs . " ";
    }

 Получилась вот такая здоровая функция, которая парсит тексты песен с сайта о роке. Написал её я за час. Спарсил 10 000 текстов песен. Думаю, что руками вы бы набивали такую базу очень и очень долго 🙂

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

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

Всего доброго! Ретвиты, лайки и репосты приветствуются!

Если статья была для Вас полезной — Поделитесь ссылкой!

Советуем почитать

Закрепленные

Понравившиеся

seo-love.ru

Многопоточный парсинг на PHP | Трепачёв Дмитрий

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

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

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

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

Разделение потоков

Пусть скрипт, который осуществляет парсинг, называется parser.php. Мы можем запускать его с разными GET параметрами, разделяя разные потоки. Например: parser.php?num=1, parser.php?num=2 и так далее.

Самое простое, что мы можем сделать — открыть этот скрипт в нескольких вкладках браузера с разными GET параметрами, тем самым запустив несколько копий этого PHP скрипта.

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

Теперь нам надо разделить обязанности копий скрипта — указать каждой копии, что именно она должна парсить. Это разделение обычно зависит от структуры того сайта, который мы парсим.

Самое простое, что можно сделать, это разделить потоки по главному меню сайта: каждый пункт — отдельный поток.

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

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

Затем в дело вступают потоки. Запускаем столько потоков, сколько нам нужно. Каждый поток перед запуском берет из таблицы одну запись из БД, помечает в специальном поле, что эта ссылка в обработке, и начинает парсить страницу по ссылке. Следующий поток берет следующую незанятую запись из БД, помечает ее занятой, парсит ее и так далее.

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

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

Особенность браузеров

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

Это связано с устройством браузеров — они разрешают одновременно для одного сайта обрабатывать 6-10 запросов и ничего с этим не сделать. Пока эти запросы не будут выполнены — остальные ожидают.

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

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

Автоматически запускаем потоки

Представим, что вы бы хотели запустить парсинг в 50 потоков. Не очень удобно открывать 50 вкладок в браузере.

Если попытаться, например, обратиться к 50 страницам через PHP, например, через file_get_contents или через CURL, то 50 потоков запустить не получится, так как PHP скрипт будет ждать окончания загрузки file_get_contents.

Нужно нечто асинхронное, например сокеты или AJAX.

Давайте откроем 50 потоков с помощью AJAX. Будем каждый поток запускать с таймаутом так, чтобы каждый поток запускался на секунду позже предыдущего — в этом случае мы обойдем ограничение на открытие 6-10 страниц в браузере:

var count = 50;
var url = 'http://paser.php';

for (var i = 1; i 

Как это работает: первый поток имеет задержку timeout: 1000 милисекунд — одну секунду. Если страница не ответит за это время (а она не ответит, так как парсинг длится дольше), то загрузка оборвется. Второй поток имеет задержку timeout: 1000*2 = 2000 — 2 секунды. Ну и так далее.

Самое главное — нужно настроить в PHP ignore_user_abord — в этом случае AJAX будет запускать поток, обрывать загрузку — но PHP скрипт все равно будет работать, несмотря на то, что браузер уже оборвал загрузку.

Настройки сервера

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

Многопоточные запросы CURL

Изучите это, это и это.

Запуск нескольких процессов на PHP

Добавлю попозже.

Настоящие потоки на PHP

Изучите это: настоящие потоки, модуль php, еще.

Что вам делать дальше:

Приступайте к решению задач по следующей ссылке: задачи к уроку.

Когда все решите — переходите к изучению новой темы.

code.mu

Автоматизация парсинга на PHP | Трепачёв Дмитрий

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

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

Логи при парсинге

Совет: ведите логи при парсинге. Создайте отдельную таблицу в базу данных, в которую парсер будет записывать все свои действия: «Зашел на такую-то страницу», «Начал парсить такую-то категорию» и так далее — любые действия парсера.

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

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

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

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

Еще совет: парсер лучше сразу начинать делать с логами, а не тогда, когда куча проблем заявит о себе — ведь тогда интегрировать логи будет гораздо сложнее и затратнее по времени.

Еще совет: автоматически очищайте таблицу с логами перед новым парсингом (sql команда TRUNCATE).

Кеш при парсинге

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

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

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

Принцип такой: при запросе определенного URL проверяется — есть такой URL и такая страница в вашей базе или нет. Если есть — тянем ее из базы, а если нет — тянем ее из интернета, сохраняем в кеш — и в при следующем обращении эта страница возьмется уже из базы.

Сохранение при обрыве

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

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

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

Поэтому хотелось бы иметь возможность сохранения и возобновления парсинга с места обрыва.

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

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

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

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

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

Автоматический запуск парсера в браузере

TODO: ссылки на плагин для хрома.

Размещение парсера в интернете

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

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

Хостинг. Преимущества: удобно запускать периодический парсинг, можно купить несколько ip для обхода защиты от парсинга (может быть дороговато). Недостатки: платно, статичный ip легко могут забанить при парсинге.

Если ваш парсер будет размещаться в интернете — то обычный хостинг вам не подойдет, так как на нем стоит ограничение по времени выполнения PHP скрипта. Вам нужен выделенный сервер или виртуальный выделенный сервер VDS. Во первом случае вы получите целый компьютер-сервер с свое пользование (дорого), во втором случае — часть компьютера (дешевле).

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

Работа с cron

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

Если вы заведете себе VDS — в настройках вы обязательно увидите вкладку Cron, перейдя на которую вы сможете запускать скрипты по расписанию. Это несложно — залезьте в настройки — вы все увидите.

Предупреждение: не следует запускать кроном урлы своего сайта — вы легко можете подвесить свой сервер. Запускайте файлы своего скрипта.

Настройки PHP

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

Команда ini_set(‘max_execution_time’, ‘10000’) устанавливает время выполнения скрипта PHP в секундах (по умолчанию оно очень мало — около минуты). Ставьте побольше.

Функция set_time_limit(0) отменяет ограничение на время выполнения скрипта. Используйте вместе с предыдущей командой.

Команда ini_set(‘memory_limit’, ‘2048M’) устанавливает лимит оперативной памяти, выделяемой на скрипт. Ставьте побольше.

Функция ignore_user_abort(true) делает так, чтобы даже если в браузере оборвут скрипт — он продолжался дальше. Значение false отменяет это это поведение.

Что вам делать дальше:

Приступайте к решению задач по следующей ссылке: задачи к уроку.

Когда все решите — переходите к изучению новой темы.

code.mu

Php — Парсер На Php Это Легко (начинающим ) | Prime Seo Tools

  • <?php

  • // Ищем все гиперссылки,

  • // возвращаем массив объектов

  • $ret = $html->find(‘a’);

  •  

  • // Ищем N-ю гиперссылку, возвращаем объект

  • // или null если ничего не найдено

  • $ret = $html->find(‘a’, 0);

  •  

  • // Ищем все <div> с атрибутом id=foo

  • $ret = $html->find(‘div[id=foo]’);

  •  

  • // Ищем все <div> с id атрибутом

  • $ret = $html->find(‘div[id]’);

  •  

  • // Ищем все элементы с атрибутом  id

  • $ret = $html->find(‘[id]’);

  • // Ищем все элементы, где id = foo

  • $ret = $html->find(‘#foo’);

  •  

  • // Ищем все элементы, где class = foo

  • $ret = $html->find(‘.foo’);

  •  

  • // Ищем все гиперссылки и изображения

  • $ret = $html->find(‘a, img’);

  •  

  • // Ищем все гиперссылки и изображения с атрибутом «title»

  • $ret = $html->find(‘a[title], img[title]’);

  • // Ищем все <li> в <ul>

  • $es = $html->find(‘ul li’);

  •  

  • // Ищем вложенные теги <div>

  • $es = $html->find(‘div div div’);

  •  

  • // Ищем все <td> в <table> где class = hello

  • $es = $html->find(‘table.hello td’);

  •  

  • // Ищем все теги <td> с атрибутом align = center в таблице

  • $es = $html->find(‘table td[align=center]’);

  •  

  • // Ищем все <li> в <ul>

  • foreach($html->find(‘ul’) as $ul)

  • {

  •         foreach($ul->find(‘li’) as $li)

  •         {

  •               // что-то делаем…

  •         }

  • }

  •  

  • // Ищем первое <li> в первом <ul>

  • $e = $html->find(‘ul’, 0)->find(‘li’, 0);

  • ?>

  • ucbit.net

    Бесплатный PHP парсер сайтов на PhantomJS

    Опубликовано: 08.06.2016 13:38

    Просмотров: 21328

    Решил Вам предоставить информацию, которая поможет спарсить ЛЮБОЙ сайт. Теперь КАЖДЫЙ сможет парсить всё, что душе угодно. К тому же написать бесплатный грабер сайтов не составит никакого труда…

    Как я решил спарсить Авито, или PhantomJS + PHP как идеальный способ сбора информации

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

    Для тех, кто в танке и не в теме. Парсер (или парсинг, т.е. процесс) — это программный продукт, который помогает собирать в автоматическом режиме информацию с площадок. Я таким образом смог насобирать несколько тысяч песен с кучи сайтов. Я уже писал об этом в моей статье Пишем php парсер сайтов с нуля, но я пользовался немного другой библиотекой и был далёк от совершенства.

    Все основные проблемы  моего прошлого подхода заключались в том, что в старом методе сбора не было эмуляции работы пользователя. Т.е. к серверу приходили запросы в автоматическом режиме, и более-менее умные сайты (я сейчас говорю про злополучный Avito)  быстро распознавали меня как робота и блокировали доступ к сайту. ну сделал я 5-10 обращений к сайту и что дальше? Бан на полчаса или на весь день. После такого жить просто не хотелось. Тогда я всё бросил и решил уйти в монахи, но через год понял. что это не моё. И нашёл для себя PhantomJS.

    PhantomJS сделает из машины — человека

    Фантом — это такой webkit-браузер, который можно запускать без графического интерфейса и бегать по страницам других сайтов без боязни быть заблокированным. Если попроще, то это оболочка, которая придаёт жизнь Вашему парсеру, помогает дать ему душу. Т.е. с использованием PhantomJS вы сможете представиться каждому порталу как Настоящий пользователь!

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

    1. Скачать программу

    В начале нам нужно идти на сайт разработчиков. На главной странице скачиваем библиотечку и радуемся, теперь у нас есть свой Фантом! 

    Заходим в папку bin и видим файл под названием phantomjs.exe Именно этот файл и будет играть основную роль в нашем создании бесплатном парсере (Вы тратите только своё время, не более того). 

    2. Переходим к PHP коду

    Давайте в начале создадим код на PHP, который будет обращаться к нашему фантому и выводить полученные результаты. Кстати, это вариант под номером 1.

    Я написал вот такую функцию:

    blic function parser() {
            try {
                echo(shell_exec('W:\OpenServer\domains\realty\phantomjs\bin\phantomjs.exe W:\OpenServer\domains\realty\phantomjs\bin\script2.js'));
                flush();
            } catch (Exception $exc) {
                echo('Ошибка!');
                echo $exc->getTraceAsString();
            }
        }

     

    В функцию shell_exec я передаю Путь, где лежит фантом и Путь к исполняемому JavaScript-коду. Да да, весь парсинг будет на JavaScript, т.е любой из Вас сможет безболезненно использовать JQuery и JS и легко работать с DOM-моделью (блоками сайта).

     3. Пришла пора JavaScript

    А теперь давайте изучим код, на примере которого я смог легко спарсить страничку с Avito. Вот пример:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

    69

    70

    71

    72

    73

    74

    75

    76

    // Example using HTTP POST operation
     
    "use strict";
     
    //Тут объявляю несколько юзерагентов, типа мы под разными браузерами заходим постоянно
    var useragent = [];
    useragent.push('Opera/9.80 (X11; Linux x86_64; U; fr) Presto/2.9.168 Version/11.50');
    useragent.push('Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5355d Safari/8536.25');
    useragent.push('Opera/12.02 (Android 4.1; Linux; Opera Mobi/ADR-1111101157; U; en-US) Presto/2.9.201 Version/12.02');
     
    //Здесь находится страничка, которую нужно спарсить
    var siteUrl = 'https://m.avito.ru/komsomolsk-na-amure/kvartiry/1-k_kvartira_29_m_45_et._665423964';
    var page = require('webpage').create();
     
    //Это я передаю заголовки 
    //Их можно посмотреть в браузере на закладке Network (тыкайте сами, ищите сами)
    page.customHeaders = {
        ":host": "m.avito.ru",
        ":method": "GET",
        ":path": "/komsomolsk-na-amure/kvartiry?user=1&hist_back=1",
        ":scheme": "https",
        ":version": "HTTP/1.1",
        "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
        "accept-language": "ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4",
        "cache-control": "max-age=0",
        "upgrade-insecure-requests": "1",
        "user-agent": useragent[Math.floor(Math.random() * useragent.length)]
    };
     
    //Здесь я отключаю загрузку сторонних скриптов для ускореняи парсинга
    page.onResourceRequested = function (requestData, request) {
        if ((/http:\/\/.+?\.css$/gi).test(requestData['url'])) {
            request.abort();
        }
        if (
                (/\.doubleclick\./gi.test(requestData['url'])) ||
                (/\.pubmatic\.com$/gi.test(requestData['url'])) ||
                (/yandex/gi.test(requestData['url'])) ||
                (/google/gi.test(requestData['url'])) ||
                (/gstatic/gi.test(requestData['url']))
                ) {
            request.abort();
            return;
        }
    };
     
    //Этот код выводит ошибки, дебаг так сказать
    page.onError = function (msg, trace) {
        console.log(msg);
        trace.forEach(function (item) {
            console.log('  ', item.file, ':', item.line);
        });
    };
     
    String.prototype.stripTags = function() {
      return this.replace(/<\/?[^>]+>/g, '');
    };
     
    //Объявим переменные для инф-и об объекте
    var href, json, price, adress, fio, descriptionShort, descriptionFull;
     
    //Здесь мы открываем страничку
    page.open(siteUrl, function (status) {
        if (status !== 'success') {
            console.log('Unable to access network');
        } else {
          	//Получим ценник квартирки
            var price = page.evaluate(function () {
                return [].map.call(document.querySelectorAll('.price-value'), function (span) {
                    return span.innerText;
                });
            });
          //Выведем
          console.log(price);
        }
    });

    С помощью такого небольшого кода я смог зайти на страницу Авито и спарсить цену квартиры. А на что способны Вы?) Я собирал таким образом всю информацию с практически ЛЮБОГО сайта. Здесь нет предела возможностям.

    А теперь давайте ка покажу несколько фишечек при работе с PhantomJS.

    Фишечки для работы с Фантомом

    1.Ожидание происхождения какого-то события

    waitFor(
      function() {
        return page.evaluate(function() {
          // Кликаем на кнопку
          $('.button').trigger('click');
          // Ждём, пока элемент не станет скрытым
          return $('.button').is(':hidden');
        });
      }, function() {
        // Выполняем действия после того, как необходимый элемент появился на экране
      });

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

    2. Подключение JQuery к сайту (вдруг нет, а вот вдруг)

    page.open(siteUrl, function(status) {
      if (status === 'success') {
        // Инклудим jQuery
        page.injectJs('//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js');
        //и что-то там другое
      }
    });

    Просто вставляем в загруженную страницу свою библиотеку и начинаем работать!

    3. Выключаем всё CSS и картинки

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

    //Отключение картинок
    page.settings = {
      loadImages: false
    };
     
    // Отключение CSS
    page.onResourceRequested = function(requestData, request) {
      if ((/http:\/\/.+?\.css$/gi).test(requestData['url'])) {
        request.abort();
      }
    

    Остальные идеи и прелести Вы сможете подсмотреть в моём верхнем коде. Просто посмотрите функции и возьмите себе на заметку какие-то нужные вещи.

    Выводы

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

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

    Скоро будет новый подгончик по материалам! Всем огромное спасибо за посещение моего сайта!

    Если статья была для Вас полезной — Поделитесь ссылкой!

    Советуем почитать

    Закрепленные

    Понравившиеся

    seo-love.ru

    Как сделать парсер контента на PHP

    Вы здесь: Главная — PHP — PHP Основы — Как сделать парсер контента на PHP

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

    Итак, вот список пунктов, которые необходимо пройти, чтобы создать парсер контента на PHP:

    1. Получить содержимое страницы и записать его в строковую переменную. Наиболее простой вариант — это функция file_get_contents(). Если контент доступен только авторизованным пользователям, то тут всё несколько сложнее. Здесь уже надо посмотреть, каков механизм авторизации. Далее, используя cURL, отправить правильный запрос на форму авторизации, получить ответ и затем отправить правильные заголовки (например, полученный идентификатор сессии), а также в этом же запросе обратиться к той странице, которая нужна. Тогда уже в этом ответе Вы получите конечную страницу.
    2. Изучить структуру страницы. Вам нужно найти контент, который Вам необходим и посмотреть, в каком блоке он находится. Если блок, в котором он находится не уникален, то найти другие общие признаки, по которым Вы однозначно сможете сказать, что если строка удовлетворяет им, то это то, что Вам и нужно.
    3. Используя строковые функции, достать из исходной строки нужный Вам контент по признакам, найденным во 2-ом пункте.

    Отмечу так же, что всё это поймёт и сможет применить на практике только тот, кто знает PHP. Поэтому те, кто его только начинает изучать, Вам потребуются следующие знания:

    1. Строковые функции.
    2. Библиотека cURL, либо её аналог.
    3. Отличное знание HTML.

    Те же, кто ещё вообще не знает PHP, то до парсеров в этом случае ещё далеко, и нужно изучать всю базу. В этом Вам поможет мой курс, либо какие-нибудь книги по PHP.

    Безусловно, Америки я в этой статье не открыл, но слишком много вопросов по теме парсеров, поэтому этой статьёй я постарался лишь дать развёрнутый ответ.

    • Создано 13.01.2014 13:21:08
    • Михаил Русаков
    Предыдущая статья Следующая статья

    Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!

    Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.
    Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.

    Если Вы не хотите пропустить новые материалы на сайте,
    то Вы можете подписаться на обновления: Подписаться на обновления

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

    Порекомендуйте эту статью друзьям:

    Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):

    1. Кнопка:
      <a href=»https://myrusakov.ru» target=»_blank»><img src=»https://myrusakov.ru//images/button.gif» alt=»Как создать свой сайт» /></a>

      Она выглядит вот так:

    2. Текстовая ссылка:
      <a href=»https://myrusakov.ru» target=»_blank»>Как создать свой сайт</a>

      Она выглядит вот так: Как создать свой сайт

    3. BB-код ссылки для форумов (например, можете поставить её в подписи):
      [URL=»https://myrusakov.ru»]Как создать свой сайт[/URL]

    myrusakov.ru