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)