Search code examples
perldommojoliciousmojo

Can't locate module(s) using Mojo::DOM


I'm new to Mojolicious. I am sure this is probably a setup problem, but it's eaten up an entire day of my time. I'm trying to run this simple test code

#!/usr/bin/perl

use strict;
use warnings;
use Mojo::DOM;
use Mojo::UserAgent;

my $ua = Mojo::UserAgent->new();

$ua->get('https://stackoverflow.com/questions/26353298/find-links-containing-bold-text-using-wwwmechanize')->res->dom('a div')->ancestors('div.spacer')->each( sub { say $_->all_text } );

which I found at this location

find links containing bold text using WWW::Mechanize

and it is failing with

Can't locate object method "ancestors" via package "Mojo::Collection" at ./test4.pl line 10.

I've deinstalled and reinstalled a jillion times, tried different package installation options (cpan, cpanm, direct link, etc). No dice. I am mildly confused that the Mojo::Collection module does not appear to have an "ancestors" method in it (inherited or no), but I've seen several other examples like this which appear to use the same method in the same way. It's not just the "ancestors" module, either -- the problem seems to be affecting a few other methods as well.

I'm using perl 5.18.2 on Linux Mint with Mojolicious package 6.11.

Thanks for any help.


Solution

  • It's very difficult to debug a single long chained statement like that, and you're much better off splitting it into individual steps

    Passing a parameter to the dom method is the same as calling find with that parameter on the DOM object. find returns a Mojo::Collection, which makes sense as it's the set of nodes that match the CSS selector. The ancestors method applies only to a single node, so you have to pick one out with something like first or last, or process them all one at a time using each

    Here's a rewrite of your code that produces what I assume is the expected result

    use strict;
    use warnings;
    use 5.010;
    
    use open qw/ :std :encoding(UTF-8) /;
    
    use Mojo;
    
    my $url = 'http://stackoverflow.com/q/26353298';
    
    my $ua = Mojo::UserAgent->new->max_redirects(3);
    my $dom = $ua->get($url)->res->dom;
    
    my $divs = $dom->find('a div');
    
    printf "%d matching div elements:\n\n", $divs->size;
    
    my $n;
    for my $div ( $divs->each ) {
      my $spacers = $div->ancestors('div.spacer');
      for my $spacer ( $spacers->each ) {
        printf "%2d -- %s\n\n", ++$n, $spacer->all_text;
      }
    }
    

    output

    20 matching div elements:
    
     1 -- Stack Exchange Podcast #65: The Word Has Two Meanings, You See
    
     2 -- PIVOTing into a new career: please welcome Taryn Pratt, bluefooted Community …
    
     3 -- 0 Can't locate module(s) using Mojo::DOM
    
     4 -- 0 tiny runable www::Mechanize examples for the beginner
    
     5 -- 2 Perl WWW::Mechanize and authenticated proxy
    
     6 -- 0 How to process a simple loop in Perl's WWW::Mechanize?
    
     7 -- 1 not able to click a button in www::mechanize perl
    
     8 -- 0 Perl - Mechanize? - How to get all links in a page up to a specific “delimiter” text
    
     9 -- 2 Why am I getting gibberish content using Perl's WWW::Mechanize?
    
    10 -- 1 Getting error in accessing a link using WWW::Mechanize
    
    11 -- 3 Perl WWW::Mechanize Web Spider. How to find all links
    
    12 -- 0 What is the best way to extract unique URLs and related link text via perl mechanize?
    
    13 -- 0 perl WWW::Mechanize file upload error