Парсер Web Archive на PHP бесплатно!

B1
На сайте с 13.12.2012
Offline
28
17038

нашлось немного времени... решил допилить старый скрипт парсера WA.

выкладываю версию с основным функционалом работы WA с помощью Momento API, а именно получения всех возможных копий документа по датам.

собственно код:


class webarchivedump {
var $params = array();
var $captures = array();
var $proxylist = array();

/*
* params - опции парсинга
*/
function __construct($params = array()) {
// точка парсинга (дата время)
$this->params['datetime'] = isset($params['datetime']) ? $params['datetime'] : time();
// в какую сторону искать отсутствуйший документ. допустимо: 'prev' or 'back'
$this->params['search_range'] = isset($params['search_range']) ? $params['search_range'] : 'back';
// пропускать(фильтр) URL - строка RegEx
$this->params['not_allow_url_regex'] = isset($params['not_allow_url_regex']) ? $params['not_allow_url_regex'] : false;
// пропускать(фильтр) файлы по расширению(jpg,txt,css, ect...) - строка RegEx
$this->params['not_allow_ext_regex'] = isset($params['not_allow_ext_regex']) ? $params['not_allow_ext_regex'] : false;
// callback функция филтра ответа
/* урезано! */ $this->params['callback_func'] = isset($params['callback_func']) ? $params['callback_func'] : false;
}

/*
* запуск дампера
* domain - имя домена
*/
function exec($domain) {
// месяцы 3-х символы
$months = array(
1 => 'Jan', 2 => 'Feb', 3 => 'Mar', 4 => 'Apr', 5 => 'May', 6 => 'Jun',
7 => 'Jul', 8 => 'Aug', 9 => 'Sep', 10 => 'Oct', 11 => 'Nov', 12 => 'Dec'
);

// запрос по домену на WA
if (($result = $this->get_url('http://web.archive.org/web/*/'.$domain.'*'))) {
// проверка наличия копий сайта в архиве и возможные ошибки (если не было 404 кода)
if (preg_match_all("/<div id=\"error\">(.*)<\/div>/Uis", $result['content'], $matches)) {
exit('Wayback error: '.$matches[1][0]);
}

// находим все доступные снимки(URL)
if (!preg_match_all("/\"\/web\/.+\">(.*)</i", $result['content'], $matches)) {
exit('Not found captures');
}

unset($result);

// парсим и преобразуем URL (готовим к закачке)
foreach($matches[1] as $m) {
$purl = parse_url($m);
// фильтр указаных URL
if ($this->params['not_allow_url_regex'] && preg_match($this->params['not_allow_url_regex'], $m))
continue;
// фильтр по расширению файла(*.ext)
if ($this->params['not_allow_ext_regex'] && preg_match($this->params['not_allow_ext_regex'], pathinfo($purl['path'], PATHINFO_EXTENSION)))
continue;

$this->captures[] = array(
'captured_url' => $m, // URL снимка на WA
'relative_url' => $purl['path'].(empty($purl['query']) ? '' : '?'.$purl['query']), // относительные URL
'absolute_url' => $purl['scheme'].'://'.$domain.$purl['path'].(empty($purl['query']) ? '' : '?'.$purl['query']), // абсолютные URL
);
}

// UP: by Momento API
// https://archive.org/help/wayback_api.php or http://mementoweb.org/
foreach ($this->captures as $n => $row) {
// получаем все копии URL - momento (timemap)
if (!($result = $this->get_url('http://web.archive.org/web/timemap/link/'.$row['captured_url']))) {
echo('fail! get_url: '.$row['captured_url']);
continue;
}

// парсим ответ timemap
// !внимание! при большом кол-ве копий снимков(на старых трастовых сайтах) хорошо кушает память
if ($count = preg_match_all("#<(.+)>; rel=\".*memento\"; datetime=\"(.+)\"#i", $result['content'], $matches, PREG_SET_ORDER)) {
$links = array(); // ссылки
// забираем все возможные снимки
for ($x = 0; $x < $count; $x++) {
// замена 3-х символа месяца на число
$matches[$x][2] = str_replace(array_values($months), array_keys($months), $matches[$x][2]);
// формируем unix_timestamp
if (!preg_match("#(\d{1,2}) (\d{1,2}) (\d{4}) (\d{2}):(\d{2}):(\d{2})#i", $matches[$x][2], $uts)) {
echo('Invalid parsing timestamp['.$matches[$x][2].']');
continue;
}
$unix_timestamp = mktime($uts[4], $uts[5], $uts[6], $uts[2], $uts[1], $uts[3]);

// формируем массив с ссылками на закачку
$links[] = array(
'url' => $matches[$x][1],
'datetime' => $unix_timestamp
);
}
/* clear %mamory% */
unset($matches);

// развернем массив если поиск идет назад
if ($this->params['search_range'] == 'back')
$links = array_reverse($links);
// погнала закачка с поиском документа по дате
for ($x = 0; $x < $count; $x++) {
if ((($this->params['search_range'] == 'back') && ($links[$x]['datetime'] <= $this->params['datetime'])) ||
(($this->params['search_range'] == 'prev') && ($links[$x]['datetime'] >= $this->params['datetime']))) {
$dbg = array(
'url' => $links[$x]['url'],
'position' => $x,
'found_datetime' => $links[$x]['datetime'],
'search_datetime' => $this->params['datetime'],
);

$result = $this->get_url($links[$x]['url']);
// нет документа на текущую дату
if ($result['code'] == 404) {
echo("<pre>Not found: {$links[$x]['url']}</pre>");
continue; // вернемся и ишим на ближайшую
}
// редирект
// !пока для меня доконца не понятно в каких случаях WA может отдать редирект и что!
if ($result['code'] >= 300 && $result['code'] <= 302) {
echo("<pre>Redirect: [{$links[$x]['url']}] -> [---]</pre>");
}
// юююппппиии!
if ($result['code'] == 200) {
$this->captures[$n]['loaded'] = true; // ставим метку !удачно получено
$this->captures[$n]['datetime'] = $links[$x]['datetime']; // метка времени документа
$this->filter($this->captures[$n], $result, $dbg);
break;
}
}
}

unset($links);

// !документ не был найден!
if (!isset($this->captures[$n]['loaded'])) {
echo("<pre>document not found: {$row['captured_url']}</pre>");
}

} // timemap

} // foreach

/* end:)! */
return true;
}

/* fail:(! */
return false;
}

/* урезано! */
function filter($info, $response, $dbg = array()) {
echo("<pre>Wayback URL: {$dbg['url']}</pre>");
echo("<pre>Found date: ".date("d.m.Y G:i:s", $dbg['found_datetime'])."</pre>");
echo("<pre>Searched date: ".date("d.m.Y G:i:s", $dbg['search_datetime'])."</pre>");
echo("<pre>--------------------------------------------------------------------------</pre>");
flush();
/*
* $info - данные из массива $this->captures[$n]
* $response['content'] - контент страницы
* $response['headers'] - заголовки ответа WA
*/
}

/* урезано!: без прокси и fsock */
function get_url($url) {
$content = null;
$headers = array();
$headers = get_headers($url, 1);
if ($headers[0] != 'HTTP/1.1 404 Not Found')
$content = file_get_contents($url);
preg_match("/^HTTP\/1\.1 (\d+) (.+)$/i", $headers[0], $m);
$code = intval($m[1]);
return (!$headers || !$content) ? false : array('code' => $code, 'headers' => $headers, 'content' => $content);
}
}
// пример
$wad = new webarchivedump(array(
//'not_allow_url_regex' => "#.+(news|faq).*$#i",
//'not_allow_ext_regex' => "#(gif|jpg|bmp|js|css|jpeg|php|png)$#i",
'datetime' => mktime(0, 0, 0, 12, 31, 2013),
'search_range' => 'back',
));
$wad->exec('xxxxxx.com');

хорошо было-бы услышать замечания по работе скрипта....

ishipilov
На сайте с 25.12.2011
Offline
101
#1

а почему самое вкусное урезано?

B1
На сайте с 13.12.2012
Offline
28
#2
ishipilov:
а почему самое вкусное урезано?

а что под вкусным подразумевается? сохранить копию на диск? работа через прокси?

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий