iceman12, видела. У мну не работает, ставила на vdscenter.com, h2m.ru и сервер. При обычной становке, пишит что ошибка в какой то строке. Эту ошибку я исправила, но он не парсит. Х/з может у меня и руки кривые, но не до такой же степени что я даже не могу установить парсер. Вот что касается парсера библиотеки - по нему я разобралась как работать с текстом.
22 Июн 2010, 14:19Ксения, не тому ответила гг, я автор а не он, и еще те парсеры работали давно , но на сколько я знаю структуру сайта не поменяли и они должны работать и по сей день
22 Июн 2010, 14:21iceman12, синтаксическая ошибка. После того как я её исправила, парсер просто отказывается работать. Бг
Итак, давайте попробуем написать парсер. Мы будем писать универсальный парсер со сменными “боеголовками - выражениями”. Долго думал насчёт многопоточности… и решил что она или будет внешней или её вообще не будет. Она интересна, но в рамках сбора данных по одному запросу она не нужна. Вариант реализации многопоточности… вот:
Начнём с многопоточности, реализуем её по учебнику, внеся свои усовершенствования:
<?php
define("MAX_PROCESSES", 20);
$items = file("keywords.txt");
$system = $_SERVER['argv'][1];
$num_procs = 0;
foreach ($items as $item)
{
$pid = pcntl_fork();
if ($pid == -1)
{
die("could not fork");
}
elseif ($pid)
{
$num_procs++;
if ($num_procs >= MAX_PROCESSES) while ($num_procs >= round(MAX_PROCESSES/2, 0))
{
pcntl_wait($status);
$num_procs--;
echo "wait theards... actual ".$num_procs.", max: ".MAX_PROCESSES."\n";
}
}
else
{
echo date("Y-m-d H:i:s").": start ".trim($item)."\n";
shell_exec("php parser.php ".$system." ".trim($item)." > log.txt & echo \$!");
exit;
}
}
Моё: прибавляем не по одной нити, а ждём когда все “слоты” заполнятся, а потом освобождаем половину (так процесс будет идти более интенсивно). Не забудьте в конце нити сделать exit, иначе сервер ляжет в момент.
Далее, ближе к телу, определим механизм разбора, допустим нужный регэксп будет определяться значением переменной $system и будет считываться из папки pregs, (структуру выложу), тогда нам надо определить для каждой системы:
-выражение для поиска следующей страницы
-выражение для разбора контента
-начальную маску урла
-формат сохранения.
Определим структуру так:
pregs
*google
**pagesRegexp.txt
<td nowrap class=b><a href=\"(.[^\"]*)\">.*Next<\/a>
**regexp.txt
<h2 class=r><a href=\"(.[^\"]*)\" class=l onmousedown=\"return.[^\"]*\">(.*)<\/a>&
lt;\/h2>
**startUrl.txt
http://www.google.com/search?source=ig&hl=en&q=@PARAMETR@&btnG=Google+Search
формат сохранения в файле
item.txt
@1@|@2@
Теперь у нас есть регулярное выражение для поиска следйющей страницы и собственно контента. Сразу скажу, в некоторых системах это неверно, но для большинства применимо. По поводу items, будем считать что это формат сохранения, примеры файлов приведу ниже.
Теперь про отправной урл. Он должен быть, причём он должен быть динамическим. Как правило он зависит от нашего запроса, и не меняет форму… предположим что у нас есть некоторый параметр, который мы будем вводить в командной строке, и на выходе должны получить урл, со вставленным вместо @PARAMETR@ значением.
Для общения с поисковиками будем использовать курл.
Ещё нам понадобится вот функция, ей на вход страницу и урл - она отдаёт абсолютный урл.
в итоге мы получим вот такой код:
<?php
define("MAX_PAGES", 50);
define("PREGS_FOLDER", "pregs");
define("RESULTS_FOLDER", "results");
define("ITEMS_FILE", "items.txt");
define("REGEXP_FILE", "regexp.txt");
define("PAGES_REGEXP_FILE", "pagesRegexp.txt");
define("START_URL_FILE", "startUrl.txt");
define("USER_AGENT", "Mozilla/4.0 (compatible; MSIE 5.01; Widows NT)");
$system = $_SERVER['argv'][1];
$parametr = $_SERVER['argv'][2];
function curlGetPost($url, $referer = null, $postContent = false, $init = false, $followLocation = true)
{
if ($init || !isset($ch)) $ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $followLocation);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
if ($referer) curl_setopt($ch, CURLOPT_REFERER, $referer);
curl_setopt($ch, CURLOPT_USERAGENT, USER_AGENT);
if ($postContent)
{
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postContent);
}
else
{
curl_setopt($ch, CURLOPT_POST, false);
}
if (strtolower(substr($url, 0, 5)) == 'https') {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
}
curl_setopt($ch, CURLOPT_COOKIEFILE, "cooks.txt");
return curl_exec($ch);
}
function getAbsUrl($page, $link)
{
$page = trim($page);
$link = trim($link);
if (strpos($link, "#") !== false) $link = substr($link, 0, strpos($link, "#"));
if (strpos($page, "?") !== false) $page = substr($page, 0, strrpos($page, "?"));
if (strtolower(substr($link, 0, 7)) == "http://") return $link;
if (strtolower(substr($link, 0, 8)) == "https://") return $link;
if (strtolower(substr($link, 0, 4)) == "www.") return "http://".$link;
if (strtolower(substr($link, 0, 7)) == "mailto:") return false;
if (strtolower(substr($link, 0, 11)) == "javascript:") return false;
if (substr($link, 0, 1) == "/")
{
$url = parse_url($page);
$url = "http://".$url['host'].$link;
}
elseif (substr($link, 0, 1) == "?")
{
$url = $page.$link;
}
else
{
$url = substr($page, 0, strrpos($page, "/")+1).$link;
}
while (strpos($url, "../") !== false)
{
$nstr = substr($url, 0, strpos($url, "../") - 1);
$nstr = substr($nstr, 0, strrpos($nstr, "/")+1);
if (substr($nstr, -2) == "//") return false;
$url = $nstr.substr($url, strpos($url, "../") +3);
}
$url = str_replace("./", "", $url);
return $url;
}
if (!file_exists($pregFolder = "./".PREGS_FOLDER."/".$system."/"&
#41;)
{
echo "Parser regular extension dont exists\n";
exit;
}
else
{
//формат сохранения
if (!file_exists($itemsFile = $pregFolder.ITEMS_FILE))
{
echo "Items file not exists\n";
exit;
} else echo "items - ok\n";
$items = file_get_contents($itemsFile);
//регэксп для контента
if (!file_exists($regexpFile = $pregFolder.REGEXP_FILE))
{
echo "Regexp file not exists\n";
exit;
} else echo "regexp - ok\n";
$regexp = file_get_contents($regexpFile);
//регэксп для сделующей страницы
if (!file_exists($pagesRegexpFile = $pregFolder.PAGES_REGEXP_FILE))
{
echo "Pages regexp file not exists\n";
exit;
} else echo "pages - ok\n";
$pagesRegexp = file_get_contents($pagesRegexpFile);
//стартовый урл
if (!file_exists($startUrlFile = $pregFolder.START_URL_FILE))
{
echo "Start url file not exists\n";
exit;
} else echo "start page - ok\n";
$startUrl = str_replace("@PARAMETR@", urlencode($parametr), file_get_contents($startUrlFile));
$tackt = 0;
$fp = fopen("./".RESULTS_FOLDER."/result_".dat
e("Ymd-His").".txt", 'w');
$url = $startUrl;
$grabAll = 0;
do
{
$tackt++;
$content = curlGetPost($url, $url);
if ($grab = preg_match_all("/".$regexp."/iUs", $content, $result))
{
unset($result[0]);
foreach ($result[1] as $key => $value)
{
$source = trim($items);
foreach ($result as $lineKey => $lineValue)
{
$source = str_replace("@".$lineKey."@", $result[$lineKey][$key], $source);
}
fwrite($fp, $source."\n");
}
$grabAll += $grab;
echo "Tackt ".$tackt.", grab:".$grab.", all: ".$grabAll."\n";
}
else
{
echo "Tackt ".$tackt.", current empty, all: ".$grabAll."\n";
}
if (!preg_match("/".$pagesRegexp."/iUs"
, $content, $result))
{
echo "Parsing ends, next page not found, tackt: ".$tackt."\n";
fclose($fp);
exit;
}
else
{
$url = getAbsUrl($url, $result[1]);
}
} while ($tackt <= MAX_PAGES);
}