如何在PHP中使用带有preg_match_all的Regex提取某些HTML标记,例如<ul>?

Nir*_*dal 2 html php regex preg-match-all preg-match

我是正则表达式的新手.我想从网页源中获取一些数据.我曾经 file_get_contents("url")获得该页面的HTML源代码.现在我想在一些特殊标签中捕获一部分.

preg_match_all()为此找到了作品.现在我想要一些帮助来解决我的问题,如果可能的话,帮助我找出如何解决这样的类似问题.

在下面的示例中,我如何获取数据<ul>?(我希望这个示例HTML代码可以让我更容易理解.)

<div class="a_a">qqqqq<span>www</span> </div>
<ul>
<li>
    <div class="a_a"><h3>aaaa</h3> aaaa aaaaa</div>
</li>
<li>
    <div class="b_b">bbbbb <span class="s-s">bbbb</span> bbbb</div>
</li>
<li>
    <div class="c_c d-d">cccc cccc ccccc</div>
</li>
</ul>
<table>
<tr>
    <td>sdsdf</td>
    <td>hjhjhj</td>
</tr>
<tr>
    <td>yuyuy</td>
    <td>ertre</td>
</tr>   
</table>
Run Code Online (Sandbox Code Playgroud)

Jon*_*y 5 17

正如评论所述,通常不建议用正则表达式解析html.在我看来,这取决于你将要做什么.


如果你想使用正则表达式,知道,有没有嵌套的标签相同种类,也得到一切的之间最简单的模式的<ul>和最接近的</ul>是:

$pattern = '~<ul>(.*?)</ul>~s';
Run Code Online (Sandbox Code Playgroud)

它匹配<ul>后跟尽可能少的任何类型的字符来满足</ul>.点是元字符,匹配除换行符(\n)之外的任何单个字符.为了使它匹配换行符,在结束分隔符之后 ~我放置了s- 修饰符.的量词 *指零次或多次.

默认情况下,量词贪婪的,这意味着,他们尽可能多地吃饱.一个问号?后面*使它们非贪婪(或懒惰)并匹配尽可能少的字符来满足</ul>.作为模式分隔符,我选择了~波形符.

preg_match_all($pattern, $html, $out);
Run Code Online (Sandbox Code Playgroud)

匹配被捕获并且可以在输出变量中找到,您可以在其中设置,preg_match或者包含所有内容,匹配整个模式,第一个捕获的带括号的子模式,...preg_match_all[0][1]


如果您的搜索标签可以包含属性(例如<ul class="my_list"...)此扩展模式,那么在<ul包含[^>]*任何数量的字符之后,它们将不会>在会议之前>

$pattern = '~<ul[^>]*>\K.*(?=</ul>)~Uis';
Run Code Online (Sandbox Code Playgroud)

而不是问号,这里我使用U- 修饰符,使所有量词变得懒惰.仅用于捕获<ul>内部所需的部件</ul>.\K用于重置报告的匹配的开头.而不是捕获结束的</ul>一个先行使用(?=,因为我们既不希望在输出部分.

这基本上与'~<ul[^>]*>(.*)</ul>~Uis'将整个模式匹配[0]和第一个括号组捕获到的相同[1].


但是,如果您的html 包含相同类型的嵌套标记,则以下模式的概念是捕获最内层标记.在里面的每个角色<ul>...... </ul>它检查是否没有开口<ul

$pattern = '~<ul[^>]*>\K(?:(?!<ul).)*(?=</ul>)~Uis';
Run Code Online (Sandbox Code Playgroud)

使用获得匹配preg_match_all

$html = '<div><ul><li><ul><li>.1.</li></ul>...</li></ul></div>
         <ul><li>.2.</li></ul>';

if(preg_match_all($pattern, $html, $out))
{
  echo "<pre>"; print_r(array_map('htmlspecialchars',$out[0])); echo "</pre>";
} else {

  echo "FAIL";
}
Run Code Online (Sandbox Code Playgroud)

之间的匹配\K(?=将被捕获到$出来[0]

  • \ K重置报告的匹配的开头(自5.2.4以来在PHP中支持)
  • 第二个模式,当<ul>匹配,展望 (?!...在每一个字符,如果没有开幕<ul会议之前</ul>,若有重新开始,直到</ul>领先 (?=</ul>).
  • [^>]*任何数量的字符,不是>(否定字符类)
  • (?:启动一个非捕获组.

使用的修饰符 :( Uis结束分隔符 后的部分~)

U(PCRE_UNGREDY),i(PCRE_CASELESS),s(PCRE_DOTALL)