按类名获取DOM元素

bgc*_*ode 120 css php dom

我正在使用PHP DOM,我正在尝试在DOM节点中获取具有给定类名的元素.获得该子元素的最佳方法是什么?

更新:我最终Mechanize用于PHP,这更容易使用.

pro*_*son 148

更新:*[@class~='my-class']css选择器的Xpath版本

所以在我的评论下面回应hakre的评论后,我很好奇,并查看了背后的代码Zend_Dom_Query.看起来上面的选择器被编译为以下xpath(未经测试):

[contains(concat(' ', normalize-space(@class), ' '), ' my-class ')]

所以php将是:

$dom = new DomDocument();
$dom->load($filePath);
$finder = new DomXPath($dom);
$classname="my-class";
$nodes = $finder->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' $classname ')]");
Run Code Online (Sandbox Code Playgroud)

基本上,我们在这里所做的只是规范化class属性,以便即使单个类也以空格为界,并且完整的类列表以空格为界.然后用空格追加我们正在搜索的类.这样我们就可以有效地寻找并找到实例my-class.


使用xpath选择器?

$dom = new DomDocument();
$dom->load($filePath);
$finder = new DomXPath($dom);
$classname="my-class";
$nodes = $finder->query("//*[contains(@class, '$classname')]");
Run Code Online (Sandbox Code Playgroud)

如果它只是一种类型的元素,您可以用*特定的标记名替换它.

如果您需要使用非常复杂的选择器进行大量操作,我建议使用Zend_Dom_Query哪种支持CSS选择器语法(la jQuery):

$finder = new Zend_Dom_Query($html);
$classname = 'my-class';
$nodes = $finder->query("*[class~=\"$classname\"]");
Run Code Online (Sandbox Code Playgroud)

  • @prodigitalson:这是不正确的,因为它不反映空格,试试`//*[contains(concat('',normalize-space(@class),''),'classname')]`(非常有用的信息:[ CSS选择器和XPath表达式](http://www.a-basketful-of-papayas.net/2010/04/css-selectors-and-xpath-expressions.html)). (2认同)
  • @babonk:是的,您需要将“contains”与“concat”结合使用...我们只是讨论填充您正在搜索的类两侧的空格或仅填充一侧的细节。不过,两者都应该有效。 (2认同)

Tsc*_*cka 17

如果你希望得到没有zend的类的innerhtml,你可以使用这个:

$dom = new DomDocument();
$dom->load($filePath);
$classname = 'main-article';
$finder = new DomXPath($dom);
$nodes = $finder->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' $classname ')]");
$tmp_dom = new DOMDocument(); 
foreach ($nodes as $node) 
    {
    $tmp_dom->appendChild($tmp_dom->importNode($node,true));
    }
$innerHTML.=trim($tmp_dom->saveHTML()); 
echo $innerHTML;
Run Code Online (Sandbox Code Playgroud)


dav*_*dav 11

我认为接受的方式更好,但我想这可能也有效

function getElementByClass(&$parentNode, $tagName, $className, $offset = 0) {
    $response = false;

    $childNodeList = $parentNode->getElementsByTagName($tagName);
    $tagCount = 0;
    for ($i = 0; $i < $childNodeList->length; $i++) {
        $temp = $childNodeList->item($i);
        if (stripos($temp->getAttribute('class'), $className) !== false) {
            if ($tagCount == $offset) {
                $response = $temp;
                break;
            }

            $tagCount++;
        }

    }

    return $response;
}
Run Code Online (Sandbox Code Playgroud)

  • 这个例子在哪里?这会很好. (2认同)

oab*_*rca 5

还有一种不使用DomXPath或的方法Zend_Dom_Query

基于dav的原始函数,我编写了以下函数,该函数返回其tag和class与参数匹配的父节点的所有子节点。

function getElementsByClass(&$parentNode, $tagName, $className) {
    $nodes=array();

    $childNodeList = $parentNode->getElementsByTagName($tagName);
    for ($i = 0; $i < $childNodeList->length; $i++) {
        $temp = $childNodeList->item($i);
        if (stripos($temp->getAttribute('class'), $className) !== false) {
            $nodes[]=$temp;
        }
    }

    return $nodes;
}
Run Code Online (Sandbox Code Playgroud)

假设您具有$html以下HTML 变量:

<html>
 <body>
  <div id="content_node">
    <p class="a">I am in the content node.</p>
    <p class="a">I am in the content node.</p>
    <p class="a">I am in the content node.</p>    
  </div>
  <div id="footer_node">
    <p class="a">I am in the footer node.</p>
  </div>
 </body>
</html>
Run Code Online (Sandbox Code Playgroud)

的使用getElementsByClass非常简单:

$dom = new DOMDocument('1.0', 'utf-8');
$dom->loadHTML($html);
$content_node=$dom->getElementById("content_node");

$div_a_class_nodes=getElementsByClass($content_node, 'div', 'a');//will contain the three nodes under "content_node".
Run Code Online (Sandbox Code Playgroud)


iau*_*ion 5

DOMDocument的输入速度很慢,而phpQuery的内存泄漏问题也很糟糕.我最终使用:

https://github.com/wasinger/htmlpagedom

要选择一个班级:

include 'includes/simple_html_dom.php';

$doc = str_get_html($html);
$href = $doc->find('.lastPage')[0]->href;
Run Code Online (Sandbox Code Playgroud)

我希望这对其他人也有帮助


Sli*_*liq 5

PHP's native DOM handling is so absurdly bad, do yourself a favour and use this or any other modern HTML parsing package which can handle this within in few lines:

Install paquettg/php-html-parser with

composer require paquettg/php-html-parser
Run Code Online (Sandbox Code Playgroud)

Then create a .php file in the same folder with this content

<?php

// load dependencies via Composer
require __DIR__ . '/vendor/autoload.php';

use PHPHtmlParser\Dom;

$dom = new Dom;
$dom->loadFromUrl("https://example.com");
$links = $dom->find('.classname a');

foreach ($links as $link) {
    echo $link->getAttribute('href');
}
Run Code Online (Sandbox Code Playgroud)

P.S. You'll find information on how to install Composer on Composer's homepage.