2012-03-27 82 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) 
    } 
}