user241126
user241126

Reputation: 93

How can I extract HTML img tags wrapped in anchors in Perl?

I am working on parsing HTML obtain all the hrefs that match a particular url (let's call it "target url") and then get the anchor text. I have tried LinkExtractor, TokenParser, Mechanize, TreeBuilder modules. For below HTML:

 <a href="target_url">
 <img src=somepath/nw.gf alt="Open this result in new window"> 
 </a>

all of them give "Open this result in new window" as the anchor text. Ideally I would like to see blank value or a string like "image" returned so that I know there was no anchor text but the href still matched the target url (http://www.yahoo.com in this case). Is there a way to get the desired result using other module or Perl regex?

Thanks,

Upvotes: 1

Views: 1583

Answers (3)

Ven&#39;Tatsu
Ven&#39;Tatsu

Reputation: 3635

If the HTML you are working with is fairly close to well formed you can usually load it into an XML module that supports HTML and use it to find and extract data from the parts of the document you are interested in. My method of choice is XML::LibXML and XPath.

use XML::LibXML;

my $parser = XML::LibXML->new();
my $html = ...;
my $doc = $parser->parse_html_string($html);

my @links = $doc->findnodes('//a[@href = "http://example.com"]');
for my $node (@links) {
    say $node->textContent();
}

The string passed to findnodes is an XPath expression that looks for all 'a' element descendants of $doc that have an href attribute equal to "http://example.com".

Upvotes: 0

draegtun
draegtun

Reputation: 22570

You should post some examples that you tried with "LinkExtractor, TokenParser, Mechanize & TreeBuilder" so that we can help you.

Here is something which works for me in pQuery:

use pQuery;

my $data = '
  <html>
    <a href="http://www.something.com">Not yahoo anchor text</a>
    <a href="http://www.yahoo.com"><img src="somepath/nw.gif" alt="Open this result in new window"></img></a>
    <a href="http://www.yahoo.com">just text for yahoo</a>
    <a href="http://www.yahoo.com">anchor text only<img src="blah" alt="alt text"/></a>
  </html>
';

pQuery( $data )->find( 'a' )->each(
    sub {
        say $_->innerHTML 
            if $_->getAttribute( 'href' ) eq 'http://www.yahoo.com';
    }
);

# produces:
#
# => <img alt="Open this result in new window" src="somepath/nw.gif"></img>
# => just text for yahoo
# => anchor text only<img /="/" alt="alt text" src="blah"></img>
#

And if you just want the text:

pQuery( $data )->find( 'a' )->each(
    sub {
        return unless $_->getAttribute( 'href' ) eq 'http://www.yahoo.com';

        if ( my $text = pQuery($_)->text ) { say $text }
    }
);

# produces:
#
# => just text for yahoo
# => anchor text only
#

/I3az/

Upvotes: 3

user240438
user240438

Reputation:

Use a proper parser (like HTML::Parser or HTML::TreeBuilder). Using regular expressions to parse SGML (HTML/XML included) isn't really all that effective because of funny multiline tags and attributes like the one you've run into.

Upvotes: 1

Related Questions