【问题标题】:HTML parsing with Perl LWP gives incorrect results使用 Perl LWP 进行 HTML 解析会给出不正确的结果
【发布时间】:2013-06-01 10:22:44
【问题描述】:

我正在尝试抓取 http://www.imdb.com/find?q=Yek+mard%2C+yek+khers&s=all 的 HTML。结果集包含一个单一的结果,在类result_text 中。所以我输入链接,获取该链接中的文本,在这种情况下,如 Firebug 所示,是A Man, a Bear。但奇怪的是,下面的代码打印出Yek mard, yek khers。谁能帮助我如何获取我在浏览器中看到的文本?

$name = "Yek mard, yek khers";
$uri = URI->new("http://www.imdb.com/find?q=".uri_escape($name)."&s=all");
my $response = $ua->get( $uri );

my $root = HTML::TreeBuilder->new_from_content($response->decoded_content);
@results = $root->find_by_attribute("class","result_text");
$link = $results[0]->find_by_tag_name("a");
say $link->as_HTML();
# This should print <a href="/title/tt0122857/?ref_=fn_al_tt_1">A Man, a Bear</a>
# but prints <a href="/title/tt0122857/?ref_=fn_al_tt_1">Yek mard, yek khers</a>

【问题讨论】:

  • 对于给定的 URL,我也得到了 Yek mard, yek khers。您能否查看您使用浏览器发送的标头,尤其是Accept-Language?返回页面的Content-language也可能很有趣。
  • 嗯,我不知道如何检查,或者发送请求时如何将其设置为英文.. :(
  • 如果你看源码,在结束标签之前有一个空格,不知道它是否与它有任何关系,但可能值得一看。您是否尝试过获取所有链接,然后使用类似 $href = $link->look_down(sub{ $_[0]-> tag() eq 'a'});然后当你点击正确的时候,打印 $href->as_text
  • 我在 Firebug 中看到的标签是 男人,熊 .你说的是哪个空间?
  • Firebug“清理东西”,看源码,看空间? 人,熊

标签: perl screen-scraping lwp


【解决方案1】:

更新

我很抱歉。进一步查看后,我发现 IMDb 使用 HTTP 请求的 Accept-Language 标头来确定如何呈现页面。默认情况下,LWP 根本不发送此标头,但 Firefox 会发送,这就是我上面的解决方案正常工作的原因。

因此,仅使用 LWP 的解决方案是可能的。定制请求必须首先使用HTTP::Request 对象构建,然后使用request 方法传递给LWP::UserAgent 对象。

此代码演示。

use strict;
use warnings;

use feature 'say';

use LWP;
use HTML::TreeBuilder::XPath;

my $url = 'http://www.imdb.com/find?q=Yek+mard%2C+yek+khers&s=all';

my $ua = LWP::UserAgent->new;
my $req = HTTP::Request->new(GET => $url, ['Accept-Language' => 'en-gb,en']);
my $resp = $ua->request($req);

my $tree = HTML::TreeBuilder::XPath->new_from_content($resp->decoded_content);
my @results = $tree->findnodes_as_strings('//td[@class="result_text"]/a/text()');

say $results[0];

输出和以前一样。


原答案

问题是您在浏览器中看到的内容是在页面加载后由 JavaScript 代码生成的。 LWPHTML::TreeBuilder 的简单组合无法处理站点返回的原始 HTML 之外的任何内容。

为此推荐的常用解决方案是使用WWW::Mechanize::Firefox 模块,该模块使用实时Firefox 进程来获取HTML 和JavaScript 并呈现页面。请注意,它需要在您的计算机上安装 Firefox 浏览器,并且必须安装并运行 MozRepl Firefox 插件。

此程序显示返回您期望的结果的工作代码。请注意,我还使用了HTML::TreeBuilder::XPath 而不是裸露的HTML::TreeBuilder,这样可以更简单地表达您感兴趣的 HTML 部分。

use strict;
use warnings;

use feature 'say';

use WWW::Mechanize::Firefox;
use HTML::TreeBuilder::XPath;

my $url = 'http://www.imdb.com/find?q=Yek+mard%2C+yek+khers&s=all';

my $mech = WWW::Mechanize::Firefox->new;
$mech->get($url);

my $tree = HTML::TreeBuilder::XPath->new_from_content($mech->response->content);
my @results = $tree->findnodes_as_strings('//td[@class="result_text"]/a/text()');

say $results[0];

输出

A Man, a Bear

【讨论】:

  • 所以你说服务器返回的原始 HTML 包含 Yek mard, yek khers,页面加载后,JS 将其转换为 A Man, a熊,对吧? JS是怎么转换的?在服务器返回的原始 HTML 中,我们看到的字符串 A Man, a Bear 在哪里?
  • @Cupidvogel:我很抱歉。问题与我最初猜测的不同。查看我的答案的更新。
  • 无需道歉.. :) 非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-27
  • 2017-12-14
  • 2019-03-12
相关资源
最近更新 更多