Доброго времени суток, ув.форумчане! Пришел за советом, в php пока не особо шарю, посему хотелось бы услышать совета и ответы на пару вопросов, собственно сабж: есть скрипт, парсит со всех сраниц сайта h1 и title: Код (Text): <meta charset="utf-8" /> <? require_once '../../config.php'; include('simple_html_dom.php'); class Page{ var $url, $h1, $title, $content, $content_type, $urls; #Подсасываем страницу и данные о ней function getPage(){ $url = $this->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, 240); // таймаут соединения curl_setopt($ch, CURLOPT_TIMEOUT, 240); // таймаут ответа curl_setopt($ch, CURLOPT_MAXREDIRS, 5); // останавливаться после 10-ого редиректа $this->content = curl_exec( $ch ); $err = curl_errno( $ch ); $errmsg = curl_error( $ch ); $header = curl_getinfo( $ch ); curl_close( $ch ); if($err){ echo "Ошибка! <br />Код ошибки: ".$err."<br />Сообщение ошибки: ".$errmsg; return false; } //определяем тип страницы $pagetype = $header['content_type']; $pagetype = explode(";", $pagetype); $this->content_type = $pagetype[0]; return true; } #Обработчик страницы function handlerPage(){ $html = str_get_html($this->content); if($html->innertext!=''){ #Высасываем h1 foreach($html->find('h1') as $h1){ $this->h1 .= $h1->innertext; } unset($h1); #Высасываем title foreach($html->find('title') as $title){ $this->title = $title->innertext; } unset($title); #высасываем все ссылки и помещаем их в массив foreach($html->find('a') as $a){ $this->urls .= $a->href."|"; } unset($a); $this->urls = explode("|",$this->urls); } else{ unset($html); return false; } $html->clear(); unset($html); $res = mysql_query("SELECT * FROM site WHERE url = '".$this->url."'") or die(mysql_error()); if(!mysql_num_rows($res)){ mysql_query("INSERT INTO site VALUES('".$this->url."','".$this->title."','".$this->h1."','1')") or die(mysql_error()); } else mysql_query("UPDATE site SET `title`='".$this->title."', `h1`='".$this->h1."', `parsed`='1' WHERE `url`='".$this->url."'") or die(mysql_error()); return true; } #Обработчик урлов со страницы function handlerUrls($domain){ foreach($this->urls as $key => $url){ if($url == "" || $url == "#"){ unset($this->urls[$key]); } if($url == "/") $url = $this->urls[$key] = "http://www.".$domain; else if(substr($url, 0, 1) == "/") $url = $this->urls[$key] = "http://www.".$domain.$url; else if(substr($url, 0, 1) != "/" && !substr_count($url, "http://") && !substr_count($url, "www.")) $url = $this->urls[$key] = "http://www.".$domain."/".$url; if(!(strpos($url, ".htm") || strpos($url, ".doc") || strpos($url, ".xls") || strpos($url, ".ppt") || strpos($url, ".psd") || strpos($url, ".pdf") || strpos($url, ".ai") || strpos($url, ".jpg") || strpos($url, ".png") || strpos($url, ".tif") || strpos($url, ".gif")) && substr($url, -1) != "/") $url = $this->urls[$key] = $url."/"; if(strpos($url, "javascript") || strpos($url, "mailto") || strpos($url, "#") || strpos($url, ".doc") || strpos($url, ".xls") || strpos($url, ".ppt") || strpos($url, ".psd") || strpos($url, ".pdf") || strpos($url, ".ai") || strpos($url, ".jpg") || strpos($url, ".png") || strpos($url, ".tif") || strpos($url, ".gif")) unset($this->urls[$key]); else if(!isInternal($domain, $url)) unset($this->urls[$key]); } unset($url); foreach($this->urls as $url){ $res = mysql_query("SELECT * FROM site WHERE url = '".$url."'") or die(mysql_error()); if(!mysql_num_rows($res)){ mysql_query("INSERT INTO site VALUES('".$url."','','','0')") or die(mysql_error()); } } unset($url); return true; } #Очистка параметров объекта function clear(){ unset($this->url); unset($this->h1); unset($this->title); unset($this->content); unset($this->content_type); unset($this->urls); } } function isInternal($domain, $url){ if(substr($url, 0, 1) == "/" || $url == "/") return true; else if($domain == getDomain($url)) return true; else{ if(!parse_url($url)) return true; return false; } } function getDomain($url){ $domain = parse_url($url); if($domain['scheme'] == "http") $domain = $domain['host']; else return false; if(substr($domain, 0, 4) == "www."){ $domain = substr($domain, 4); } return $domain; } function nextUrl(){ $res = mysql_query("SELECT * FROM site WHERE parsed = '0'") or die(mysql_error()); if(mysql_num_rows($res)){ $row = mysql_fetch_array($res); parse($row['url']); nextUrl(); } } function parse($url){ echo "<br /><br />ТЕКУЩИЙ URL: ".$url."<br />"; $page = new Page; $page->url = $url; if($page->getPage()){ if($page->content_type == "text/html"){ if(!$page->handlerPage()){ mysql_query("UPDATE site SET `parsed`='1' WHERE `url`='".$url."'") or die(mysql_error()); return false; } global $domain; $page->handlerUrls($domain); } } else{ mysql_query("UPDATE site SET `parsed`='1' WHERE `url`='".$url."'") or die(mysql_error()); } $page->clear(); #ЧИСТОТА - ЗАЛОГ ЗДОРОВЬЯ!! :D unset($page); nextUrl(); } mysql_connect($dbHost,$dbUser,$dbPass) OR DIE("Не могу создать соединение<br />"); mysql_select_db($dbName) or die(mysql_error()); $domain = getDomain("http://www.csat.ru/"); parse("http://www.csat.ru/"); echo "DONE!"; mysql_close(); ?> Скрипт в общем-то прекрасно работает но, есть одно но! На хостинге, куда это дело планируется водрузить, ограничение на выполнение скрипта в 30с. как в общем-то почти везде, и это дело никак не изменить. А парсинг всего сайта, с локалки, занимает порой минут 15-20. Закономерный вопрос: каким образом это ограничение можно преодолеть? И еще вопрос, можно ли каким-либо образом это дело распараллелить? Ну и буду рад услышать комментарии по поводу самого кода. Заранее благодарен!
Если хостер позволяет менять локально настройки PHP на акке, то да, можно, разумеется. Через ini_set() или, у моего хостера, к примеру, разрешено запиливать локальные ini-файлы. Теоретически, да. Вот еще какая-то приблуда для трединга: http://pthreads.org/
если б было можно через локальные ини я бы сделал уже))) но вот проблема в том что менять нельзя, вообще никак, вот такой дибильный хостер у заказчика. Как быть в этом случае?
не совсем хорошее решение но - где-то хранить смещение на котором закончил скрипт, и при повторном запуске начинать от туда. Либо сделать парсер более оптимальным по времени выполнения.
если через ini_set() не получится время сменить, то стучаться в поддержку хостера и выносить мозг. Вы попробуйте все же в самом начале поставить Код (Text): ini_set('max_execution_time', 3600); Если сработает, скрипт будет жить час.
не работает, ну, значит будем выносить мозг у меня скрипт не придирчив к месту окончания, работает он с базой и после парсинга одного урла стучится в базу за следующим неотпарсенным урлом. Есть у меня идея - засекать время начала парса, брать время жизни скрипта и если до окончания времени работы остается n секунд, - перезапускать скрипт, но вот самый главный вопрос - как его перезапускать?
делаешь для sql запроса limit, засечку времени делаешь и сохраняешь между запросами в сессию, ну а перезагрузку страницы можно делать с header refresh, в общем так, когда-то делал такую штуку, если найду кину алгоритм
Можно еще при первом заходе сделать в переменную записать время $time = time(), ну а потом при парсинге сравнивать время разницу(time() - $time) с ограничением хостинга(при условии, что вы добавите величину n упомянутую вами выше).
А можно сказать заказчику, чтобы не был жлобом. А то "хочу грузовик, но чтоб топливо жрал как мопед!" Требует ресурсоемкую приблуду? Пусть выделяет ресурсы.
И я решил написать-это: sleeper.php Код (PHP): <?php function sleeper() { sleep(2); $file='sleeper.txt'; $content=file_get_contents($file); file_put_contents($file,is_file($file) && $content?intval($content+1):1); sleep(2); sleeper(); } sleeper(); ?> LOL!
- ого, так можно что ли? беру на заметку. Добавлено спустя 2 минуты 45 секунд: как вариант поставить денвер (или что там у вас) на своем компе и запустить скрипт без лимита. можно крон повесить.
небольшая. а зачем так делать-то? =) если у нас есть ответ в $content - ето раз два, в пхп такая форма всегда отработает корректно: file_put_contents($file, (int)$content+1); и неебет, есть он или нет он, есть в нем или нет в нем и тд
http://php.ru/manual/info.configuration.html igordata, Ну-это если фанарно, счетчик (и то который только с единицы начнется, а мож я сначала ноль хочу записать), а вот если, что -то большее. Без этой проверки не обойтись, по этому, лучше проверять.