XPath查询&;HTML-查找特定HREF';s在锚定标记内


XPath Query & HTML - Find Specific HREF's Within Anchor Tags

我得到了DOMDocumentDOMXPath中所需的HTML数据。

但我需要访问和检索某些<a>标签中的href值。以下是标准:

  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值。如果我没有遵守这个问题的任何协议,我最谦卑的道歉。。。

任何/所有帮助都将不胜感激!提前感谢!

我不建议只使用xpath来执行此操作。首先,你有一个白名单和一个黑名单。目前还不清楚你想要什么,所以我认为这可能会随着时间的推移而改变。

因此,您可以做的是首先选择所有有问题的href属性并返回节点。这就是Xpath非常好的功能,所以让我们使用Xpath:

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

现在,您在$links中有了公共DOMNodeList,并且它包含零个或多个DOMAttr元素,因为我们已经选择了这些元素。这些现在需要您正在寻找的筛选。

所以你有一些你想要匹配的标准。您有详细但不太具体的工作方式。你有积极的匹配,但也有消极的匹配。但在这两种情况下,你都不知道如果不知道会发生什么。所以我在这里做了一个快捷方式:您自己编写一个函数,如果"href"字符串符合条件,则返回truefalse

function is_valid_href($href) {
    // do whatever you see fit ...
    return true or false;
}

因此,判断CCD_ 26现在是否有效的问题已经得到解决。最好的办法:你可以稍后更改。

因此,所有需要的是将其与链接集成,以获得所有链接的标准化和绝对形式。这意味着更多的数据处理,请参阅:

  • 使用php-domdocument添加根路径的问题
  • URL代码和文件集内容

有关不同类型的URL规范化的更多详细信息。

因此,我们创建了另一个函数,它封装了away-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 = 'https://stackoverflow.com/questions/9894956/xpath-query-html-find-specific-hrefs-within-anchor-tags';
/**
 * @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)
  }
}