php抓取网页指定内容

用PHP抓网页内容,取网最直接的定内方式是file_get_contents()。一行代码拿到整页HTML,取网然后正则匹配你要的定内片段。听起来简单,取网实际用起来坑不少。定内

我拿一个真实场景举例。取网假设要抓某图书网站的定内书名和价格,页面结构大概是取网这样:

<div class="book-item"> <h2 class="title">PHP从入门到跑路</h2> <span class="price">¥59.00</span> </div>

最朴素的做法:

$html = file_get_contents('https://example.com/books'); preg_match('/<h2 class="title">(.*?)<\/h2>/s', $html, $matches); echo $matches[1];

能跑通,但只适合结构极其稳定的定内页面。目标站改一次class名,取网代码就废了。定内

正则的取网边界在哪

正则处理嵌套HTML很吃力。比如书名里套了<em>标签,定内(.*?取网)还能凑合。但如果要提取多个字段、处理属性顺序变化、应对自闭合标签,正则的维护成本会急剧上升。

我的判断标准很简单:提取单一字段、页面结构半年不变,用正则没问题。一旦要抓三个以上字段,或者目标站经常改版,直接上DOM解析。

DOMDocument才是正经工具

PHP内置的DOMDocument配合DOMXPath,能把HTML当XML树来查。上面那个例子改写一下:

$dom = new DOMDocument(); libxml_use_internal_errors(true); $dom->loadHTML($html); libxml_clear_errors(); $xpath = new DOMXPath($dom); $titles = $xpath->query('//h2[@class="title"]'); $prices = $xpath->query('//span[@class="price"]'); foreach ($titles as $i => $node) {  echo trim($node->nodeValue) . ' - ' . trim($prices->item($i)->nodeValue); }

libxml_use_internal_errors(true)这行别省。网页HTML经常有未闭合标签,不加这行,loadHTML会抛一堆warning,输出全被污染。

编码问题绕不开

抓中文网页,十次有三次遇到乱码。file_get_contents拿到的字节流如果页面是GBK编码,直接丢给DOMDocument会变成一坨问号。解决办法:

$html = mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8');

或者更稳妥的,先检测编码再转:

$encoding = mb_detect_encoding($html, ['UTF-8', 'GBK', 'GB2312']); if ($encoding !== 'UTF-8') {  $html = mb_convert_encoding($html, 'UTF-8', $encoding); }

还有个偏方:在loadHTML之前手动插入<meta charset="utf-8">,有时候比mb_convert_encoding管用。具体哪个有效,得看目标页面的实际编码声明。

请求头不设置,连门都进不去

file_get_contents默认的User-Agent是PHP自带的,很多网站直接403。加个上下文:

$context = stream_context_create([ 'http' => [ 'header' => "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\r\n" ] ]); $html = file_get_contents($url, false, $context);

需要POST、需要Cookie、需要跟随跳转的时候,file_get_contents就开始力不从心了。这时候换cURL。不是因为它更高级,而是它把超时控制、重定向、Cookie管理这些事都做成了参数,不用自己拼header字符串。

抓不到内容的几种可能

代码没报错但query返回空,按这个顺序排查:页面是否由JavaScript渲染(查看源码里有没有目标内容)、XPath路径是否写错(用浏览器开发者工具复制XPath对比)、目标元素是否在iframe里、网站是否返回了验证码页面。

JavaScript渲染的页面,PHP层面基本无解,得上无头浏览器。这是另一个话题了。

抓取之前先看一眼robots.txt,别给自己找麻烦。频率控制住,别把人家服务器打挂了。

时尚
上一篇:漏洞排查
下一篇:网站核销