การจับแอตทริบิวต์ href ขององค์ประกอบ A


114

พยายามค้นหาลิงก์ในหน้า

regex ของฉันคือ:

/<a\s[^>]*href=(\"\'??)([^\"\' >]*?)[^>]*>(.*)<\/a>/

แต่ดูเหมือนจะล้มเหลวที่

<a title="this" href="that">what?</a>

ฉันจะเปลี่ยน regex เพื่อจัดการกับ href ที่ไม่ได้วางไว้ก่อนในแท็กได้อย่างไร

คำตอบ:


208

ความน่าเชื่อถือ Regex เพื่อใช้ HTML เป็นเรื่องยาก นี่คือวิธีดำเนินการกับDOM :

$dom = new DOMDocument;
$dom->loadHTML($html);
foreach ($dom->getElementsByTagName('a') as $node) {
    echo $dom->saveHtml($node), PHP_EOL;
}

ข้างต้นจะค้นหาและส่งออก"outerHTML"ของAองค์ประกอบทั้งหมดใน$htmlสตริง

ในการรับค่าข้อความทั้งหมดของโหนดคุณต้องทำ

echo $node->nodeValue; 

เพื่อตรวจสอบว่ามีhrefแอตทริบิวต์อยู่หรือไม่คุณสามารถทำได้

echo $node->hasAttribute( 'href' );

ที่จะได้รับhrefแอตทริบิวต์ที่คุณต้องการจะทำอย่างไร

echo $node->getAttribute( 'href' );

หากต้องการเปลี่ยนhrefแอตทริบิวต์ที่คุณต้องการจะทำอย่างไร

$node->setAttribute('href', 'something else');

การลบhrefแอตทริบิวต์ที่คุณต้องการจะทำอย่างไร

$node->removeAttribute('href'); 

คุณยังสามารถค้นหาhrefแอตทริบิวต์ได้โดยตรงด้วยXPath

$dom = new DOMDocument;
$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
$nodes = $xpath->query('//a/@href');
foreach($nodes as $href) {
    echo $href->nodeValue;                       // echo current attribute value
    $href->nodeValue = 'new value';              // set new attribute value
    $href->parentNode->removeAttribute('href');  // remove attribute
}

ดูเพิ่มเติมที่:

เกี่ยวกับเรื่องเล็กน้อย: ฉันแน่ใจว่ามันซ้ำกันและคุณสามารถหาคำตอบได้จากที่ไหนสักแห่งที่นี่


regex ที่เชื่อถือได้สำหรับการแยกวิเคราะห์ HTML นั้นเป็นไปไม่ได้เลยแม้ว่า HTML จะไม่ใช่ภาษาปกติก็ตาม
Asciiom

19

ฉันเห็นด้วยกับกอร์ดอนคุณต้องใช้โปรแกรมแยกวิเคราะห์ HTML เพื่อแยกวิเคราะห์ HTML แต่ถ้าคุณต้องการ regex จริงๆคุณสามารถลองสิ่งนี้:

/^<a.*?href=(["\'])(.*?)\1.*$/

สิ่งนี้จะจับคู่<aที่จุดเริ่มต้นของสตริงตามด้วยจำนวนอักขระใด ๆ (ไม่โลภ) .*?จากนั้นhref=ตามด้วยลิงก์ที่ล้อมรอบด้วยอย่างใดอย่างหนึ่ง"หรือ'

$str = '<a title="this" href="that">what?</a>';
preg_match('/^<a.*?href=(["\'])(.*?)\1.*$/', $str, $m);
var_dump($m);

เอาท์พุท:

array(3) {
  [0]=>
  string(37) "<a title="this" href="that">what?</a>"
  [1]=>
  string(1) """
  [2]=>
  string(4) "that"
}

เพียงเพื่อดูข้อมูล: หากเราค้นหาในข้อความที่มีองค์ประกอบมากกว่านิพจน์ (. *?) ผิด
Michal - wereda-net

5

รูปแบบที่คุณต้องการค้นหาน่าจะเป็นรูปแบบจุดยึดลิงก์เช่น (บางอย่าง):

$regex_pattern = "/<a href=\"(.*)\">(.*)<\/a>/";

1
จะเกิดอะไรขึ้นถ้าจุดยึดมีคุณสมบัติมากกว่านี้?
funerr

3

ทำไมคุณไม่จับคู่

"<a.*?href\s*=\s*['"](.*?)['"]"

<?php

$str = '<a title="this" href="that">what?</a>';

$res = array();

preg_match_all("/<a.*?href\s*=\s*['\"](.*?)['\"]/", $str, $res);

var_dump($res);

?>

แล้วก็

$ php test.php
array(2) {
  [0]=>
  array(1) {
    [0]=>
    string(27) "<a title="this" href="that""
  }
  [1]=>
  array(1) {
    [0]=>
    string(4) "that"
  }
}

ซึ่งได้ผล ฉันเพิ่งถอดวงเล็บปีกกาแรกออก


2
ฉันขอแนะนำให้ใช้preg_match_all("/<a.*?href\s*=\s*['\"](.*?)['\"]/", $str, $res, PREG_SET_ORDER);เพื่อจับค่า href ทั้งหมดในการใช้อย่างถูกต้องforeach($res as $key => $val){echo $val[1]}
Ignacio Bustos

3

สำหรับผู้ที่ยังไม่ได้รับโซลูชันที่ง่ายและรวดเร็วโดยใช้ SimpleXML

$a = new SimpleXMLElement('<a href="www.something.com">Click here</a>');
echo $a['href']; // will echo www.something.com

มันใช้งานได้สำหรับฉัน


2

ฉันไม่แน่ใจว่าคุณกำลังพยายามทำอะไรที่นี่ แต่ถ้าคุณกำลังพยายามตรวจสอบความถูกต้องของลิงก์ให้ดูที่ filter_var () ของ PHP

หากคุณต้องการใช้นิพจน์ทั่วไปจริงๆลองดูเครื่องมือนี้อาจช่วยได้: http://regex.larsolavtorvik.com/


2

ใช้ regex ของคุณฉันปรับเปลี่ยนเล็กน้อยเพื่อให้เหมาะกับความต้องการของคุณ

<a.*?href=("|')(.*?)("|').*?>(.*)<\/a>

ฉันขอแนะนำให้คุณใช้HTML Parser เป็นการส่วนตัว

แก้ไข: ทดสอบแล้ว


ใช้ myregextester.com - ขออภัยไม่พบลิงก์
bergin

มันบอกว่า: ไม่มีการแข่งขัน ตรวจสอบ DELIMITER COLLISION
bergin

ช่วยบอกข้อความที่ตรงกันได้ไหม ฉันใช้:<a title="this" href="that">what?</a>
Ruel

1

การทดสอบอย่างรวดเร็ว: <a\s+[^>]*href=(\"\'??)([^\1]+)(?:\1)>(.*)<\/a>ดูเหมือนว่าจะทำเคล็ดลับโดยการจับคู่ครั้งที่ 1 คือ "หรือ" ครั้งที่สอง "ค่า href" "ที่" และครั้งที่สามคือ "อะไร"

เหตุผลที่ฉันทิ้งนัดแรกของ "/" ไว้ในนั้นคือคุณสามารถใช้มันเพื่ออ้างอิงกลับในภายหลังสำหรับการปิด "/" ดังนั้นมันก็เหมือนกัน

ดูตัวอย่างสดได้ที่: http://www.rubular.com/r/jsKyK2b6do


1
@bergin โปรดระบุสิ่งที่ไม่ได้ผล? ฉันได้ค่าที่แน่นอนจาก href ใน HTML ทดสอบของคุณ คุณคาดหวังอะไรที่ไม่ได้ทำ? ฉันเห็นว่าคุณใช้ไซต์อื่นในการทดสอบที่นั่นฉันยังได้รับค่า "href" จากตัวอย่างของคุณด้วย myregextester.com/?r=d966dd6b
CharlesLeaf

0

preg_match_all ("/ (] >) (. ?) (</ a) /", $ content, $ impmatches, PREG_SET_ORDER);

ได้รับการทดสอบและดึงแท็กทั้งหมดจากโค้ด html ใด ๆ


0

สิ่งต่อไปนี้ใช้ได้ผลสำหรับฉันและส่งคืนทั้งhrefและvalueของแท็กจุดยึด

preg_match_all("'\<a.*?href=\"(.*?)\".*?\>(.*?)\<\/a\>'si", $html, $match);
if($match) {
    foreach($match[0] as $k => $e) {
        $urls[] = array(
            'anchor'    =>  $e,
            'href'      =>  $match[1][$k],
            'value'     =>  $match[2][$k]
        );
    }
}

อาร์เรย์หลายมิติที่เรียกว่า$urlsมีอาร์เรย์ย่อยที่เชื่อมโยงซึ่งใช้งานง่าย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.