【问题标题】:Scraping HTML content, preg_match not working抓取 HTML 内容,preg_match 不起作用
【发布时间】:2013-09-01 16:21:07
【问题描述】:

目前我正在从 HTML 页面中抓取数据。我的代码之一不起作用。 HTML 内容是这样的。

<ul class="pagination">
    <li>
        <span class="page active">
            1
        </span>
    </li>
    <li>
        <a class="page available" href="/somethingherewithanychars1">
            2
        </a>
    </li>
    <li>
        <a class="page available" href="/somethingherewithanychars2">
            3
        </a>
    </li>
    <li>
        <a class="page available" href="/somethingherewithanychars3">
        4
        </a>
    </li>
<ul>

我尝试使用此代码获取活动页面链接旁边的 href 值,就像在示例中活动页面链接是第 1 页一样,所以我将获得的 href 值必须是第 2 页,其中值为 /somethingherewithanychars1 但它不起作用

$file_string = file_get_contents($url); 
 preg_match('/<li><span class="page active">.*?<\/span><\/li><li><a class="page available" href="(.*)">/i', $file_string, $pages); 

print_r($pages);

我正在访问的 html 有一些这样的代码

<div class="attributes">
   <a class="name" href="/linksTothissite" data-hovercard-id="somechars">link1</a>
   <span class="list">
    USA
   </span>
   <a class="name" href="/linksTothissite" data-hovercard-id="somechars">link2</a>
   <span class="list">
    CANADA
   </span>
</div>

我尝试使用此代码获取值,我可以获取链接 1 和链接 2

preg_match_all('/<a class="name" href=".*?" data-hovercard-id=".*?">(.*)<\/a>/i', $file_string, $values); 

这个我也可以拿到美国和加拿大

 preg_match_all('/<span class="list">(.*?)<\/span>/s',$file_string, $values); 
         $val= $values[1]; 

为什么我的 preg_match 没有得到我需要的值?我也尝试使用 pre_match_all() 但我仍然在我的 print_r Array () 中得到一个输出,但我的其余代码可以工作。

【问题讨论】:

  • 也许这有帮助:stackoverflow.com/a/1732454
  • Regex 仅适用于此类任务,前提是您知道自己在做什么。看到您的 preg_match 甚至没有考虑 &lt;li&gt;&lt;span 之间的空格,您可能应该调查 simpler alternatives
  • 我明白了。我尝试添加我的代码以忽略空格和换行符,但仍然无法正常工作。其他代码也有换行符,但我可以得到它的值。
  • @Cobra_Fast 请不要发布指向该问题的链接,因为它们对读者没有帮助,除非您用他们可以使用的答案跟进它。 知道评论的重点,那堵文字墙是用正则表达式解析 HTML 是个坏主意。但是,对于正在询问的其他人来说,这根本不清楚。更糟糕的是,它并没有为读者指出任何可以帮助可靠地解析 HTML 的有用解决方案。
  • @AndyLester 我链接的帖子以“您是否尝试过使用 XML 解析器代替?”...

标签: php regex html-parsing


【解决方案1】:

这样做的一个好方法是使用 DOM 与 XPath 相结合,如所写的 Prix。

如果您想检查您要查找的链接是否是“分页”类的无序列表中某个项目的子元素,并检查该项目是否是“活动页面”项目之后的下一个,查询会有点复杂。

$doc = new DOMDocument();
@$doc->loadHTMLFile($url);
$xpath = new DOMXPath($doc);
$xquery = '//ul[@class="pagination"]'                    // ul with the "pagination" class
        . '/li[descendant::span[@class="page active"]]'  // li that contains a span with "page active" class
        . '/following-sibling::*[1]'                     // next sibling (next li)
        . '/a/@href';                                    // href attribute of the a tags
$links = $xpath->query($xquery);
echo $links->item(0)->value;

您的正则表达式不起作用的原因是:

  • 您忘记了标签之间所有可能的空白(空格、制表符、换行符)。
  • 您使用点来描述标签之间可能出现的无法匹配换行符的字符
  • 这里不是致命的,但是:您使用了一个贪婪的量词 (.*)" 来描述链接(结果:正则表达式引擎将使用该行的最后一个双引号,而不是它遇到的第一个双引号。)

在必要时添加\s* 后,您可以将.*.*? 替换为否定字符类:

preg_match('/<li>\s*<span class="page active">[^<]+<\/span>\s*<\/li>\s*<li>\s*<a class="page available" href="([^"]+)">/i', $file_string, $pages);

请记住,当 DOM 方法始终有效时(只要树结构保持不变),您的 html 代码中的最小更改都会使您的模式失败

【讨论】:

  • 感谢您的简短解释。一直在尝试这个 DOM,但我不知道如何使用它的查询。我已经尝试了你给出的 dom 和 preg_match 并且两者都在工作。我对这个 DOM 感兴趣。我可以要求一些关于 dom xquery 的链接或文档。 :)
  • 您可以在 PHP 手册中找到所有关于 DOMDocument 和 DOMXPath 的信息:php.net/manual/en/class.domxpath.phpphp.net/manual/en/class.domdocument.php 您还可以找到一些关于如何在 php 中使用 xpath 的教程,例如:ibm.com/developerworks/library/x-xpathphp 或使用您喜欢的搜索引擎
  • 非常感谢。 .
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-23
  • 1970-01-01
  • 2013-04-16
  • 1970-01-01
  • 1970-01-01
  • 2014-01-04
  • 2016-09-04
相关资源
最近更新 更多