XPath Query & HTML - Найти конкретные HREF в тегах привязки - PullRequest
1 голос
/ 27 марта 2012

У меня есть данные HTML, необходимые в DOMDocument и DOMXPath.

Но мне нужно получить доступ и получить значения href в определенных тегах <a>.Следующие критерии:

  1. href содержит: some-site.vendor.com/jobs/[#idnumber]/job (то есть some-site.vendor.com/jobs/23094/job)

  2. href не содержит:some-site.vendor.com/jobs/search?search=pr2

  3. href не содержит: some-site.vendor.com/jobs/intro

  4. href не содержит: www.someothersite.com/

  5. href не содержит: media.someothersite.com/

  6. href не содержит: javascript:void(0)

Либоиз этих (похожих) запросов извлекает все, кроме 4-6 - это хорошо:

$joblinks = $xpath->query('//a[@href[contains(., "https://some-site.vendor.com/jobs/")]]');    
$joblinks = $xpath->query('//a[@href[contains(., "job")]]');

В конечном счете, однако, мне нужно получить доступ ко всем тегам привязки, содержащим href, как # 1, и назначить фактические значения href в пределахв переменную / массив.Вот что я делаю:

$payload = fetchRemoteData(SPEC_SOURCE_URL);

// suppress warning(s) due to malformed markup
libxml_use_internal_errors(true);

// load the fetched contents
$dom = new DOMDocument();
$dom->preserveWhiteSpace = false;
$dom->loadHTML($payload);

// parse and cache the required data elements
$xpath = new DOMXPath($dom);

//$joblinks = $xpath->query('//a[@href[contains(., "some-site.vendor.com/jobs/")]]');
$joblinks = $xpath->query('//a[@href[contains(., "job")]]');
foreach($joblinks as $joblink) {
    var_dump(trim($joblink->nodeValue)); // dump hrefs here!
}
echo "\n";

Это действительно бьет меня - я близок, но я просто не могу корректно настроить запрос и / или получить доступ к фактическим значениям href.Мои самые скромные извинения, если я не следую протоколу любого рода по этому вопросу ...

ЛЮБАЯ / ВСЕ помощь будет принята с благодарностью!СПАСИБО ЗА ГЛАВНОЕ!

1 Ответ

1 голос
/ 01 июля 2012

Делать это исключительно с xpath Я бы не советовал. Прежде всего, у вас есть белый и черный список. Не совсем понятно, чего вы хотите, поэтому я предполагаю, что со временем это может измениться.

Итак, вы можете сначала выбрать все href рассматриваемые атрибуты и вернуть узлы. Вот для чего очень хорош Xpath, поэтому давайте используем xpath:

if (!$links = $xpath->query('//a/@href')) {
    throw new Exception('XPath query failed.');
}

Теперь у вас есть общий DOMNodeList в $links, и он содержит ноль или более DOMAttr элементов, как мы их выбрали. Теперь им нужна фильтрация, которую вы ищете.

Итак, у вас есть некоторые критерии, которым вы хотите соответствовать. У вас есть подробные, но не очень конкретные, как это должно работать. У вас есть положительное совпадение, а также отрицательные совпадения. Но в обоих случаях вы не говорите, что должно произойти, если нет. Поэтому я делаю ярлык здесь: вы пишете себе функцию, которая возвращает либо true, либо false, если строка "href" соответствует критерию (ам):

function is_valid_href($href) {

    // do whatever you see fit ...

    return true or false;
}

Таким образом, проблема определения, является ли href действительным или нет, была решена. Лучшая вещь: вы можете изменить его позже.

Так что все, что нужно, это интегрировать это со ссылками, чтобы получить все ссылки в их нормализованном и абсолютном виде. Это означает больше обработки данных, см .:

для более подробной информации о различных типах нормализации URL.

Итак, мы создаем еще одну функцию, которая инкапсулирует href нормализацию, базовое разрешение и проверку. Если href неверен, он просто возвращает null, иначе нормализованный href:

function normalize_href($href, $base) {

    // do whatever is needed ...

    return null or "href string";
}

Давайте соединим это, в моем случае я даже сделаю href экземпляром Net_URL2, чтобы валидатор мог извлечь из него пользу.

Естественно, если вы заключите это в замыкания или некоторые классы, получится более приятный интерфейс. Также вы можете сделать выражение xpath параметром:

// get all href
if (!$links = $xpath->query('//a/@href')) {
    throw new Exception('XPath query failed.');
}

// set a base URL
$base = '/8196211/xpath-query-html-naiti-konkretnye-href-v-tegah-privyazki';

/**
 * @return bool
 */
function is_valid_href($href) {    
    ...
}

/**
 * @return href
 */
function normalize_href($href, $base) {
    ...
}

$joblinks = array();
foreach ($links as $attr) {
    $href = normalize_href($attr->nodeValue, $base);
    if (is_valid_href($href)) {
        $joblinks[] = $href;
    }
}

// your result is in:
var_dump($joblinks);

Я запустил пример на этом сайте, и результат:

array(122) {
  [0]=>
  object(Net_URL2)#129 (8) {
    ["_options":"Net_URL2":private]=>
    array(5) {
      ["strict"]=>
      bool(true)
      ["use_brackets"]=>
      bool(true)
      ["encode_keys"]=>
      bool(true)
      ["input_separator"]=>
      string(1) "&"
      ["output_separator"]=>
      string(1) "&"
    }
    ["_scheme":"Net_URL2":private]=>
    string(4) "http"
    ["_userinfo":"Net_URL2":private]=>
    bool(false)
    ["_host":"Net_URL2":private]=>
    string(17) "stackexchange.com"
    ["_port":"Net_URL2":private]=>
    bool(false)
    ["_path":"Net_URL2":private]=>
    string(1) "/"
    ["_query":"Net_URL2":private]=>
    bool(false)
    ["_fragment":"Net_URL2":private]=>
    bool(false)
  }
  [1]=> 

  ...

  [121]=>
  object(Net_URL2)#250 (8) {
    ["_options":"Net_URL2":private]=>
    array(5) {
      ["strict"]=>
      bool(true)
      ["use_brackets"]=>
      bool(true)
      ["encode_keys"]=>
      bool(true)
      ["input_separator"]=>
      string(1) "&"
      ["output_separator"]=>
      string(1) "&"
    }
    ["_scheme":"Net_URL2":private]=>
    string(4) "http"
    ["_userinfo":"Net_URL2":private]=>
    bool(false)
    ["_host":"Net_URL2":private]=>
    string(22) "blog.stackoverflow.com"
    ["_port":"Net_URL2":private]=>
    bool(false)
    ["_path":"Net_URL2":private]=>
    string(30) "/2009/06/attribution-required/"
    ["_query":"Net_URL2":private]=>
    bool(false)
    ["_fragment":"Net_URL2":private]=>
    bool(false)
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...