Прикинув приблизительный объем материала, я поняла, что в одну статью все не влезет, так что продолжение будет следовать :)
Для того, чтобы начать работать с библиотекой CURL, ее надо установить. Инструкций установки CURL в сети найти можно много, поэтому останавливаться на этом не буду.
Перейдем сразу к работе. Разберем простой пример использования библиотеки CURL для получения кода страницы. Этот пример вы можете часто встретить в листингах скриптов (я взяла его с какого-то форума).
function get_web_page( $url )
{
$uagent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.0.8) Gecko/2009032609 Firefox/3.0.8";
$ch = curl_init( $url );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // возвращает веб-страницу
curl_setopt($ch, CURLOPT_HEADER, 0); // не возвращает заголовки
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); // переходит по редиректам
curl_setopt($ch, CURLOPT_ENCODING, ""); // обрабатывает все кодировки
curl_setopt($ch, CURLOPT_USERAGENT, $uagent); // useragent
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 120); // таймаут соединения
curl_setopt($ch, CURLOPT_TIMEOUT, 120); // таймаут ответа
curl_setopt($ch, CURLOPT_MAXREDIRS, 10); // останавливаться после 10-ого редиректа
$content = curl_exec( $ch );
$err = curl_errno( $ch );
$errmsg = curl_error( $ch );
$header = curl_getinfo( $ch );
curl_close( $ch );
$header['errno'] = $err;
$header['errmsg'] = $errmsg;
$header['content'] = $content;
return $header;
}
В эту функцию в качестве параметра передается URL, а возвращается ассоциативный массив, состоящий из заголовка и содержимого страницы. Функции CURL автоматически управляют редиректами, кукисами, декомпрессией файлов.
(Как хорошо, что в блоггере появилась простая возможность скрывать часть поста под кат! Сейчас, наконец, на главной не будет простыней листингов. А читателям, я думаю, будет не сложно один лишний раз кликнуть на "Читать далее")
Параметры заголовка можно посмотреть в мануалах-описаниях функции curl_getinfo().
Как видим, параметров там немало:
- "url"
- "content_type"
- "http_code"
- "header_size"
- "request_size"
- "filetime"
- "ssl_verify_result"
- "redirect_count"
- "total_time"
- "namelookup_time"
- "connect_time"
- "pretransfer_time"
- "size_upload"
- "size_download"
- "speed_download"
- "speed_upload"
- "download_content_length"
- "upload_content_length"
- "starttransfer_time"
- "redirect_time"
Наиболее полезными для нас будут:
url — адрес после всех редиректов;
content_type — "тип" контента (например, "text/html; charset=utf-8");
http_code — код ответа (если все прошло благополучно — 200. О кодах я уже писала на этом блоге раньше, в статье о HTTP-протоколе).
Дополнительными возвращаемыми параметрами приведенной выше функции будут:
errno — код ошибки CURL (если без ошибок — вернется 0);
errmsg — сообщение об ошибке (определяется по коду ошибки errno);
content — содержимое страницы (HTML-код, картинка, т.д.).
Когда все прошло удачно, errno = 0, http_code = 200 и в переменной content находится содержимое страницы.
Если возникает ошибка, связанная с неверным адресом, неизвестным хостом, истачением таймаутов или с множественными редиректами, то в переменной errno будет возвращен отличный от нуля код ошибки, а errmsg будет содержать пояснение к этой ошибке.
Если возникает ошибка, связанная с отсутствием страницы (404) или с недостаточными правами, errno = 0, http_code — статус-код, отличный от 200, а в переменной content будет страница сайта, сообщающая об ошибке.
Как видите, функция get_web_page() расширена. Она не просто позволяет получить контент, но еще и выявить наличие ошибок при его получении. Если вам надо просто получить контент — можно переделать ее под себя. Как правило, каждый разработчик со временем выделяет себе нужные функции в библиотечку (если поискать в сети — можно найти различные варианты классов для работы с CURL, выложенные разными разработчиками. Тут уж дело вкуса — берете чужое (и при необходимости дорабатываете) или делаете свое).
Пример ее использования:
$result = get_web_page( $url );
if ( $result['errno'] != 0 )
... ошибка: неправильный url, таймаут, зацикливание ...
if ( $result['http_code'] != 200 )
... ошибка: нет страницы, нет прав ...
$page = $result['content'];
Но разберемся с функциями в листинге по порядку. Чтобы получить web-страницу с помощью библиотеки CURL, необходимо действовать в соответствии со следующей инструкцией:
1. Инициализируем работу CURL с помощью curl_init(). При использовании этой функции создается объект для управления запросом. Единственным аргументом функции является URL, который сохраняется до тех пор, пока curl_exec() не выполнит запрос. В приведенном в начале статьи примере в листинге мы видели строку:
$ch = curl_init( $url );
После ее выполнения переменной $ch будет присвоен дескриптор объекта CURL для работы с адресом $url.
Есть еще немного другой способ выполнить то же самое.
$ch = curl_init( $url );
curl_setopt($ch, CURLOPT_URL, $url);
Как видно, адрес не передается в виде параметра, а указывается уже после инициализации с помощью curl_setopt. Curl_setopt — это как раз следующий шаг, рассмотрим его подробнее.
2. С помощью curl_setopt() настраиваем параметры запроса и их значения. Параметров на самом деле немало. Все их помнить необязательно, но ознакомиться стоит (http://ru.php.net/manual/en/function.curl-setopt.php).
Наиболее важными считаются:
— CURLOPT_RETURNTRANSFER
Когда он равен true (или 1), CURL возвращает содержимое страницы с помощью curl_exec(). Когда значение этого параметра равно false, CURL выводит содержимое страницы на экран. Для парсинга нам всегда придется работать с CURLOPT_RETURNTRANSFER = 1, так как всегда требуется дальнейшая обработка содержимого.
— CURLOPT_HEADER
Когда этот параметр установлен в true (или 1), CURL включает в страницу заголовки ответа HTTP-сервера. Когда false — они не включаются, что делает результат более "удобным" для дальнейшего разбора. Причем доступ к заголовкам при CURLOPT_HEADER=false получить можно, через упоминавшуюся выше функцию curl_getinfo().
В разряд "основных" входят также следующие параметры:
- CURLOPT_FOLLOWLOCATION
Когда параметр установлен в true, редирект осуществляется CURL-ом автоматически. Когда false — после первой же попытки редиректа происходит остановка работы и возвращается ошибка.
- CURLOPT_ENCODING
Когда данный параметр пустой, CURL управляет декомпрессией и компрессией. "Сжатые" страницы автоматически распаковываются перед тем, как данные возвращаются с помощью curl_exec().
Параметры, которые еще следует указывать, чтобы серфинг по вебу с использованием CURL был "наиболее грамотным":
- CURLOPT_USERAGENT
Ну, это понятно. User agent — идентифицирует приложение, с помощью которого выполнен запрос (например, веббраузер). Если этот параметр оставить пустым, некоторые веб-ресурсы могут не ответить на запрос.
- CURLOPT_AUTOREFERER
Реферер — URL страницы, с которой пришли с запросом. Когда разрешены редиректы, то достаточно установить этот параметр равным true (или 1) — и CURL будет автоматически заполнять рефереры при редиректе.
Параметры для выявления ошибок при выполнении запросов:
- CURLOPT_CONNECTTIMEOUT — время в секундах, через которое CURL перестанет пытаться соединиться с сервером, который не отвечает;
- CURLOPT_TIMEOUT — время в секундах, через которое CURL перестанет пытаться получить содержимое страницы с сервера, который не отвечает/не доступен/и так далее;
- CURLOPT_MAXREDIRS — устанавливает максимальное количество возможных редиректов.
Следует так же написать здесь о том, что в версиях PHP, начиная с 5.1.3, появилась функция curl_setopt_array(), которая позволяет установить все параметры разом, загнав их в массив.
$options = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => false,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_ENCODING => "",
CURLOPT_USERAGENT => $uagent,
CURLOPT_AUTOREFERER => true,
CURLOPT_CONNECTTIMEOUT => 120,
CURLOPT_TIMEOUT => 120,
CURLOPT_MAXREDIRS => 10,
);
curl_setopt_array( $ch, $options );
3. После установки всех нужных параметров используем curl_exec(). curl_exec() отправляет запрос и возвращает веб-страницу (HTML, XML, image и т.д.).
4. curl_errno() и curl_error() мы уже рассмотрели в начале статьи.
Еще раз, в качестве резюме:
- Системные ошибки возникают из-за неверного url-а, протокола, неправильного хоста, таймаутов (соединения и ответа) и зацикливания. При таких ошибказ curl_errno() возвращает отличный от нуля код (libcurl errors) и curl_error() возвращает сообщение, описывающее ошибку.
- Ошибки сайта возникают, если страница не найдена или нет доступа. В этом случае curl_errno() вернет ноль, а код-статус страницы можно уточнить через описанный выше curl_getinfo().
5. curl_close() уничтожает объект, очищает память. curl_close() надо вызывать по окончанию работы с объектом CURL.
На первый раз материалу достаточно для того, чтобы самим поэкспериментировать с применением библиотеки CURL.
___
Продолжаю благодарить людей, оказавших информационную поддержку RSSAdder-у. На этот раз это автор блога о мини-бизнесе и не только :)
___
Чтобы быть в курсе обновлений блога, можно подписаться на RSS.
Кстати начинающим можно присмотреться к библиотеке Snoopy - достаточно хорошая обертка над curl. Много удобных возможностей.
ОтветитьУдалитьА что значит "curl_setopt($ch, CURLOPT_HEADER, 0);// не возвращает заголовки"". Что за заголовки?
ОтветитьУдалитьKubig, http://parsing-and-i.blogspot.com/2009/04/http.html :))
ОтветитьУдалитьKubig, и вот здесь про протокол http можно почитать: http://parsing-and-i.blogspot.com/2009/04/http-protocol-http-requests.html. А потом уже спрашивай, если что останется непонятным.
ОтветитьУдалитьА каким образом получить в переменную адрес хоста после всех редиректов!?
ОтветитьУдалитьОчень бы интересно было посмотреть на пример автогенератора фрихост блогов на curl
ОтветитьУдалитьЗдравствуйте! Может вы подскажете, столкнулся с такой проблемой. Выполняется скрипт авторизации с последующим заполнением некоторых форм, но после первого курл запроса, адрес страницы скрипта замещаеться адресом проблемного сайта, также это происходит независимо от того стоит FOLLOWLOCATION в 0 или 1.
ОтветитьУдалитьИ еще такой вопрос. Нужно инициализировать сессию curl_init один раз, выполнять N запросов и закрывать или каждый раз перед запросом, или же разницы нету. Спасибо за ответы!))
Жаль, что так и нет ответа на вопрос анонима. Можно ли между вызовами curl_init/curl_close делать несколько запросов curl_exec с разными curl_setopt?
ОтветитьУдалитьIvan, я просто не понимаю, в чем особая проблема? Написать лишние 2 строчки? Лично я всегда делаю один curl_exec между curl_init/curl_close и считаю, что так логически и структурно правильно. Никогда даже не интересовалась, что будет, если использовать несколько вызовов :) Может, скилл любознательности у меня не прокачан...
ОтветитьУдалитьвопрос, а как проверить через curl степень анонимности прокси?
ОтветитьУдалитьMasha, меня этот вопрос заинтересовал с точки зрения производительности. В принципе не люблю выполнять какие-либо лишние вызовы функций, если есть шанс обойтись без них.
ОтветитьУдалитьВпрочем, это, конечно, мелочи по сравнению с другими проблемами парсинга, которые у меня возникли.
Ответ Анонимному об анонимности прокси:
ОтветитьУдалитьНаписать скрипт, который обращается через искомый прокси к какому-нибудь прокси-чекеру (первое, что нашел в гугле - http://aruljohn.com/details.php).
Далее распарсить выданную прокси-чекером страницу и проанализировать информацию о прокси и айпи.
Либо, если у вас есть хостинг с публичным айпи, можно написать собственный прокси-чекер. В этом случае ничего парсить не потребуется, достаточно проанализировать содержимое $_SERVER.
Ivan, а как проверить если скрипт запускаю с локального компа? (это по второму варианту)
ОтветитьУдалитьвывел весь print_r($_SERVER); но что-то не пойму куда смотреть
Смотреть нужно сюда:
ОтветитьУдалить$_SERVER['REMOTE_ADDR'],
$_SERVER['HTTP_X_FORWARDED_FOR'] или $_SERVER['X_FORWARDED_FOR'] или
$_SERVER['HTTP_CLIENT_IP']
Среди этих значений (если они вообще присутствуют) не должно быть вашего ip.
Очень полезная статья а главное понятная. Но у меня возникла проблема:
ОтветитьУдалитьделаю парсинг как Вы описали на сервере, который выходит в интернет напрямую - все работает. А вот пытаюсь сделать парсинг с сервера, который спрятан за Proxy - ничего не получается пишет ошибку 56 - Failure when receiving data from the peer. Не пойму как это исправить. Подскажите что можно проверить.
curl_setopt( $co, CURLOPT_FOLLOWLOCATION, 1);
ОтветитьУдалитьу вас написано что этот параметр нужен чтоб переходить по редиректам. Запустил ваш пример на сайте www.zhuoyush.com, чтоб просто сграбить главную страницу, редирект не схавало
Слава, посмотрите внимательно код страницы ресурса. Может, там редирект устроен по-особомую
ОтветитьУдалитьИзвините за запоздалую реакцию, но хотел бы внести замечание по поводу Snoopy, которого рекомендуют в первом комментарии.
ОтветитьУдалитьНе советую. Во-первых, при неудачном соединении, генерирует не только внутреннюю ошибку, но и вываливает два варнинга прямо в вывод.
Во-вторых старый и не развивается. Устаревший код с большим количеством граблей.
В-третьих он curl пытается через exec вызывать (!!!) и, если не получается, то пробует всё сделать через сокеты.
В общем, даже не стоит по ссылке переходить. Спасибо.
Подскажите пожалуйста (я реализовал по вашему примеру функцию которая вызывается в цикле) у меня к примеру есть 150 ссылок и мне надо зайти по каждой из них и вытянуть какую нибудь информацию, но в цикле почему то просматриваются 5-15 ссылок и все!!! а как же остальные??
ОтветитьУдалитьАнонимный, откуда мне знать? :)) Я не вижу вашего кода, пальцем в небо тыкать бесполезно :)
ОтветитьУдалить