Perl 无法提取与Mojolicous的链接
我试图使用Mojo::DOM提取搜索结果页面中下一页的链接。但是,我有一个问题,在对现有元素使用Perl 无法提取与Mojolicous的链接,perl,web-scraping,mojolicious,Perl,Web Scraping,Mojolicious,我试图使用Mojo::DOM提取搜索结果页面中下一页的链接。但是,我有一个问题,在对现有元素使用->find()之后,我得到了一个字符串,而不是Mojo::DOM元素 我有: my $pagination_elements = $dom->find("div[class*=\"pagination-block\"]"); my $page_counter_text = $pagination_elements->find("div[class=\"page-of-pages\"]")
->find()
之后,我得到了一个字符串,而不是Mojo::DOM元素
我有:
my $pagination_elements = $dom->find("div[class*=\"pagination-block\"]");
my $page_counter_text = $pagination_elements->find("div[class=\"page-of-pages\"]")->text();
$page_counter_text =~ /^Page (\d+) of (\d+)$/;
my $current_page = int($1);
my $last_page = int($2);
my $prev_next_elements = $pagination_elements->find("a[class*=\"prev-next\"]");
my $next_page_link = $prev_next_elements->last();
my $next_page_url = $next_page_link->attr("href");
在每个页面上,可能有2个链接标签,其类别为prev-next
。我得到的不是最后一个元素的链接,而是一个字符串,其中包含两个标记的href
(如果页面上都有)
现在,如果我不这样做:
my $next_page_link = $dom->find("div[class*=\"pagination-block\"] > ul > li > a[class*=\"prev-next\"]")->last();
my $next_page_url_rel = $next_page_link->attr("href");
我得到了所需的链接
我的问题是,为什么第二个版本有效而第一个版本无效?为什么我必须从根DOM元素开始获取元素列表,为什么从根的子元素开始返回一个包含所有链接标记的字符串,而不仅仅是我想要的链接标记
编辑
我正在解析的HTML的一个示例是:
<div class="pagination-block clearfix">
<div class="page-of-pages">
Page 2 of 100
</div>
<ul class="pagination-links">
<li>
.
.
.
</li>
<li>
<a class="page-option prev-next" href="PREV LINK">Prev</a>
</li>
<li>
<a class="page-option prev-next" href="NEXT LINK">Next</a>
</li>
</ul>
</div>
第2页,共100页
-
.
.
.
-
-
如果您能展示一个您正在处理的HTML示例,那么它会有很大帮助。相反,我想象了这一点,我希望这一点很接近
<html>
<head>
<title>Title</title>
</head>
<body>
<div class="pagination-block">
<div class="page-of-pages">Page 99 of 100</div>
<ul>
<li>
<a class="prev-next" href="/page98">Prev</a>
</li>
<li>
<a class="prev-next" href="/page100">Next</a>
</li>
<ul>
</div>
<div class="pagination-block">
<div class="page-of-pages">Page 99 of 100</div>
<ul>
<li>
<a class="prev-next" href="/page98">Prev</a>
</li>
<li>
<a class="prev-next" href="/page100">Next</a>
</li>
<ul>
</div>
</body>
</html>
这将为您提供一个Mojo::Collection
,其中包含具有分页块的div
的两个实例
my $prev_next_elements = $pagination_elements->find('a[class*="prev-next"]')
这类似于一个映射
,将Mojo::集合
的每个成员替换为对其执行查找
的结果。由于find
返回另一个Mojo::Collection
,您现在拥有两个集合的集合,每个集合都有两个Mojo::DOM
对象。澄清
$prev\u next\u elements
是一个Mojo::Collection
对象,其大小为2
$prev\u next\u元素->[0]
和$prev\u next\u元素->[1]
都是Mojo::Collection
对象,每个对象的大小为2
$prev\u next\u elements->[0][0]
、$prev\u next\u elements->[0][1]
、$prev\u next\u elements->[1][0]
和$prev\u next\u elements->[1][/code>都是Mojo DOM
对象,每个对象都包含HTML文档中的
元素
my$next\u page\u link=$prev\u next\u elements->last
这将获取$prev\u next\u elements
的第二个元素。它与$prev\u next\u elements->[1]
相同,它也是一个Mojo::Collection
对象,包含两个Mojo::DOM
元素,它们保存HTML文档中最后两个
元素
my$next\u page\u url=$next\u page\u link->attr('href')
现在您正在执行另一个map
操作:将attr
应用于集合的两个元素,并返回另一个包含两个href
字符串/page98
和/page100
的集合。t对这个Mogo::Collection
进行加密,只需将它的所有元素连接起来,就可以得到“/page98\n/page100”
要解决所有这些问题,请获取$pagination_元素的最后一个,为您提供一个Mojo::DOM
对象。然后对prev
和next
元素执行find
,为您提供Mojo::Collection
“prev”和
“下一步”
元素,最后使用attr('href')
将这些元素映射到链接。最后,您将看到Mojo::Collection
,其中包含最后一个分页块中“prev”和“next”链接的href
文本
my $pagination_elements = $dom->find('div[class*="pagination-block"]');
my $last_pagination_element = $pagination_elements->last;
my $prev_next_elements = $last_pagination_element->find('a[class*="prev-next"]');
my $prev_next_links = $prev_next_elements->attr('href');
my ($prev_page_link, $next_page_link) = ($prev_next_links->first, $prev_next_links->last);
say $prev_page_link;
say $next_page_link;
输出
/page98
/page100
你可以把这些折叠成更方便的东西,像这样
my $pagination_elements = $dom->find('div[class*="pagination-block"]');
my $prev_next_links = $pagination_elements->last->find('a[class*="prev-next"]')->attr('href');
my ($prev_page_link, $next_page_link) = @$prev_next_links;
say $prev_page_link;
say $next_page_link;
如果您使用(或某个等效模块)而不是,您将得到关于发生了什么的线索:
use Data::Dump;
dd $next_page_url;
dd $next_page_url_rel;
产出:
bless(["PREV LINK", "NEXT LINK"], "Mojo::Collection")
"NEXT LINK"
"NEXT LINK"
"NEXT LINK"
如您所见,第一个变量实际上包含一个集合,而不是一个字符串
出现问题的原因是返回:
对集合执行后续的find
操作会返回一个嵌套集合,它不会像调用last
那样执行预期的操作
以下是三种不同的解决方案,用于修复您第一次尝试查找链接文本的问题:
使用该方法查找DOM结构中与CSS选择器匹配的第一个元素
my $pagination_elements = $dom->at('div[class*="pagination-block"]');
在后续的find
之前,使用或隔离集合中的特定元素
my $pagination_elements
= $dom->find('div[class*="pagination-block"]')->last();
用于将后续的find
创建的嵌套集合展平到包含所有元素的新集合中:
my $pagination_elements = $dom->find('div[class*="pagination-block"]');
my $prev_next_elements
= $pagination_elements->find('a[class*="prev-next"]')->flatten();
所有这些方法都将使脚本按预期工作:
use strict;
use warnings;
use Mojo::DOM;
use Data::Dump;
my $dom = Mojo::DOM->new(do { local $/; <DATA> });
# Fix 1
my $pagination_elements = $dom->at('div[class*="pagination-block"]');
# Fix 2
#my $pagination_elements
# = $dom->find('div[class*="pagination-block"]')->last();
# Fix 3
#my $pagination_elements = $dom->find('div[class*="pagination-block"]');
#my $prev_next_elements
# = $pagination_elements->find('a[class*="prev-next"]')->flatten();
my $prev_next_elements = $pagination_elements->find('a[class*="prev-next"]');
my $next_page_link = $prev_next_elements->last();
my $next_page_url = $next_page_link->attr("href");
dd $next_page_url;
$next_page_link = $dom->find('div[class*="pagination-block"] > ul > li > a[class*="prev-next"]')->last();
my $next_page_url_rel = $next_page_link->attr("href");
dd $next_page_url_rel;
__DATA__
<html>
<head>
<title>Paging Example</title>
</head>
<body>
<div class="pagination-block clearfix">
<div class="page-of-pages">
Page 2 of 100
</div>
<ul class="pagination-links">
<li>
.
.
.
</li>
<li>
<a class="page-option prev-next" href="PREV LINK">Prev</a>
</li>
<li>
<a class="page-option prev-next" href="NEXT LINK">Next</a>
</li>
</ul>
</div>
</body>
</html>
如果你也能提供一份报告,建议就容易多了。以html页面为例,将其缩减为您正在讨论的部分,并将这些数据包含在您的文章中。@Miller示例已添加。谢谢!你的解释很有道理。但是,我正在解析的HTML只有一个分页块
。我在上面粘贴了一个示例。我希望你也能帮我解决这个问题?@Jibran:我的修复程序只需一个分页块
。唯一的区别是对last
的调用将返回一个块中的最后一个,而不是两个块中的最后一个。您必须以某种方式从Mojo::Collection
中提取Mojo::DOM
对象,并且使用last
是一种与任何方法一样好的方法。@Borodin我创建了一个答案,其中有两个额外的问题解决方案。因为我学到了一些东西,所以给你发了个通知。
use strict;
use warnings;
use Mojo::DOM;
use Data::Dump;
my $dom = Mojo::DOM->new(do { local $/; <DATA> });
# Fix 1
my $pagination_elements = $dom->at('div[class*="pagination-block"]');
# Fix 2
#my $pagination_elements
# = $dom->find('div[class*="pagination-block"]')->last();
# Fix 3
#my $pagination_elements = $dom->find('div[class*="pagination-block"]');
#my $prev_next_elements
# = $pagination_elements->find('a[class*="prev-next"]')->flatten();
my $prev_next_elements = $pagination_elements->find('a[class*="prev-next"]');
my $next_page_link = $prev_next_elements->last();
my $next_page_url = $next_page_link->attr("href");
dd $next_page_url;
$next_page_link = $dom->find('div[class*="pagination-block"] > ul > li > a[class*="prev-next"]')->last();
my $next_page_url_rel = $next_page_link->attr("href");
dd $next_page_url_rel;
__DATA__
<html>
<head>
<title>Paging Example</title>
</head>
<body>
<div class="pagination-block clearfix">
<div class="page-of-pages">
Page 2 of 100
</div>
<ul class="pagination-links">
<li>
.
.
.
</li>
<li>
<a class="page-option prev-next" href="PREV LINK">Prev</a>
</li>
<li>
<a class="page-option prev-next" href="NEXT LINK">Next</a>
</li>
</ul>
</div>
</body>
</html>
"NEXT LINK"
"NEXT LINK"