2009-09-30 7 views
9

Il existe de nombreux exemples de la façon de dépouiller les balises HTML d'un document en utilisant Ruby, Hpricot et Nokogiri, avec des méthodes inner_text qui suppriment tout le HTML pour vous facilement et rapidement. Ce que j'essaie de faire est le contraire, supprimer tout le texte d'un document HTML, en ne laissant que les balises et leurs attributs. Je considérais que le paramètre inner_html du document était bouclé à zéro, mais en fait, il faudrait inverser le processus puisque le premier élément (root) a un inner_html du reste du document, donc idéalement je l'aurais commencer à l'intérieur le plus élément et mettre inner_html à zéro tout en remontant à travers les ancêtres.Bande de texte à partir de document HTML en utilisant Ruby

Est-ce que quelqu'un connaît une petite astuce pour le faire efficacement? Je pensais que peut-être regex pourrait le faire, mais probablement pas aussi efficacement qu'un tokenizer HTML/analyseur pourrait le faire.

+0

Êtes-vous confronté à un mauvais balisage? (entités non échappées, etc.) – Neall

+0

C'est possible - le balisage que je suis en train de traiter vient des utilisateurs finaux, donc je ne peux pas compter dessus. – davidsmalley

Répondre

38

Cela fonctionne aussi:

doc = Nokogiri::HTML(your_html) 
doc.xpath("//text()").remove 
+1

Excellent! Jetez un '.to_s' à la fin pour obtenir une chaîne et vous êtes prêt à partir! –

2

Vous pouvez numériser la chaîne pour créer un tableau de « jetons », et seulement sélectionner ceux qui sont des balises HTML:

>> some_html 
=> "<div>foo bar</div><p>I like <em>this</em> stuff <a href='http://foo.bar'> long time</a></p>" 
>> some_html.scan(/<\/?[^>]+>|[\w\|`[email protected]#\$%^&*\(\)\-_\+=\[\]{}:;'",\.\/?]+|\s+/).select { |t| t =~ /<\/?[^>]+>/ }.join("") 
=> "<div></div><p><em></em><a href='http://foo.bar'></a></p>" 

== == Modifier

Ou mieux encore, juste balayage pour les balises html;)

>> some_html.scan(/<\/?[^>]+>/).join("") 
=> "<div></div><p><em></em><a href='http://foo.bar'></a></p>" 
3

pour saisir tout pas dans une balise, vous pouvez utiliser nokogiri comme ceci:

doc.search('//text()').text 

Bien sûr, cela va attirer des choses comme le contenu de <script> ou <style> balises, de sorte que vous pouvez également supprimer les balises inscrites sur liste noire:

blacklist = ['title', 'script', 'style'] 
nodelist = doc.search('//text()') 
blacklist.each do |tag| 
    nodelist -= doc.search('//' + tag + '/text()') 
end 
nodelist.text 

Vous pouvez également liste blanche si vous avez préféré, mais qui va probablement être plus Vous pouvez également créer une énorme expression XPath et effectuer une recherche. Honnêtement, je ne sais pas quelle est la voie la plus rapide, ou s'il y a même une différence appréciable.

0

Je suis venu avec, mais la solution de @ andre-r est soo beaucoup mieux!

#!/usr/bin/env ruby 

require 'nokogiri' 

def strip_text doc 
    Nokogiri(doc).tap { |doc| 
    doc.traverse do |node| 
     node.content = nil if node.text? 
    end 
    }.to_s 
end 

require 'test/unit' 
require 'yaml' 
class TestHTMLStripping < Test::Unit::TestCase 
    def test_that_all_text_gets_strippped_from_the_document 
    dirty, clean = YAML.load DATA 
    assert_equal clean, strip_text(dirty) 
    end 
end 
__END__ 
--- 
- | 
    <!DOCTYPE html> 
    <html xmlns='http://www.w3.org/1999/xhtml' xml:lang='en' lang='en'> 
    <head> 
     <meta http-equiv='Content-type'  content='text/html; charset=UTF-8' /> 
     <title>Test HTML Document</title> 
     <meta http-equiv='content-language' content='en' /> 
    </head> 
    <body> 
     <h1>Test <abbr title='Hypertext Markup Language'>HTML</abbr> Document</h1> 
     <div class='main'> 
      <p> 
       <strong>Test</strong> <abbr title='Hypertext Markup Language'>HTML</abbr> <em>Document</em> 
      </p> 
     </div> 
    </body> 
    </html> 
- | 
    <!DOCTYPE html> 
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> 
    <head> 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 
    <title></title> 
    <meta http-equiv="content-language" content="en"> 
    </head> 
    <body><h1><abbr title="Hypertext Markup Language"></abbr></h1><div class="main"><p><strong></strong><abbr title="Hypertext Markup Language"></abbr><em></em></p></div></body> 
    </html> 
Questions connexes