当前位置:
首页 > 技术 > phpQuery采集乱码解决方法 phpQuery释放内存方法

phpQuery采集乱码解决方法 phpQuery释放内存方法

phpQuery是一款JQuery的PHP实现,用来解析网页元素DOM非常的方便,头疼的是他总是有乱码问题。其实也不能全怪phpQuery。

因为phpQuery分析网页元素时候进行网页编码探测使用的是正则表达式进行页面meta标签的charset匹配。但是总是有那么多奇形怪状的网页,所以也难免会出错。

比如这个页面 他就没有meta标签,phpQuery在处理这个页面的时候(function loadMarkupHTML),就会遵循如下流程

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进行编码转换
    }

}
......其余略

这里面有个问题,那就是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)

$markup = $this->charsetFixHTML($markup);

这个BUG会导致中文wordpress博客,比如我这个博客,虽然有规范的meta标签 但是会被错误的charsetFixHTML。破坏了DOM结构,导致解析乱码。该BUG到Revision 393依旧没修复。 这个不注释的话,采集我的博客就会乱码.

由于PHPQuery是精确采集,所以你之前基本知道了网页的编码,那么只要指定了phpQuery::$defaultCharset,不管是有没有meta的页面或者meta不规范的页面,基本上都不会乱码。

规范的HTML页面演示

<?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
     //不规范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($trsas$tr){
         $line=pq($tr)->find('td:first a');
         $title=$line->text();
         if($title){
            $url=$line->attr('href');
            echo $title.'---->'.$url.'<br />';
         }
     }
?>
<?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();
?>

注意: phpQuery的输出全部是UTF-8编码的.

phpQuery主页http://code.google.com/p/phpquery/

phpQuery在每处理一个网页就会产生一个DOMDocumentWrapper 对象,而每个DOMDocumentWrapper 对象会被保存在静态成员$documents中(phpQuery::createDocumentWrapper中),这个变量是一个数组,每解析一个网页数组元素就增加一个。

如果不想让自己的内存被额沾满,每次解析完一个网页,把phpQuery::$documents置空

phpQuery::$documents = array();

或者清空不必要的ID,节省内存。同理,你也可以有选择的保留一些ID 见

http://code.google.com/p/phpquery/wiki/MultiDocumentSupport


比较折腾的方法:

本地先将抓来的中文由utf-8转换为ISO-8859-1

mb_convert_encoding($zn_str,'ISO-8859-1','utf-8')

然后输出中文时就发现他们变成了比较熟悉的gbk乱码形式,然后再从gbk转换成utf-8即可

mb_convert_encoding($zn_str,'utf-8','GBK')

前后转了两次解决了问题

网友评论2

  1. 板凳
    mets womens jersey:

    Enquired specifically for proclaim just what made often the Leafs' "setup" which means that exclusive, Jokinen in cui within the particulars.

    2016-09-23 2:38 AM
  2. 沙发
    tyler toffoli jersey:

    The catch is, that they can also have recently been very challenging on by themselves.

    2016-09-24 7:15 PM

发表评论

您必须 [ 登录 ] 才能发表留言!