0

我做了很多研究,但我还没有找到我的答案。我正在尝试从网页中获取一些信息,这些信息具有以下 HTML 结构

<div id="xxx" class="some1">
        <h1>This is the time</h1>
    <div class="ti12">
        <div class="sss"></div>
        <div class="sss">
                     <span class="hhh">
            <div class="sded">
                City:
                <span class="sh">CCC</span>
            </div>
                    </span>
        </div>
        </div>
        .
        .
    .
        <div class="pp12"></div>
</div>

现在,我正在做的是以相同的方式获取城市的名称和类似的其他信息。

我必须从上面的代码中找到这些信息。

$arr=array('City', 'Name', 'Address', 'DOB');

如果存在获取其值,否则将其留空。

希望我的我很清楚。

它尝试了以下代码:

<?php
include "simple_html_dom.php";
   $html = new simple_html_dom();
   $listItem = array('City', 'Name', 'Address', 'DOB');
$html->load_file('simp.html');
$found=array();
    foreach($listItem as $item){
        $ret = $html->find('div[id=xxx] div',0);
        iterateParentNode($ret, $item);
        }
function iterateParentNode($ret1, $item1){
for ($node=0;$node < count($ret1->children());$node++){
    $child=$ret1->children($node);
    echo count($ret1->children())."<br/>";
    if(count($ret1->children())==1 && strpos($child, '<span class="sh"')!==false ){
        $found[$item1]=$ret1->find('span[class=sh]',0)->plaintext;
        return true;
    }else{
    goThroughChildNode($child, $item1);
    }
}
}
function goThroughChildNode($child1, $item2){
    echo $child1."ITEM:".$item2;
        if(strpos($child1, $item2)!==false){
            iterateParentNode($child1, $item2);
        }else{
            return false ;
        }
        return true;
}
foreach ($found as $structure=>$data){
  echo $structure."=>".$data."<br />";
}
?>

我知道我的 PHP 方法不好,所以请建议我考虑我的 PHP 代码来做这件事的好方法。

4

3 回答 3

0

使用正则表达式执行此操作可能是最简单的。当然,如果 HTML 结构发生变化,它就会中断。

if (ereg('<div.*?h1>(.*?)</h1>.*?City:.*?>(.*?)<', $input, $regs)) {
    $title = $regs[1];
    $city = $regs[2];
} else {
    $title = "";
    $city = "";
}

/*
Match 1 of 1
Matched text: <div id="xxx" class="some1">
        <h1>This is the time</h1>
    <div class="ti12">
        <div class="sss"></div>
        <div class="sss">
                     <span class="hhh">
            <div class="sded">
                City:
                <span class="sh">CCC<
Match offset: 0
Match length: 282
Group 1: This is the time
Group 1 offset: 42
Group 1 length: 16
Group 2: CCC
Group 2 offset: 278
Group 2 length: 3
*/

// <div.*?h1>(.*?)</h1>.*?City:.*?>(.*?)<
// 
// Match the characters "<div" literally «<div»
// Match any single character «.*?»
//    Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?»
// Match the characters "h1>" literally «h1>»
// Match the regular expression below and capture its match into backreference number 1 «(.*?)»
//    Match any single character «.*?»
//       Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?»
// Match the characters "</h1>" literally «</h1>»
// Match any single character «.*?»
//    Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?»
// Match the characters "City:" literally «City:»
// Match any single character «.*?»
//    Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?»
// Match the character ">" literally «>»
// Match the regular expression below and capture its match into backreference number 2 «(.*?)»
//    Match any single character «.*?»
//       Between zero and unlimited times, as few times as possible, expanding as needed (lazy) «*?»
// Match the character "<" literally «<»
于 2013-04-28T04:55:01.957 回答
0

手动遍历的一种替代方法是查询数据。在 DOMDocument 中,这通常使用 XPath 来完成,XPath 是一种专门用于该工作的语言。

您使用的库不支持XPath,但是,PHP 开箱即用地支持它。PHP 还支持开箱即用的DOMDocument ,所以我认为我可以安全地建议您作为替代方案。

因此,在您的情况下,您首先查看带有 ID 的 div:

//div[@id="xxx"]

然后在某个地方的div里面:

   //div

如果没有特定名称(子项),那么您需要另一个元素:

       //*

