Поступил заказ на реализацию простого прокси чекера на php. Особых требований нету, только одно - количество прокси от 60к штук o_O, от чего я вошёл в небольшой ступор.
Начал реализацию через обычный curl и мускул. В процессе тестирования стало ясно что ждать результатов в этом году уже нам не придется :) И я начал курить гугль по тематике много поточности.
Много поточности в php нету и наверное не будет. Есть только извращенные методы эмуляции, которые дают результат, но далеко не идеальный.
Короче, не стал я забивать голову процессами, сокетами, сторонними модулями и тд, а начал ковырять curl_multi который позволяет делать POST GET HEAD запросы в несколько потоков и не только.
Много реализаций перелопатил, облазил много форумов блогов и в результате создал как мне кажется "правильный код" который делает то что мне нужно. Давайте рассмотрим код в деталях:
Начал реализацию через обычный curl и мускул. В процессе тестирования стало ясно что ждать результатов в этом году уже нам не придется :) И я начал курить гугль по тематике много поточности.
Много поточности в php нету и наверное не будет. Есть только извращенные методы эмуляции, которые дают результат, но далеко не идеальный.
Короче, не стал я забивать голову процессами, сокетами, сторонними модулями и тд, а начал ковырять curl_multi который позволяет делать POST GET HEAD запросы в несколько потоков и не только.
Много реализаций перелопатил, облазил много форумов блогов и в результате создал как мне кажется "правильный код" который делает то что мне нужно. Давайте рассмотрим код в деталях:
1. Открываем файлик с проксиками proxies
- $proxies = file ("proxies.txt");
2. Создаем мультикурл и получаем его хендл- $mc = curl_multi_init ();
3. Создаем n сеансов curl и записываем дескрипторы в массив $c. Позже все эти курлы мы запустим параллельно :). Каждый сеанс инициализируется своим прокси (см. CURLOPT_PROXY) и своими тамаутами (CURLOPT_CONNECTTIMEOUT - таймаут конекта и CURLOPT_TIMEOUT - тамаут на скачивание контента).
- for ($thread_no = 0; $thread_no<count ($proxies); $thread_no++)
- {
- $c [$thread_no] = curl_init ();
- curl_setopt ($c [$thread_no], CURLOPT_URL, "http://google.com");
- curl_setopt ($c [$thread_no], CURLOPT_HEADER, 0);
- curl_setopt ($c [$thread_no], CURLOPT_RETURNTRANSFER, 1);
- curl_setopt ($c [$thread_no], CURLOPT_CONNECTTIMEOUT, 5);
- curl_setopt ($c [$thread_no], CURLOPT_TIMEOUT, 10);
- curl_setopt ($c [$thread_no], CURLOPT_PROXY, trim ($proxies [$thread_no]));
- curl_setopt ($c [$thread_no], CURLOPT_PROXYTYPE, 0);
- curl_multi_add_handle ($mc, $c [$thread_no]);
- }
Важный момент: колличество потоков тут равно колличеству строк в файле proxies. Потому проксей нужно давать скрипту в пределах разумного :)
Далее идет процесс проверки проксей на валидность.
- do {
- while (($execrun = curl_multi_exec ($mc, $running)) == CURLM_CALL_MULTI_PERFORM);
- if ($execrun != CURLM_OK) break;
- while ($done = curl_multi_info_read ($mc))
- {
- $info = curl_getinfo ($done ['handle']);
- if ($info ['http_code'] == 301) {
- echo trim ($proxies [array_search ($done['handle'], $c)])."\r\n";
- }
- curl_multi_remove_handle ($mc, $done ['handle']);
- }
- } while ($running);
- curl_multi_close ($mc);
Мой метод проверки отличается от других, я делаю это просто: устанавливаю проксик и скачиваю страничку Гоши (см. CURLOPT_URL, "http://google.com" код выше).
В полученом заголовке странички стоит редирект через header, потому что адрес http://google.com не используется а Гоша перебрасывает всех на www.google.com.
Чтобы получить код http header 301 использую функцию $info = curl_getinfo ($done ['handle']); ну и дальше уже делаю проверку кода и вывод результатов if ($info ['http_code'] == 301) { echo trim ($proxies [array_search ($done['handle'], $c)])."\r\n"; }
Проанализировав подобные конструкции я понял что у большинства программистов проблемы возникают в реализации параллельных запросов а именно в обработке рузультатов.
Многие пишут код в котором результаты обрабатывают уже после завершения всех запросов. В моем коде реализовано все как нужно и при тестах однопоточного чекера и этого на платформе windows видно что скорость работы скриптов разная и многопоточность в multicurl действительно работает.
Так что пользуйтесь на здоровье.
Скачать сорец прокси чекера можно по ссылке [PHP прокси чекер (curl_multi)]
В полученом заголовке странички стоит редирект через header, потому что адрес http://google.com не используется а Гоша перебрасывает всех на www.google.com.
Чтобы получить код http header 301 использую функцию $info = curl_getinfo ($done ['handle']); ну и дальше уже делаю проверку кода и вывод результатов if ($info ['http_code'] == 301) { echo trim ($proxies [array_search ($done['handle'], $c)])."\r\n"; }
Проанализировав подобные конструкции я понял что у большинства программистов проблемы возникают в реализации параллельных запросов а именно в обработке рузультатов.
Многие пишут код в котором результаты обрабатывают уже после завершения всех запросов. В моем коде реализовано все как нужно и при тестах однопоточного чекера и этого на платформе windows видно что скорость работы скриптов разная и многопоточность в multicurl действительно работает.
Так что пользуйтесь на здоровье.
Скачать сорец прокси чекера можно по ссылке [PHP прокси чекер (curl_multi)]
1 коммент.:
Отличная статья, спасибо! :)
Отправить комментарий