phpQuery是一款JQuery的PHP实现,用来解析网页元素DOM非常的方便,头疼的是他总是有乱码问题。其实也不能全怪phpQuery。
因为phpQuery分析网页元素时候进行网页编码探测使用的是正则表达式进行页面meta标签的charset匹配。但是总是有那么多奇形怪状的网页,所以也难免会出错。
比如这个页面 他就没有meta标签,phpQuery在处理这个页面的时候(function loadMarkupHTML),就会遵循如下流程
[text]if(正则表达式匹配meta标签失败,即documentCharset变量空){
if(定义了requestedCharset,就是那个newDocumentFileHTML后面的charset参数){
charset = requestedCharset
}
if(charset还不能被定义,即requestedCharset为空){
charset = phpQuery::$defaultCharset
}
if(documentCharset变量空){
根据HTTP 1.1的要求 设置默认documentCharset为ISO-8859-1
需要在后面补足标准的meta标记
}
}
if (requestedCharset && documentCharset && requestedCharset !== documentCharset){
如果存在mb_detect_encoding的话,进行编码转换
possibleCharsets = array(documentCharset, requestedCharset, 'AUTO')
docEncoding = mb_detect_encoding(markup, implode(', ', possibleCharsets));
if(检测不出docEncoding){
已documentCharset为准
}
if(docEncoding这个检测编码和requestedCharset不一样){
使用mb_convert_encoding进行编码转换
}
}
其余略[/text]
这里面有个问题,那就是mb_detect_encoding检测的编码不一定是准确的,大部分情况下,在ISO-8859-1优先的情况下(documentCharset排在前面),他都认为该文档是ISO-8859-1,从而出现乱码。
所以,如果你这里定义了phpQuery::$defaultCharset,就可以避免这种情况的发生,这样的话 采集淘宝网首页 只要指定phpQuery::$defaultCharset=GBK,就不会乱码。
第二个问题是一个BUG,在phpQuery的大概273行(phpQuery 0.9.5 (r386; one file release) )
[php]$markup = $this->charsetFixHTML($markup);[/php]
这个BUG会导致中文wordpress博客,比如我这个博客,虽然有规范的meta标签 但是会被错误的charsetFixHTML。破坏了DOM结构,导致解析乱码。该BUG到Revision 393依旧没修复。 这个不注释的话,采集我的博客就会乱码.
所以 这里有我的一个修补版本,有兴趣的可以下了试试。[download id="32" format="2"]
由于PHPQuery是精确采集,所以你之前基本知道了网页的编码,那么只要指定了phpQuery::$defaultCharset,不管是有没有meta的页面或者meta不规范的页面,基本上都不会乱码。
规范的HTML页面演示
[php]
<?php
//规范meta演示
header("Content-type: text/html; charset=utf-8");
set_time_limit(0);
include 'phpQuery-onefile-ipatched.php';
//phpQuery::$defaultCharset = 'euc-jp';
phpQuery::newDocumentFileHTML('http://page14.auctions.yahoo.co.jp/jp/auction/s237346475');
echo pq('title')->text();
echo pq("strong[property='auction:Price'])")->text();
?>[/php]
不规范的页面演示
[php]
<?php
//不规范meta演示
header("Content-type: text/html; charset=utf-8");
set_time_limit(0);
include 'phpQuery-onefile-ipatched.php';
phpQuery::$defaultCharset = 'euc-jp';
phpQuery::newDocumentFileHTML('http://storeuser11.auctions.yahoo.co.jp/jp/user/makototakahashi0316?alocale=0jp&mode=0&u=makototakahashi0316');
$trs = pq('#list01')->find('table tr:not(:first)');
foreach($trs as $tr){
$line = pq($tr)->find('td:first a');
$title = $line->text();
if($title){
$url = $line->attr('href');
echo $title.'---->'.$url.'<br />';
}
}
?>
[/php]
[php]<?php
//规范meta演示
header("Content-type: text/html; charset=utf-8");
set_time_limit(0);
include 'phpQuery-onefile-ipatched.php';
//phpQuery::$defaultCharset = 'euc-jp';
phpQuery::newDocumentFileHTML('http://ihipop.info');
echo pq("title")->text();
//不规范meta演示
phpQuery::$defaultCharset = 'GBK';
phpQuery::newDocumentFileHTML('http://taobao.com');
echo pq("title")->text();
?>[/php]
注意 1.phpQuery的输出全部是UTF-8编码的.
2.phpQuery主页http://code.google.com/p/phpquery/
phpQuery在每处理一个网页就会产生一个DOMDocumentWrapper 对象,而每个DOMDocumentWrapper 对象会被保存在静态成员$documents中(phpQuery::createDocumentWrapper中),这个变量是一个数组,每解析一个网页数组元素就增加一个。如果不想让自己的内存被额沾满,每次解析完一个网页,把phpQuery::$documents置空
[php]phpQuery::$documents = array();[/php]或者清空不必要的ID,节省内存。同理,你也可以有选择的保留一些ID 见http://code.google.com/p/phpquery/wiki/MultiDocumentSupport
http://www.fhzww.net 用你的版本采这个站的title是乱码
$callback=array('demo2_cb1',array('http://www.fhzww.net'));
$curl->add('http://www.fhzww.net'),$callback);
$curl->go();
function demo2_cb1($r,$id){
global $db,$curl;
//print_r($r['info']);exit;
if($r['info']['http_code']==200){
phpQuery::$defaultCharset = 'utf-8';
$html=phpQuery::newDocumentHTML($r['content'],'utf-8');
$list=$html['title'];
echo $list->text();exit;
}
phpQuery::unloadDocuments();
$curl->status();
}
?>
楼主的文章在百度排名很靠前。
于是搜到这里。
注释charsetFixHTML不能解决问题。
这个函数核心左右是phpquery作者为了适配domdocument而写的
参考po主的内容作了以下修改
http://hi.baidu.com/feilala_fly/item/fdd0942357d6b398b7326307
用了你的版本依然没搞定,还是乱码。怎么办呢。。。
@布布
难道之前都是因为这个原因乱码?
这个不是我改错的。他本来就是错的
phpQuery-onefile-ipatched.php的第517行$hltml,变量名错了。
phpQuery::$documents = array();
用这个清空数组以后,php CLI下执行,php进程内存占用基本就固定在8.7M
继续关注
太好了,有你这个版本我就省劲了。
谢谢