使用 HTML::TreeBuilder as_HTML 后编码损坏

use*_*035 2 perl encoding html-parsing

假设,我们有以下文件:

\n

测试.html

\n
<!DOCTYPE html>\n<html>\n  <head>\n    <title>\xd0\x95\xd0\xb2\xd0\xb3\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb9 \xd0\x9e\xd0\xbd\xd0\xb5\xd0\xb3\xd0\xb8\xd0\xbd</title>\n    <meta charset="utf-8">\n  </head>\n  <body>\n    <p><cite>\xd0\x95\xd0\xb2\xd0\xb3\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb9 \xd0\x9e\xd0\xbd\xd0\xb5\xd0\xb3\xd0\xb8\xd0\xbd</cite></p>\n    <pre>\n      \xd0\x9d\xd0\xb5 \xd0\xbc\xd1\x8b\xd1\x81\xd0\xbb\xd1\x8f \xd0\xb3\xd0\xbe\xd1\x80\xd0\xb4\xd1\x8b\xd0\xb9 \xd1\x81\xd0\xb2\xd0\xb5\xd1\x82 \xd0\xb7\xd0\xb0\xd0\xb1\xd0\xb0\xd0\xb2\xd0\xb8\xd1\x82\xd1\x8c,\n      \xd0\x92\xd0\xbd\xd0\xb8\xd0\xbc\xd0\xb0\xd0\xbd\xd1\x8c\xd0\xb5 \xd0\xb4\xd1\x80\xd1\x83\xd0\xb6\xd0\xb1\xd1\x8b \xd0\xb2\xd0\xbe\xd0\xb7\xd0\xbb\xd1\x8e\xd0\xb1\xd1\x8f,\n      \xd0\xa5\xd0\xbe\xd1\x82\xd0\xb5\xd0\xbb \xd0\xb1\xd1\x8b \xd1\x8f \xd1\x82\xd0\xb5\xd0\xb1\xd0\xb5 \xd0\xbf\xd1\x80\xd0\xb5\xd0\xb4\xd1\x81\xd1\x82\xd0\xb0\xd0\xb2\xd0\xb8\xd1\x82\xd1\x8c\n      \xd0\x97\xd0\xb0\xd0\xbb\xd0\xbe\xd0\xb3 \xd0\xb4\xd0\xbe\xd1\x81\xd1\x82\xd0\xbe\xd0\xb9\xd0\xbd\xd0\xb5\xd0\xb5 \xd1\x82\xd0\xb5\xd0\xb1\xd1\x8f,\n    </pre>\n</body>\n</html>\n
Run Code Online (Sandbox Code Playgroud)\n

我想使用解析器获取 HTML 格式的 body 标签的内容:

\n
<p><cite>\xd0\x95\xd0\xb2\xd0\xb3\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb9 \xd0\x9e\xd0\xbd\xd0\xb5\xd0\xb3\xd0\xb8\xd0\xbd</cite></p>\n<pre>\n  \xd0\x9d\xd0\xb5 \xd0\xbc\xd1\x8b\xd1\x81\xd0\xbb\xd1\x8f \xd0\xb3\xd0\xbe\xd1\x80\xd0\xb4\xd1\x8b\xd0\xb9 \xd1\x81\xd0\xb2\xd0\xb5\xd1\x82 \xd0\xb7\xd0\xb0\xd0\xb1\xd0\xb0\xd0\xb2\xd0\xb8\xd1\x82\xd1\x8c,\n  \xd0\x92\xd0\xbd\xd0\xb8\xd0\xbc\xd0\xb0\xd0\xbd\xd1\x8c\xd0\xb5 \xd0\xb4\xd1\x80\xd1\x83\xd0\xb6\xd0\xb1\xd1\x8b \xd0\xb2\xd0\xbe\xd0\xb7\xd0\xbb\xd1\x8e\xd0\xb1\xd1\x8f,\n  \xd0\xa5\xd0\xbe\xd1\x82\xd0\xb5\xd0\xbb \xd0\xb1\xd1\x8b \xd1\x8f \xd1\x82\xd0\xb5\xd0\xb1\xd0\xb5 \xd0\xbf\xd1\x80\xd0\xb5\xd0\xb4\xd1\x81\xd1\x82\xd0\xb0\xd0\xb2\xd0\xb8\xd1\x82\xd1\x8c\n  \xd0\x97\xd0\xb0\xd0\xbb\xd0\xbe\xd0\xb3 \xd0\xb4\xd0\xbe\xd1\x81\xd1\x82\xd0\xbe\xd0\xb9\xd0\xbd\xd0\xb5\xd0\xb5 \xd1\x82\xd0\xb5\xd0\xb1\xd1\x8f,\n</pre>\n
Run Code Online (Sandbox Code Playgroud)\n

解析器.pl

\n
#!/usr/bin/env perl\n\nuse strict;\nuse warnings;\nuse 5.010;\nuse utf8;\n\nuse HTML::TreeBuilder;\n\nmy $root = HTML::TreeBuilder->new;\n$root->parse_file('test.html');\n\nmy $body = $root->find('body');\nprint $body->as_HTML;\n
Run Code Online (Sandbox Code Playgroud)\n

