Выдирание URL-ов из HTML

Cyber Jack

Новичок
Выдирание URL-ов из HTML

Нужно выдернуть из HTML потока гиперссылки из тегов типа <a href="траливали">

То, что заключено в кавычки (траливали) нужно выдернуть.

Возможно есть уже готовые скрипты? Я не могу найти... уже целый день парюсь...
 

Cyber Jack

Новичок
Автор оригинала: fixxxer
А чем тебя этот не устраивает?
Неустраивает, тем, что мало выдерает :) Если забабахать HTML поток по более, то вырывает только первые несколько урлов, а урлы которые в конце потока не выдерает. Хз почему. Ктонить знает почему?

-~{}~ 16.07.04 19:45:

Автор оригинала: Dallas
Есть- вручную.
Юморист :)
 

Sir_J

Guest
Потрудись объяснить что сие
>> то вырывает только первые несколько урлов <<
означает
 

Dallas

Guest
Возможно, я ошибаюсь, но... вот выдержка из той же статьи:
"максимальная длинна совпадения регулярного выражения равна m символов"
Возможно, ф-ция захлебывается целым потоком? Попробуй разбить на строки и по одной "кормить" проверку.

-~{}~ 16.07.04 20:25:

Кстати, если я правильно понимаю суть этого макс. числа m, то чем оно определяется? В статье были непонятные моменты, в частности с:
/(?<=url\()[a-z.\/]*(?=\))/i
откуда последний символ взялся?
Отвечать не обязательно, все равно буду углубляться по иным источникам.
 

Cyber Jack

Новичок
Вощем раскопал дальше, оказалось дело не в объеме, просто далее встречались ссылки вида

index.php?link=1&a=add

в выражение следующее

"/(?<=href=\"()[a-z.\/]*(?=\")/i"

улавливаете? :)

нада так

"/(?<=href=\")[_0-9a-z.=\?\/\&]*(?=\")/i"

и все работает :)

-~{}~ 16.07.04 20:43:

Далее, столкнулся с проблемой относительных ссылок вида

../../img/

итп.

а нужны абсолютные (я подставляю вперед имя домена)

в итоге ссылки неправильные получаются.
 

valyala

Новичок
Я использовал функцию fetch_all_urls(), размещенную ниже, для создания простого спайдера, скачивающего из инета html-ки. Может быть, кому-нибудь пригодится.
PHP:
/**
    Вырезает все url-ы вида href=[url] из текста $str.
    Преобразует url-ы к абсолютным, как это делают браузеры,
    если считать, что они находятся на странице по адресу $base_url.
*/
function fetch_all_urls($base_url, $str)
{
    $tmp = parse_url($base_url);

    // формируем имя сервера
    if (!isset($tmp['scheme'])) $tmp['scheme'] = 'http';
    if (!isset($tmp['host'])) $tmp['host'] = 'microsoft.com';
    $server = $tmp['scheme'] . '://' . $tmp['host'];

    // формируем путь к документу на сервере
    if (!isset($tmp['path'])) $tmp['path'] = '/';
    $doc_path = $tmp['path'];

    // удаляем из пути вложенные каталоги типа . и ..
    $tmp1 = parse_doc_path($doc_path);
    $doc_path = $tmp1['path'];
    $dir_name = $tmp1['dir'];

    // добавляем к пути строку query_string, если она есть
    if (isset($tmp['query'])) $doc_path .= '?' . $tmp['query'];

    // достаем url-ы, взятые в кавычки (одинарные и двойные)
    $a = array();
    preg_match_all('/href\s*=\s*(?:' . '([\'"])(.*?)\\1)/s', $str, $a);
    $urls = $a[2];

    // достаем url-ы без кавычек
    $a = array();
    preg_match_all('/href\s*=\s*([^\\s>"\'][^\\s>]*)/', $str, $a);
    $urls = array_merge($urls, $a[1]);

    // обрабатываем url-ы
    $n = sizeof($urls);
    for ($i = 0; $i < $n; $i++) {
        // декодируем htmlentities во всех url-ах
        $url = html_entity_decode($urls[$i]);
        $url = preg_replace('/&#(?:0*)(\d+);/e', 'chr(\\1)', $url);

        // преобразуем все url-ы в асболютные ссылки (начинающиеся с http://)
        if (strlen($url) == 0) {
            // пустая ссылка
            $url = $server . $doc_path . (isset($tmp['fragment']) ? ('#' . $tmp['fragment']) : '');
        } else if ($url{0} == '#') {
            // якорь
            $url = $server . $doc_path . $url;
        } else {
            if (!preg_match('/^(http|ftp|mailto):/', $url)) {
                // относительные ссылки
                if ($url{0} != '/') {
                    // ссылка, относительно текущего каталога
                    $url = $dir_name . $url;
                }
                $tmp1 = parse_doc_path($url);
                $url = $server . $tmp1['path'];
            }
        }

        $urls[$i] = $url;
    }

    // удаляем повторяющиеся url-ы
    $urls = array_unique($urls);

    return $urls;
}