但是那些需要匹配特定的模式:这里,包含一个具有“sh”类属性的跨度,它必须是其中的第一个跨度,并且在跨度之前必须有一些文本:

            [
                span[@class="sh"]
                and span = span[@class="sh"]
                and span/preceding-sibling::text()
            ]

和那个孩子,你想要第一个文本节点孩子:

                /text()[1]

因此,只需一目了然:

    //div[@id="xxx"]
        //div
            //*[
                span[@class="sh"]
                and span = span[@class="sh"]
                and span/preceding-sibling::text()
            ]
                /text()[1]

这将为您提供命名字符串,例如“City:”等。然后下一个兄弟(跨度)将包含该值。

您所要做的就是将其包装到代码中(这里我加载了一个字符串,但您也可以加载一个 HTML 文件loadHTMLFile(),请查看上面的 DOMDocument 链接以获取所有荣耀的详细信息):

$dom = new DOMDocument();
$dom->loadHTML($string);
$xp = new DOMXPath($dom);

foreach ($xp->query('
        //div[@id="xxx"]
            //div
                //*[
                    span[@class="sh"]
                    and span = span[@class="sh"]
                    and span/preceding-sibling::text()
                ]
                    /text()[1]
                '
         ) as $node
) {
    $name  = trim($node->nodeValue);
    $value = trim($node->nextSibling->nodeValue);
    printf("%s %s\n", $name, $value);
}

带有示例 HTML 的输出:

City: CCC

我希望这可以激发您研究 DOMDocument 并帮助您探索 XPath 的力量。

于 2013-05-02T08:08:32.267 回答
0

我花了一段时间才把它弄好,但是这段代码使用 Simple HTML Dom 遍历了整个 DOM。希望有人可以使用。

<?php
$html = new simple_html_dom();
$html->load('<html><body>'.$text.'</body></html>');

if(method_exists($html,"childNodes")){
    if($html->find('html')) {
    //IF NOT OK, THROW ERROR
}}

$e=$html->find('body',0);
$p=$e->childNodes(0);
if(!$p){
    //BODY HAS NO CHILDNODES< THROW ERROR
    }

    $loop=true;
    //SAFEGUARD, PREVENTS INDEFINITE LOOPS
    $i=$j=0; 
    $i_max=500;
    $j_max=500;


    while($loop==true){
        //SAFEGUARD, PREVENTS INDEFINITE LOOPS
        $i=0;$i++;if($i>$i_max){$loop=false;break;}

        //TEST IF NODE HAS CHILDREN
        $p=$e->childNodes(0);

        //NO CHILDREN
        if(!$p){
            //DO SOMETHING WITH NODE
            clean_dom($e->outertext);

            //TEST IF NODE HAS SIBLING
            $p=$e->next_sibling();
            if(!$p){
                //NO SIBLING
                    //TEST THE PARENT, LOOP TILL WE FIND A SIBLING
                    $j=0;$sib_loop=true;
                    while($sib_loop==true){
                        //SAFEGUARD, PREVENTS INDEFINITE LOOPS
                        $j++;if($j>$j_max){$sib_loop=false;break;}
                        //TEST IF THERE IS A PARENT
                        $e=$e->parent();
                            //NO PARENT, WE'VE REACHED THE TOP AGAIN
                            if(!$e){
                                echo'***THE END***';
                                $sib_loop=$loop=false;break;}
                            //ELSE, TEST IF PARENT HAS SIBLING
                            $p=$e->next_sibling();
                            //THERE IS A SIBBLING, GO THERE
                            if($p){
                                //DO SOMETHING WITH THIS NODE
                                clean_dom($e->outertext);
                                $e=$e->next_sibling();
                                $sib_loop=false;break;
                                }
                            else{
                                $ret=clean_dom($e->outertext,$all);
                                $e->outertext=$ret;
                                }

                        }       
                    }
            else{
                //GOTO SIBLING
                $e=$e->next_sibling();
                }
            }

        else{
        //THERE IS A CHILD
            $e=$e->childNodes(0);
            }
        }
$text=$html->save();
$html->clear(); 
unset($html);

function clean_dom($e){
    //DO SOMETHING HERE        
    }
于 2013-05-15T07:50:30.667 回答