当我将输出保存到 HTML 文件并在浏览器中以 Unicode 形式观看时,编码被破坏:而不是 "\xd0\x95\xd0\xb2\xd0\xb3\xd0\xb5\xd0\xbd\xd0\xb8\xd0 \xb9 \xd0\x9e\xd0\xbd\xd0\xb5\xd0\xb3\xd0\xb8\xd0\xbd" 我得到 "\xc3\x90\xe2\x80\xa2\xc3\x90\xc2\xb2\xc3 \x90\xc2\xb3\xc3\x90\xc2\xb5\xc3\x90\xc2\xbd\xc3\x90\xc2\xb8\xc3\x90\xc2\xb9\xc3\x90\xc5\xbe\xc3\x90 \xc2\xbd\xc3\x90\xc2\xb5\xc3\x90\xc2\xb3\xc3\x90\xc2\xb8\xc3\x90\xc2\xbd”。

\n

正确的工作

\n

当 HTML 存储在 Perl 文件中时,它可以正常工作:

\n
#!/usr/bin/env perl\n\nuse strict;\nuse warnings;\nuse 5.010;\nuse utf8;\n\nuse Data::Dumper;\nuse HTML::TreeBuilder;\n\nmy $root = HTML::TreeBuilder->new;\n$root->parse_file(\\*DATA);\n\nmy $body = $root->find('body');\nprint $body->as_HTML;\n\n__END__\n<!DOCTYPE html>\n<html>\n  <head>\n    <title>\xd0\x95\xd0\xb2\xd0\xb3\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb9 \xd0\x9e\xd0\xbd\xd0\xb5\xd0\xb3\xd0\xb8\xd0\xbd</title>\n    <meta charset="utf-8">\n  </head>\n  <body>\n    <p><cite>\xd0\x95\xd0\xb2\xd0\xb3\xd0\xb5\xd0\xbd\xd0\xb8\xd0\xb9 \xd0\x9e\xd0\xbd\xd0\xb5\xd0\xb3\xd0\xb8\xd0\xbd</cite></p>\n    <pre>\n      \xd0\x9d\xd0\xb5 \xd0\xbc\xd1\x8b\xd1\x81\xd0\xbb\xd1\x8f \xd0\xb3\xd0\xbe\xd1\x80\xd0\xb4\xd1\x8b\xd0\xb9 \xd1\x81\xd0\xb2\xd0\xb5\xd1\x82 \xd0\xb7\xd0\xb0\xd0\xb1\xd0\xb0\xd0\xb2\xd0\xb8\xd1\x82\xd1\x8c,\n      \xd0\x92\xd0\xbd\xd0\xb8\xd0\xbc\xd0\xb0\xd0\xbd\xd1\x8c\xd0\xb5 \xd0\xb4\xd1\x80\xd1\x83\xd0\xb6\xd0\xb1\xd1\x8b \xd0\xb2\xd0\xbe\xd0\xb7\xd0\xbb\xd1\x8e\xd0\xb1\xd1\x8f,\n      \xd0\xa5\xd0\xbe\xd1\x82\xd0\xb5\xd0\xbb \xd0\xb1\xd1\x8b \xd1\x8f \xd1\x82\xd0\xb5\xd0\xb1\xd0\xb5 \xd0\xbf\xd1\x80\xd0\xb5\xd0\xb4\xd1\x81\xd1\x82\xd0\xb0\xd0\xb2\xd0\xb8\xd1\x82\xd1\x8c\n      \xd0\x97\xd0\xb0\xd0\xbb\xd0\xbe\xd0\xb3 \xd0\xb4\xd0\xbe\xd1\x81\xd1\x82\xd0\xbe\xd0\xb9\xd0\xbd\xd0\xb5\xd0\xb5 \xd1\x82\xd0\xb5\xd0\xb1\xd1\x8f,\n    </pre>\n</body>\n</html>\n
Run Code Online (Sandbox Code Playgroud)\n

因此,当 HTML::TreeBuilder 从文件读取时,会发生错误。

\n

问题:

\n
    \n
  1. 如何修复编码?
  2. \n
  3. 该模块将每个俄语字符编码为一个实体:&#x415;。是否可以将其另存为角色\xd0\x95?
  4. \n
\n

Bor*_*din 5

该parse_file方法将采用文件名或文件句柄,因此最简单的解决方案是通过调用openusing:utf8作为模式打开文件,然后传递要解析的文件句柄。

看起来像这样。我使用new_from_file构造函数只是因为它保存了一条语句。它与您自己的代码具有完全相同的效果。

#!/usr/bin/env perl

use strict;
use warnings;
use 5.010;
use utf8;

use HTML::TreeBuilder;

my $file = 'test.html';

open my $fh, '<:utf8', $file or die qq{Unable to open "$file" for parsing: $!};
my $root = HTML::TreeBuilder->new_from_file($fh);

my $body = $root->find('body');
print $body->as_HTML;
Run Code Online (Sandbox Code Playgroud)

至于将实体改为字母,我不清楚你的意思。您是否只想删除所有十六进制实体并将其替换为等效字符?您可能会从该模块中获得一些里程 HTML::Entities。

  • @user4035:我很高兴听到这个消息。但请务必小心,因为如果文本中存在任何“&lt;”或“&gt;”,则“decode_entities”会将它们转换为“&lt;”和“&gt;”,这将使 HTML 无效。 (2认同)