2012-03-27 103 views
1

我已获得DOMDocumentDOMXPath中所需的HTML数据。XPath查询和HTML - 在锚标签中查找特定的HREF

但我需要访问并检索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,一个d将实际的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值。我最不高兴的道歉,如果我没有遵循这个问题的任何种类的协议...

任何/所有的帮助将不胜感激! Thanx提前多少!

+0

是否有必要筛选HREF值仅使用XPath查询?我确信这是可能的,但是我的头很痛苦(典型的XPath)。也许你可以使用'$ xpath-> query()'来获得一个与广泛模式匹配的节点列表(例如'href =“https://some-site.vendor.com/jobs/”'),然后使用几行PH​​P来更深入地检查每个节点的href值? – 2012-06-08 20:13:22

+0

“XPath 1.0”而不是“XPath 1.1”肯定会造成这种不必要的冗长......但这就是我们所有的a.t.m.我会创建一个函数,它可以与['registerphpfunctions'](http://php.net/manual/en/domxpath.registerphpfunctions.php)进行正则表达式匹配。 – Wrikken 2012-07-01 11:35:40

回答

1

这样做完全与xpath我不会建议。首先你有一个白名单和一个黑名单。这是不是很清楚你想要什么,所以我认为这可以随着时间的推移而改变。

所以你可以做的是首先选择所有href属性并返回节点。这就是XPath是非常好的,所以让我们使用XPath:

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

你现在有$links共同DOMNodeList和我们选择那些它包含的零个或多个DOMAttr元素。这些现在需要你正在寻找的过滤。

所以你有一些你想匹配的标准。你有详细的但不是很具体的应该如何工作。你有一个积极的比赛,但也有负面的比赛。但是在这两种情况下,你都不知道如果没有,会发生什么。所以,我在这里做一个快捷方式:你自己写的返回要么truefalse一个功能,如果一个"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实例,以便验证可以从中受益。

当然,如果你把它封装到闭包或某些类中,它会有一个更好的接口。您还couold考虑使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) 
    } 
}