Goutte/Guzzle可以强制进入UTF-8模式吗?

hal*_*fer 6 php web-scraping goutte guzzle symfony-components

我正在使用Goutte从UTF-8网站上搜索,Goutte内部使用Guzzle.该网站声明了UTF-8的元标记,因此:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Run Code Online (Sandbox Code Playgroud)

但是,内容类型标题是:

Content-Type: text/html
Run Code Online (Sandbox Code Playgroud)

并不是:

Content-Type: text/html; charset=utf-8
Run Code Online (Sandbox Code Playgroud)

因此,当我刮,Goutte没有发现它是UTF-8,并且错误地抓取数据.远程站点不在我的控制之下,所以我无法解决问题!这是一组用于复制问题的脚本.一,刮刀:

<?php

require_once realpath(__DIR__ . '/..') . '/vendor/goutte/goutte.phar';

$url = 'http://crawler-tests.local/utf-8.php';
use Goutte\Client;

$client = new Client();
$crawler = $client->request('get', $url);
$text = $crawler->text();
echo 'Whole page: ' . $text . "\n";
Run Code Online (Sandbox Code Playgroud)

现在要放置在Web服务器上的测试页面:

<?php
// Correct
#header('Content-Type: text/html; charset=utf-8');

// Incorrect
header('Content-Type: text/html');
?>  
<!DOCTYPE html>
<html>
    <head>
        <title>UTF-8 test</title>
        <meta charset="utf-8" />
    </head>
    <body>
        <p>When the Content-Header header is incomplete, the pound sign breaks:

        £15,216</p>
    </body>
</html>
Run Code Online (Sandbox Code Playgroud)

这是Goutte测试的输出:

整页:UTF-8测试当Content-Header标题不完整时,英镑符号中断:£15,216

正如您在上一个脚本中的注释中所看到的,正确地声明标头中的字符集可以修复问题.我在Goutte周围寻找,看看是否有任何东西看起来会迫使字符集,但无济于事.有任何想法吗?

Pet*_*ter 15

问题实际上是symfony/browser-kit和symfony/domcrawler.browserkit Client 不检查HTML元标记以仅确定charset,content-type标头.当响应体被移交给domcrawler,它被处理默认字符集ISO-8859-1.在检查了meta标签后,应该恢复决策并重建DomDocument,但这种情况从未发生过.

最简单的解决方法是换$crawler->text()utf8_decode():

$text = utf8_decode($crawler->text());
Run Code Online (Sandbox Code Playgroud)

如果输入为UTF-8,则此方法有效.我想对于其他编码类似的东西可以用iconv()左右来实现.但是,每次打电话时都必须记住这样做text().

更通用的方法是让Domcrawler相信它处理UTF-8.为此,我想出了一个Guzzle插件,它在内容类型响应头中覆盖(或添加)charset.您可以在https://gist.github.com/pschultz/6554265找到它.用法是这样的:

<?php

use Goutte\Client;


$plugin = new ForceCharsetPlugin();
$plugin->setForcedCharset('utf-8');

$client = new Client();
$client->getClient()->addSubscriber($plugin);
$crawler = $client->request('get', $url);

echo $crawler->text();
Run Code Online (Sandbox Code Playgroud)


hal*_*fer 11

我似乎在这里遇到了两个错误,其中一个是彼得的回答.另一种是我分别使用Symfony Crawler类来探索HTML片段的方式.

我这样做(解析表格行的HTML):

$subCrawler = new Crawler($rowHtml);
Run Code Online (Sandbox Code Playgroud)

但是,通过构造函数添加HTML似乎并未提供可以指定字符集的方法,并且我假设ISO-8859-1再次是默认值.

只需使用addHtmlContent就可以了; 第二个参数指定字符集,如果未指定,则默认为UTF-8.

$subCrawler = new Crawler();
$subCrawler->addHtmlContent($rowHtml);
Run Code Online (Sandbox Code Playgroud)