2013-03-11 63 views
1

我通过链接使用foreach循环。我需要$mech->back();来继续循环还是隐式的。WWW ::机械化:: Firefox的循环虽然链接

此外,我需要一个单独的$mech2对象为每个循环嵌套?

我现在的代码被卡住了(它没有完成),并在没有找到td#tabcolor3的第一页结束。

foreach my $sector ($mech->selector('a.link2')) 
{ 
    $mech->follow_link($sector); 

    foreach my $place ($mech->selector('td#tabcolor3')) 
    { 
      if (($mech->selector('td#tabcolor3', all=>1)) >= 1) 
    { 
     $mech->follow_link($place); 
      print $_->{innerHTML}, '\n' 
      for $mech->selector('td.dataCell'); 
     $mech->back(); 
    } 
    else 
    { 
     $mech->back(); 
    } 
} 

回答

1

不能从页面访问信息,当它不再显示。然而,这样foreach作品是建立列表第一它是通过迭代之前,所以你写的代码应该罚款。

由于链接是绝对的,因此不需要拨打back。如果您用过click那么就必须在页面点击一个链接,但与follow_link所有你正在做的是去一个新的URL。

也不需要检查要遵循的链接数,因为for循环遍历空列表将不会被执行。

为了使事情更清晰,我建议您在循环之前将selector的结果赋值给一个数组。

像这样

my @sectors = $mech->selector('a.link2'); 
for my $sector (@sectors) { 

    $mech->follow_link($sector); 

    my @places = $mech->selector('td#tabcolor3'); 
    for my $place (@places) { 

     $mech->follow_link($place); 

     print $_->{innerHTML}, '\n' for $mech->selector('td.dataCell'); 
    } 
} 

更新

我的道歉。看来,follow_link是挑剔的,需要按照当前页面上的链接

我建议您从每个链接中提取href属性,并使用get而不是follow_link

my @selectors = map $_->{href}, $mech->selector('a.link2'); 
for my $selector (@selectors) { 

    $mech->get($selector); 

    my @places = map $_->{href}, $mech->selector('td#tabcolor3'); 
    for my $place (@places) { 

     $mech->get($place); 

     print $_->{innerHTML}, '\n' for $mech->selector('td.dataCell'); 
    } 
} 

请让我知道这是否适用于您要连接到的网站。

+0

感谢更多优雅的解决方案。我得到一个Mozrepl :: RemoteObject:TypeError - 不能访问这个行的死对象:= $ mech-> follow_link($ share); #it​​显示在上面...我认为有一个嵌套的问题...我是否需要一个单独的机甲物体作为以前的答案建议? – surfer190 2013-03-11 11:43:08

+0

对不起,行是:$ mech-> follow_link($ place); – surfer190 2013-03-11 12:07:56

+0

从[*最新的修改列表*](http://cpansearch.perl.org/src/CORION/WWW-Mechanize-Firefox-0.70/Changes),它看起来像从Firefox 15开始的“死对象”问题。已经更新了我的解决方案以展示另一种方法。 – Borodin 2013-03-11 12:51:50

1

我建议使用单独的$机甲的对象是:

foreach my $sector ($mech->selector('a.link2')) 
{ 
    my $mech = $mech->clone(); 
    $mech->follow_link($sector); 

    foreach my $place ($mech->selector('td#tabcolor3')) 
    { 
      if (($mech->selector('td#tabcolor3', all=>1)) >= 1) 
    { 
      my $mech = $mech->clone(); 
      $mech->follow_link($place); 
      print $_->{innerHTML}, '\n' 
      for $mech->selector('td.dataCell'); 
     #$mech->back(); 
    } 
# else 
# { 
#  $mech->back(); 
# } 
} 
+0

为什么你推荐多个机械化对象? – Borodin 2013-03-11 11:20:02

+0

因为我可以很容易地将此​​代码更改为与多个线程一起使用。我在谈论经典的WWW :: Mechanize当然不是Firefox。 – gangabass 2013-03-11 11:57:53

+0

'克隆'方法列在模块文档下的*函数中,可能永远不会实现*。假设你没有测试过你的代码? – Borodin 2013-03-11 12:14:08

0

我使用WWW:机械化:: Firefox来遍历使用Javascript的负荷一堆网址。页面不立即渲染,因此需要测试一个特定的页面元素是否可见(类似于Mechanize :: Firefox文档中的建议,除了测试中的两个xpaths),然后再决定下一个操作。

页面最终呈现一个XPath来“无信息”或某些约2-3秒后想要的东西。如果没有信息,我们会转到下一个网址。我认为存在某种竞争条件,这两种xpath不会立即导致间歇性地(在循环中的sleep 1足够奇怪)造成MozRepl::RemoteObject: TypeError: can't access dead object错误。

我的解决方案,似乎工作/提高可靠性是包围所有$mech->get$mech->is_visibleeval{};这样的:

eval{ 
    $mech->get("$url"); 
    $retries = 15; #test to see if element visible = page complete 
    while ($retries-- and ! $mech->is_visible(xpath => $xpath_btn) and ! $mech->is_visible(xpath => $xpath_no_info)){ 
    sleep 1; 
    }; 
    last if($mech->is_visible(xpath => $xpath_no_info)); #skip rest if no info page 
}; 

其他人可能会认为这一改进。