/***********************************************************************/
/**
    Фильтрует абсолютный путь к каталогу (т.е. начинающийся со слэша /)
    Удаляет из него каталоги вида . и ..
    Добавляет в начало пути слэш, если его там не было
    Возвращает ассоциативный массив со следующими элементами:
      [path] - отфильтрованный путь к файлу (фактически [dir] + [file])
      [file] - имя файла
      [dir] - путь к каталогу, в котором лежит файл
*/
function parse_doc_path($path)
{
    $path = strtr($path, '\\', '/'); // заменяем бэкслэши на обычные слэши
    $a = explode('/', $path);

    if (!sizeof($a)) {
        return array('path' => '/', 'file' => '', 'dir' => '/');
    }

    $b = array();
    foreach ($a as $part) {
        if (!strlen($part)) continue; // пропускаем строку нулевой длины
        if ($part == '.') continue; // пропускаем одинарную точку (указывает сама на себя)
        if (preg_match('/\\.{2,}/', $part)) {
            if (sizeof($b)) array_pop($b);
            continue;
        }
        array_push($b, $part);
    }

    $file = array_pop($a);
    if (strlen($file)) array_pop($b);
    $dir = '/' . implode('/', $b);
    if (strlen($dir) > 1) $dir .= '/';

    return array('path' => $dir . $file, 'file' => $file, 'dir' => $dir);
}
 

advocat

developer
хочу кое что добавить из практики :)

PHP:
preg_match_all("'<\s*a\s.*?href\s*=\s*([\"\'])?(?(1) (.*?)\\1 | ([^\s\>]+))'isx", $text, $matches, PREG_SET_ORDER);
for($i=0; $i < count($matches); $i++) {
    $link = preg_replace("/(\r\n|\n|\r)+/", "", $matches[$i][2]);
    $links[$link] = 1;
}
 

SiMM

Новичок
Автор оригинала: advocat
<\s*a\s.*?href\s*=\s*([\"\'])?(?(1) (.*?)\\1 | ([^\s\>]+))
Интересно, где в стандарте HTML ты откопал допустимость первого (< a ...)? А во втором случае не хватает наличия обязательного пробела перед href (<a nohref=...).
 

advocat

developer
SiMM

сдесь я с тобой согласен, код писался давно, как ни странно :) до сих пор работает. Но некоторые коррективы я внес :)
по поводу <\s - сенкс,
 

Motor

Guest
Стал изобретать свой велосепед.
Регулярные выражения знаю плохо, поэтому возникла проблема:

для того чтоб наглядно показать изменил и упростил код.

$st="111 <a href='paradox.tom.ru'>xxx</a> 222 <a href='paradox.tom.ru'>yyy</a>";

echo preg_replace ("(<a\s+href\s*=\s*[\"'](\S+)[\"'].*>\s*(\S*)\s*<\/a\s*>)", '',$st);

вывод: 111
надо чтоб было:111 222

Т.е. поиск работает неправельно (2урла сливаються в один), где обшибка?
 

Motor

Guest
Хы.. :) И правда с утра всегда хорошо думаеться, просто убрал "жадность" в рег. выражении и все заработало.
 
Сверху