Пишем php парсер сайтов с нуля. Php парсер авторизация
Пишем php парсер сайтов с нуля
Просмотров: 53181
Очень многие из нас хотели бы быстро наполнить сайт контентом. Я покажу вам, как несколько тысяч материалов собрать всего лишь за несколько часов.
Парсер на php - раз плюнуть!
Приветствую вас, наши дорогие читатели. Сегодня решил написать сложную статью про парсеры (сбор информации со сторонних ресурсов).
Скажу сразу, что вам потребуется знание основ программирования на php. В противном случае почитайте теории. Я не буду рассказывать азы, а сразу полезу показывать всё на практике.
Шаг 1 - PHP Simple HTML DOM Parser
Для парсинга сайтов мы будем использовать простецкую библиотечку под названием PHP Simple HTML DOM Parser, которую вы сможете скачать на сайте разработчика. Данный класс поможет вам работать с DOM-моделью страницы (дерево документа). Т.е. главная идея нашей будущей программы будет состоять из следующих пунктов:
- Разбираем её по элементы (div, table, img и прочее)
- В соответствии с логикой получим определённые данные.
Давайте же начнём написание нашего php парсера сайтов.
Для начала подключим нашу библиотеку с помощью следующей строки кода:
include 'simple_html_dom.php';Шаг 2 - Скачиваем страничку
На этом этапе мы смогли подключить файл к проекту и теперь пришла пора скачать страничку для парсинга.
В нашей библе есть две функции для получения удалённой страницы сайта. Вот эти функции
- str_get_htm() - получает в качестве параметров обычную строку. Это полезно, если вы стянули страничку с помощью CURL или метода file_get_contents. Пример использования:
$seo = str_get_html('<html>Привет, наш любимый читатель блога SEO-Love.ru!</html>')
- file_get_html() - здесь же мы передаём в качестве параметра какой-то url, с которого нам потребуется скачать контент.
- $seo = file_get_html('http://www.site.ru/');
После скачивания каждой страницы вам требуется подчищать память, дабы парсеру было легче работать и не так сильно грузился ваш сервер. Эта функция вызовется с помощью данного кода:
Шаг 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; } }Шаг 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 - Поля элементов
Каждый найденный элемент имеет несколько структур:
- $seo->tag Прочитает или запишет имя тега искомого элемента.
- $seo->outertext Прочитает или запишет всю HTML-структуру элемента с ним включительно.
- $seo->innertext Прочитает или запишет внутреннюю HTML-структуру элемента.
- $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Если вы захотите затереть какой-либо элемент из дерева, то просто обнулить значение outertext, т.е. $div->outertext = ""; Можно поэксперементировать с удалением элементов.
P.S. Я обнаружил проблему с кодировками при очистке и всяческими манипуляциями с полем innertext. Пришлось использовать outertext и затем с помощью функции strip_tags удалял ненужные теги.
Шаг 6 - Дочерние элементы
Разработчики данной библиотеки позаботились так же и о том, чтобы вам было легко перемещаться по дочерним и родительским элементам дерева. Для этого ими были любезно созданы следующие методы:
- $seo->children ( [int $index] ) Возвращает N-ый дочерний элемент, иначе возвращает массив, состоящий из всех дочерних элементов.
- $seo->parent() Возвращает родительский элемент искомого элемента.
- $seo->first_child() Возвращает первый дочерний элемент искомого элемента, или NULL, если результат пустой
- $seo->last_child() Возвращает последний дочерний элемент искомого элемента, или null, если результат пустой
- $seo->next_sibling() Возвращает следующий родственный элемент искомого элемента, или null, если результат пустой
- $seo->prev_sibling() Возвращает предыдущий родственный элемент искомого элемента, или null, если результат пустой
Я особо не пользовался этими возможностями, потому что они ещё ни разу не пригодились мне. Хотя один раз при разборе таблицы использовал, потому что они структурированы, что делает разбор очень простым и лёгким.
Шаг 7 - Практика
Перейдём к практике. Я решил отдать вам на растерзание одну функцию, что использовал при написании парсера текстов песен на один из своих сайтов. Пытался досконально подробно описать код. Смотрите комментарии и задавайте вопросы.
1
2
3
4
5
6
7
8
9
10
11
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 . " "; }Замечу, что в коде много самописных функций, которые используются для вставки в мой базу. Эти функции у каждого могут быть индивидуальными, так что в этом я вам не помощник. Либо обращайтесь за помощью в комментарии. Всегда буду рад помочь!
Пока что на этом всё. В следующих уроках расскажу, как можно быстро и просто спарсить кучу информации на несколько десятков сайтов. Этот кейс должен обогатить каждого!
Всего доброго! Ретвиты, лайки и репосты приветствуются!
Если статья была для Вас полезной - Поделитесь ссылкой!
Советуем почитать
Закрепленные
Понравившиеся
seo-love.ru
Автоматизация парсинга на 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 - PHP Основы - Как сделать парсер контента на PHP
У многих из Вас возникают вопросы по поводу создания парсера на PHP. Например, есть какой-то сайт, и Вам необходимо получить с него контент. Я долго не хотел писать эту статью, поскольку конкретного смысла в ней нет. Чтобы сделать парсер на PHP, нужно знать этот язык. А те, кто его знает, такой вопрос просто не зададут. Но в этой статье я расскажу, как вообще создаются парсеры, а также, что конкретно нужно изучать.
Итак, вот список пунктов, которые необходимо пройти, чтобы создать парсер контента на PHP:
- Получить содержимое страницы и записать его в строковую переменную. Наиболее простой вариант - это функция file_get_contents(). Если контент доступен только авторизованным пользователям, то тут всё несколько сложнее. Здесь уже надо посмотреть, каков механизм авторизации. Далее, используя cURL, отправить правильный запрос на форму авторизации, получить ответ и затем отправить правильные заголовки (например, полученный идентификатор сессии), а также в этом же запросе обратиться к той странице, которая нужна. Тогда уже в этом ответе Вы получите конечную страницу.
- Изучить структуру страницы. Вам нужно найти контент, который Вам необходим и посмотреть, в каком блоке он находится. Если блок, в котором он находится не уникален, то найти другие общие признаки, по которым Вы однозначно сможете сказать, что если строка удовлетворяет им, то это то, что Вам и нужно.
- Используя строковые функции, достать из исходной строки нужный Вам контент по признакам, найденным во 2-ом пункте.
Отмечу так же, что всё это поймёт и сможет применить на практике только тот, кто знает PHP. Поэтому те, кто его только начинает изучать, Вам потребуются следующие знания:
- Строковые функции.
- Библиотека cURL, либо её аналог.
- Отличное знание HTML.
Те же, кто ещё вообще не знает PHP, то до парсеров в этом случае ещё далеко, и нужно изучать всю базу. В этом Вам поможет мой курс, либо какие-нибудь книги по PHP.
Безусловно, Америки я в этой статье не открыл, но слишком много вопросов по теме парсеров, поэтому этой статьёй я постарался лишь дать развёрнутый ответ.
- Создано 13.01.2014 13:21:08
- Михаил Русаков
Копирование материалов разрешается только с указанием автора (Михаил Русаков) и индексируемой прямой ссылкой на сайт (http://myrusakov.ru)!
Добавляйтесь ко мне в друзья ВКонтакте: http://vk.com/myrusakov.Если Вы хотите дать оценку мне и моей работе, то напишите её в моей группе: http://vk.com/rusakovmy.
Если Вы не хотите пропустить новые материалы на сайте,то Вы можете подписаться на обновления: Подписаться на обновления
Если у Вас остались какие-либо вопросы, либо у Вас есть желание высказаться по поводу этой статьи, то Вы можете оставить свой комментарий внизу страницы.
Порекомендуйте эту статью друзьям:
Если Вам понравился сайт, то разместите ссылку на него (у себя на сайте, на форуме, в контакте):
-
Кнопка:
<a href="https://myrusakov.ru" target="_blank"><img src="https://myrusakov.ru//images/button.gif" alt="Как создать свой сайт" /></a>
Она выглядит вот так:
-
Текстовая ссылка:<a href="https://myrusakov.ru" target="_blank">Как создать свой сайт</a>
Она выглядит вот так: Как создать свой сайт
- BB-код ссылки для форумов (например, можете поставить её в подписи): [URL="https://myrusakov.ru"]Как создать свой сайт[/URL]
myrusakov.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