2012-03-27 8 views
1

DOMDocumentDOMXPathに必要なHTMLデータがあります。XPathクエリとHTML - アンカー内で特定のHREFを検索するタグ

しかし、特定の<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")]]'); 

しかし、最終的には#1のようなhrefを含むすべてのアンカータグにアクセスする必要があります。 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の値にアクセスできないようです。私がこの質問のために何らかのプロトコルを遵守しなかったなら、私の謙虚な謝罪...

ANY/ALLヘルプは大歓迎です! Thanxあまりにも前に!

+0

hrefの値をフィルタすることが必要ですXPathクエリのみを使用しますか?私はそれが可能だと確信していますが、私の頭がそれを見て痛い(典型的なXPath)。おそらく '$ xpath-> query()'を使用して、幅広いパターン(例えば、 'href =" https://some-site.vendor.com/jobs/ ")にマッチするノードのリストを取得し、数行のPHPを使用して、各ノードのhrefの値をより詳細に調べてください。 –

+0

「XPath 1.1」ではなく「XPath 1.0」は、これを不必要に冗長にしています...しかし、これはすべて私たちが持っているものです。私は['registerphpfunctions'](http://php.net/manual/en/domxpath.registerphpfunctions.php)との正規表現マッチを行う関数を作成します。 – Wrikken

答えて

1

xpathでこれを行うのはお勧めしません。まず、ホワイトリストとブラックリストがあります。あなたが何を望んでいるかは本当にはっきりしていないので、時間の経過と共に変化すると思います。

だから、最初にすべてのhref属性を選択してノードを返すことができます。それはXPathがために非常に良いものだ、それでは、XPathを使ってみましょう:

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

あなたは今$linksで共通DOMNodeListを持っているし、我々はそれらを選択しているとして、それがゼロ以上DOMAttrの要素が含まれています。これらは今あなたが探しているフィルタリングを必要とします。

だから、一致させたいと思う基準がいくつかあります。冗長ではありますが、それがどのように機能すべきかは非常に具体的ではありません。肯定的な一致がありますが、否定的な一致もあります。しかし、どちらの場合でも、もしそうでなければ何が起こるべきかを言わないでください。だから私はここにショートカットを実行します。

function is_valid_href($href) { 

    // do whatever you see fit ... 

    return true or false; 
} 

のでhrefが現在有効であるかどうかを伝えるの問題があります。"href"文字列が基準(複数可)と一致する場合は、自分自身のいずれかtrueまたはfalseを返す関数を書きます解決されました。良いこと:後で変更することができます。

リンクとの統合は、すべてのリンクを正規化された絶対形式で取得することだけです。これは、より多くのデータ処理を意味し、以下を参照してください。URLの正規化のさまざまな種類の詳細については

を。

したがって、hrefの正規化、ベース解決、および検証をカプセル化する別の関数を作成します。 HREFが間違っている場合には、それだけでそれ以外の場合は、正規化のhref、nullを返します。

function normalize_href($href, $base) { 

    // do whatever is needed ... 

    return null or "href string"; 
} 

は、バリデータがそれの恩恵を受けることができますので、私の場合は私もHREF Net_URL2インスタンスを作成し、ご一緒にこれを入れてみましょう。

もちろん、これをクロージャーやいくつかのクラスにまとめると、より良いインターフェースが得られます。また、あなたは同様に、XPath式のパラメータを作ることを検討couold:

// 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) 
    } 
} 
関連する問題