web-dev-qa-db-fra.com

Pouvez-vous fournir des exemples d'analyse HTML?

Comment analyser le HTML avec une variété de langues et de bibliothèques d'analyse? 


En répondant:

Les commentaires individuels seront liés aux réponses aux questions sur la façon d’analyser le HTML avec des expressions rationnelles afin de montrer la bonne façon de faire les choses.

Par souci de cohérence, je demande que l'exemple analyse un fichier HTML pour la variable href dans les balises d'ancrage. Pour faciliter la recherche dans cette question, je vous demande de suivre ce format.

Langue: [nom de la langue]

Bibliothèque: [nom de la bibliothèque]

[example code]

Faites de la bibliothèque un lien vers la documentation de la bibliothèque. Si vous souhaitez fournir un exemple autre que l'extraction de liens, veuillez également inclure:

But: [ce que l'analyse fait]

69
Chas. Owens

Langue: JavaScript
Bibliothèque: jQuery

$.each($('a[href]'), function(){
    console.debug(this.href);
});

(en utilisant firebug console.debug pour la sortie ...)

Et en chargeant une page HTML:

$.get('http://stackoverflow.com/', function(page){
     $(page).find('a[href]').each(function(){
        console.debug(this.href);
    });
});

Utilisé une autre chaque fonction pour celle-ci, je pense que c'est plus propre lors de l'enchaînement des méthodes.

29
Ward Werbrouck

Langue: C #
Bibliothèque: HtmlAgilityPack

class Program
{
    static void Main(string[] args)
    {
        var web = new HtmlWeb();
        var doc = web.Load("http://www.stackoverflow.com");

        var nodes = doc.DocumentNode.SelectNodes("//a[@href]");

        foreach (var node in nodes)
        {
            Console.WriteLine(node.InnerHtml);
        }
    }
}
25
alexn

langue: Python
bibliothèque: BeautifulSoup

from BeautifulSoup import BeautifulSoup

html = "<html><body>"
for link in ("foo", "bar", "baz"):
    html += '<a href="http://%s.com">%s</a>' % (link, link)
html += "</body></html>"

soup = BeautifulSoup(html)
links = soup.findAll('a', href=True) # find <a> with a defined href attribute
print links  

sortie:

[<a href="http://foo.com">foo</a>,
 <a href="http://bar.com">bar</a>,
 <a href="http://baz.com">baz</a>]

également possible:

for link in links:
    print link['href']

sortie:

http://foo.com
http://bar.com
http://baz.com
22
Paolo Bergantino

Langue: Perl
Bibliothèque: pQuery

use strict;
use warnings;
use pQuery;

my $html = join '',
    "<html><body>",
    (map { qq(<a href="http://$_.com">$_</a>) } qw/foo bar baz/),
    "</body></html>";

pQuery( $html )->find( 'a' )->each(
    sub {  
        my $at = $_->getAttribute( 'href' ); 
        print "$at\n" if defined $at;
    }
);
20
draegtun

langue: Shell
library: lynx (enfin, ce n'est pas une bibliothèque, mais dans Shell, chaque programme est une sorte de bibliothèque)

lynx -dump -listonly http://news.google.com/
15
user80168

langue: Ruby
bibliothèque: Hpricot

#!/usr/bin/Ruby

require 'hpricot'

html = '<html><body>'
['foo', 'bar', 'baz'].each {|link| html += "<a href=\"http://#{link}.com\">#{link}</a>" }
html += '</body></html>'

doc = Hpricot(html)
doc.search('//a').each {|Elm| puts Elm.attributes['href'] }
14
Pesto

langue: Python
bibliothèque: HTMLParser

#!/usr/bin/python

from HTMLParser import HTMLParser

class FindLinks(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)

    def handle_starttag(self, tag, attrs):
        at = dict(attrs)
        if tag == 'a' and 'href' in at:
            print at['href']


find = FindLinks()

html = "<html><body>"
for link in ("foo", "bar", "baz"):
    html += '<a href="http://%s.com">%s</a>' % (link, link)
html += "</body></html>"

find.feed(html)
12
Chas. Owens

langue: Perl
bibliothèque: HTML :: Parser

#!/usr/bin/Perl

use strict;
use warnings;

use HTML::Parser;

my $find_links = HTML::Parser->new(
    start_h => [
        sub {
            my ($tag, $attr) = @_;
            if ($tag eq 'a' and exists $attr->{href}) {
                print "$attr->{href}\n";
            }
        }, 
        "tag, attr"
    ]
);

my $html = join '',
    "<html><body>",
    (map { qq(<a href="http://$_.com">$_</a>) } qw/foo bar baz/),
    "</body></html>";

$find_links->parse($html);
11
Chas. Owens

Langue Perl
Bibliothèque: HTML :: LinkExtor

La beauté de Perl, c’est que vous avez des modules pour des tâches très spécifiques. Comme l'extraction de lien.

Programme entier:

#!/usr/bin/Perl -w
use strict;

use HTML::LinkExtor;
use LWP::Simple;

my $url     = 'http://www.google.com/';
my $content = get( $url );

my $p       = HTML::LinkExtor->new( \&process_link, $url, );
$p->parse( $content );

exit;

sub process_link {
    my ( $tag, %attr ) = @_;

    return unless $tag eq 'a';
    return unless defined $attr{ 'href' };

    print "- $attr{'href'}\n";
    return;
}

Explication:

  • use strict - active le mode "strict" - facilite le débogage potentiel, pas complètement pertinent pour l'exemple
  • use HTML :: LinkExtor - charge du module intéressant
  • utilisez LWP :: Simple - juste un moyen simple d'obtenir du HTML pour les tests
  • mon $ url = ' http://www.google.com/ ' - la page à partir de laquelle nous allons extraire les URL
  • mon $ content = get ($ url) - récupère la page html
  • mon $ p = HTML :: LinkExtor-> new (\ & process_link, $ url) - crée un objet LinkExtor, lui attribuant une référence à une fonction qui sera utilisée comme rappel sur chaque URL et $ url à utiliser comme BASEURL pour les URL relatives
  • $ p-> parse ($ content) - assez évident je suppose
  • sortie - fin de programme
  • sub process_link - début de la fonction process_link
  • my ($ tag,% attr) - Récupère les arguments, qui sont le nom de la balise et ses attributs
  • return à moins que $ tag eq 'a' - ignore le traitement si le tag n'est pas <a>
  • return à moins que $ attr {'href'} soit défini - ignore le traitement si la balise <a> n'a pas d'attribut href
  • print "- $ attr {'href'}\n"; - assez évident je suppose :)
  • revenir; - terminer la fonction

C'est tout.

9
user80168

Langue: rubis
Bibliothèque: Nokogiri

#!/usr/bin/env Ruby
require 'nokogiri'
require 'open-uri'

document = Nokogiri::HTML(open("http://google.com"))
document.css("html head title").first.content
=> "Google"
document.xpath("//title").first.content
=> "Google"
8
Jules Glegg

Langue: LISP commun
Bibliothèque: Fermeture Html , Fermeture Xml , CL-WHO

(affiché à l'aide de l'API DOM sans utiliser XPATH ou l'API STP)

(defvar *html*
  (who:with-html-output-to-string (stream)
    (:html
     (:body (loop
               for site in (list "foo" "bar" "baz")
               do (who:htm (:a :href (format nil "http://~A.com/" site))))))))

(defvar *dom*
  (chtml:parse *html* (cxml-dom:make-dom-builder)))

(loop
   for tag across (dom:get-elements-by-tag-name *dom* "a")
   collect (dom:get-attribute tag "href"))
=> 
("http://foo.com/" "http://bar.com/" "http://baz.com/")
8
dmitry_vk

Langue: Clojure
Library: Enlive (un système de modélisation et de transformation basé sur un sélecteur (à la CSS) pour Clojure)


Expression du sélecteur:

(def test-select
     (html/select (html/html-resource (Java.io.StringReader. test-html)) [:a]))

Maintenant, nous pouvons faire ce qui suit au REPL (j'ai ajouté des sauts de ligne dans test-select):

user> test-select
({:tag :a, :attrs {:href "http://foo.com/"}, :content ["foo"]}
 {:tag :a, :attrs {:href "http://bar.com/"}, :content ["bar"]}
 {:tag :a, :attrs {:href "http://baz.com/"}, :content ["baz"]})
user> (map #(get-in % [:attrs :href]) test-select)
("http://foo.com/" "http://bar.com/" "http://baz.com/")

Vous aurez besoin de ce qui suit pour l'essayer:

Préambule:

(require '[net.cgrand.enlive-html :as html])

Test HTML:

(def test-html
     (apply str (concat ["<html><body>"]
                        (for [link ["foo" "bar" "baz"]]
                          (str "<a href=\"http://" link ".com/\">" link "</a>"))
                        ["</body></html>"])))
6
Michał Marczyk

Langue: Java
Bibliothèques: XOM , TagSoup

J'ai inclus du code XML intentionnellement mal formé et incohérent dans cet exemple.

import Java.io.IOException;

import nu.xom.Builder;
import nu.xom.Document;
import nu.xom.Element;
import nu.xom.Node;
import nu.xom.Nodes;
import nu.xom.ParsingException;
import nu.xom.ValidityException;

import org.ccil.cowan.tagsoup.Parser;
import org.xml.sax.SAXException;

public class HtmlTest {
    public static void main(final String[] args) throws SAXException, ValidityException, ParsingException, IOException {
        final Parser parser = new Parser();
        parser.setFeature(Parser.namespacesFeature, false);
        final Builder builder = new Builder(parser);
        final Document document = builder.build("<html><body><ul><li><a href=\"http://google.com\">google</li><li><a HREF=\"http://reddit.org\" target=\"_blank\">reddit</a></li><li><a name=\"nothing\">nothing</a><li></ul></body></html>", null);
        final Element root = document.getRootElement();
        final Nodes links = root.query("//a[@href]");
        for (int linkNumber = 0; linkNumber < links.size(); ++linkNumber) {
            final Node node = links.get(linkNumber);
            System.out.println(((Element) node).getAttributeValue("href"));
        }
    }
}

TagSoup ajoute un espace de nom XML référençant XHTML au document par défaut. J'ai choisi de supprimer cela dans cet exemple. L'utilisation du comportement par défaut nécessiterait l'appel de root.query pour inclure un espace de noms comme suit:

root.query("//xhtml:a[@href]", new nu.xom.XPathContext("xhtml", root.getNamespaceURI())
5
laz

langue: Perl
bibliothèque: XML ​​:: Twig

#!/usr/bin/Perl
use strict;
use warnings;
use Encode ':all';

use LWP::Simple;
use XML::Twig;

#my $url = 'http://stackoverflow.com/questions/773340/can-you-provide-an-example-of-parsing-html-with-your-favorite-parser';
my $url = 'http://www.google.com';
my $content = get($url);
die "Couldn't fetch!" unless defined $content;

my $twig = XML::Twig->new();
$twig->parse_html($content);

my @hrefs = map {
    $_->att('href');
} $twig->get_xpath('//*[@href]');

print "$_\n" for @hrefs;

mise en garde: peut générer des erreurs de caractères larges avec des pages telles que celle-ci (le fait de modifier l'URL de celle mise en commentaire provoquera l'erreur), mais la solution HTML :: Parser ci-dessus ne partage pas ce problème.

5
Tanktalus
5
runrig

Langue: JavaScript
Bibliothèque: DOM

var links = document.links;
for(var i in links){
    var href = links[i].href;
    if(href != null) console.debug(href);
}

(en utilisant firebug console.debug pour la sortie ...)

4
Ward Werbrouck

Langue: C #
Bibliothèque: System.XML (standard .NET)

using System.Collections.Generic;
using System.Xml;

public static void Main(string[] args)
{
    List<string> matches = new List<string>();

    XmlDocument xd = new XmlDocument();
    xd.LoadXml("<html>...</html>");

    FindHrefs(xd.FirstChild, matches);
}

static void FindHrefs(XmlNode xn, List<string> matches)
{
    if (xn.Attributes != null && xn.Attributes["href"] != null)
        matches.Add(xn.Attributes["href"].InnerXml);

    foreach (XmlNode child in xn.ChildNodes)
        FindHrefs(child, matches);
}
4
zigzag

Langue: Raquette

Bibliothèque: (planet ashinn/html-parser: 1) et (planet clements/sxml2: 1)

(require net/url
         (planet ashinn/html-parser:1)
         (planet clements/sxml2:1))

(define the-url (string->url "http://stackoverflow.com/"))
(define doc (call/input-url the-url get-pure-port html->sxml))
(define links ((sxpath "//a/@href/text()") doc))

Exemple ci-dessus utilisant des paquets du nouveau système de paquets: html-parsing et sxml

(require net/url
         html-parsing
         sxml)

(define the-url (string->url "http://stackoverflow.com/"))
(define doc (call/input-url the-url get-pure-port html->xexp))
(define links ((sxpath "//a/@href/text()") doc))

Remarque: Installez les packages requis avec 'raco' à partir d'une ligne de commande, avec:

raco pkg install html-parsing

et:

raco pkg install sxml
4
Ryan Culpepper

Langue: Objective-C
Bibliothèque: libxml2 + Les enveloppes libxml2 de Matt Gallagher + ASIHTTPRequest de Ben Copsey

ASIHTTPRequest *request = [ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://stackoverflow.com/questions/773340"];
[request start];
NSError *error = [request error];
if (!error) {
    NSData *response = [request responseData];
    NSLog(@"Data: %@", [[self query:@"//a[@href]" withResponse:response] description]);
    [request release];
}
else 
    @throw [NSException exceptionWithName:@"kMyHTTPRequestFailed" reason:@"Request failed!" userInfo:nil];

...

- (id) query:(NSString *)xpathQuery WithResponse:(NSData *)resp {
    NSArray *nodes = PerformHTMLXPathQuery(resp, xpathQuery);
    if (nodes != nil)
        return nodes;
    return nil;
}
3
Alex Reynolds

Langue: Perl
Bibliothèque: HTML :: TreeBuilder

use strict;
use HTML::TreeBuilder;
use LWP::Simple;

my $content = get 'http://www.stackoverflow.com';
my $document = HTML::TreeBuilder->new->parse($content)->eof;

for my $a ($document->find('a')) {
    print $a->attr('href'), "\n" if $a->attr('href');
}
3
dfa

langue: Python
bibliothèque: lxml.html

import lxml.html

html = "<html><body>"
for link in ("foo", "bar", "baz"):
    html += '<a href="http://%s.com">%s</a>' % (link, link)
html += "</body></html>"

tree = lxml.html.document_fromstring(html)
for element, attribute, link, pos in tree.iterlinks():
    if attribute == "href":
        print link

lxml a aussi une classe de sélecteur CSS pour parcourir le DOM, ce qui peut rendre son utilisation très similaire à celle de JQuery:

for a in tree.cssselect('a[href]'):
    print a.get('href')
3
Adam

Langue: PHP
Bibliothèque: SimpleXML (et DOM)

<?php
$page = new DOMDocument();
$page->strictErrorChecking = false;
$page->loadHTMLFile('http://stackoverflow.com/questions/773340');
$xml = simplexml_import_dom($page);

$links = $xml->xpath('//a[@href]');
foreach($links as $link)
    echo $link['href']."\n";
3
Ward Werbrouck

Langue: Python
Bibliothèque: HTQL

import htql; 

page="<a href=a.html>1</a><a href=b.html>2</a><a href=c.html>3</a>";
query="<a>:href,tx";

for url, text in htql.HTQL(page, query): 
    print url, text;

Simple et intuitif.

1
seagulf

Langue: Java
Bibliothèque: jsoup

import Java.io.IOException;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.xml.sax.SAXException;

public class HtmlTest {
    public static void main(final String[] args) throws SAXException, ValidityException, ParsingException, IOException {
        final Document document = Jsoup.parse("<html><body><ul><li><a href=\"http://google.com\">google</li><li><a HREF=\"http://reddit.org\" target=\"_blank\">reddit</a></li><li><a name=\"nothing\">nothing</a><li></ul></body></html>");
        final Elements links = document.select("a[href]");
        for (final Element element : links) {
            System.out.println(element.attr("href"));
        }
    }
}
1
laz

langue: Ruby
bibliothèque: Nokogiri

#!/usr/bin/env Ruby

require "nokogiri"
require "open-uri"

doc = Nokogiri::HTML(open('http://www.example.com'))
hrefs = doc.search('a').map{ |n| n['href'] }

puts hrefs

Quelles sorties:

/
/domains/
/numbers/
/protocols/
/about/
/go/rfc2606
/about/
/about/presentations/
/about/performance/
/reports/
/domains/
/domains/root/
/domains/int/
/domains/arpa/
/domains/idn-tables/
/protocols/
/numbers/
/abuse/
http://www.icann.org/
mailto:[email protected]?subject=General%20website%20feedback

Il s’agit d’une modification mineure de la précédente, qui permet d’obtenir une sortie utilisable pour un rapport. Je ne retourne que les premier et dernier éléments de la liste des hrefs:

#!/usr/bin/env Ruby

require "nokogiri"
require "open-uri"

doc = Nokogiri::HTML(open('http://nokogiri.org'))
hrefs = doc.search('a[href]').map{ |n| n['href'] }

puts hrefs
  .each_with_index                     # add an array index
  .minmax{ |a,b| a.last <=> b.last }   # find the first and last element
  .map{ |h,i| '%3d %s' % [1 + i, h ] } # format the output

  1 http://github.com/tenderlove/nokogiri
100 http://yokolet.blogspot.com
1
the Tin Man

A l’aide de phantomjs, enregistrez ce fichier sous le nom extract-links.js:

var page = new WebPage(),
    url = 'http://www.udacity.com';

page.open(url, function (status) {
    if (status !== 'success') {
        console.log('Unable to access network');
    } else {
        var results = page.evaluate(function() {
            var list = document.querySelectorAll('a'), links = [], i;
            for (i = 0; i < list.length; i++) {
                links.Push(list[i].href);
            }
            return links;
        });
        console.log(results.join('\n'));
    }
    phantom.exit();
});

courir:

$ ../path/to/bin/phantomjs extract-links.js
0
jGc

Langue: JavaScript/Node.js

Bibliothèque: Demande et Cheerio

var request = require('request');
var cheerio = require('cheerio');

var url = "https://news.ycombinator.com/";
request(url, function (error, response, html) {
    if (!error && response.statusCode == 200) {
        var $ = cheerio.load(html);
        var anchorTags = $('a');

        anchorTags.each(function(i,element){
            console.log(element["attribs"]["href"]);
        });
    }
});

Request Library télécharge le document HTML et Cheerio vous permet d’utiliser les sélecteurs jquery css pour cibler le document HTML.

0
GabaGabaDev

Langue: PHP Bibliothèque: DOM

<?php
$doc = new DOMDocument();
$doc->strictErrorChecking = false;
$doc->loadHTMLFile('http://stackoverflow.com/questions/773340');
$xpath = new DOMXpath($doc);

$links = $xpath->query('//a[@href]');
for ($i = 0; $i < $links->length; $i++)
    echo $links->item($i)->getAttribute('href'), "\n";

Il est parfois utile de mettre le symbole @ avant le $doc->loadHTMLFile pour supprimer les avertissements d'analyse HTML non valides 

0
Entea

Langue: Coldfusion 9.0.1+

Bibliothèque: jSoup

<cfscript>
function parseURL(required string url){
var res = [];
var javaLoader = createObject("javaloader.JavaLoader").init([expandPath("./jsoup-1.7.3.jar")]);
var jSoupClass = javaLoader.create("org.jsoup.Jsoup");
//var dom = jSoupClass.parse(html); // if you already have some html to parse.
var dom = jSoupClass.connect( arguments.url ).get();
var links = dom.select("a");
for(var a=1;a LT arrayLen(links);a++){
    var s={};s.href= links[a].attr('href'); s.text= links[a].text(); 
    if(s.href contains "http://" || s.href contains "https://") arrayAppend(res,s); 
}
return res; 
}   

//writeoutput(writedump(parseURL(url)));
</cfscript>
<cfdump var="#parseURL("http://stackoverflow.com/questions/773340/can-you-provide-examples-of-parsing-html")#">

Retourne un tableau de structures, chaque structure contient des objets HREF et TEXT.

0
chewymole