2009-12-29 5 views
0

J'essaie d'utiliser Hpricot pour obtenir la valeur dans une plage avec un nom de classe que je ne connais pas. Je sais qu'il suit le modèle "foo_ [plusieurs chiffres] _bar".Recherche Hpricot avec Regex

À l'heure actuelle, j'obtiens l'ensemble de l'élément contenant sous la forme d'une chaîne et en utilisant une regex pour analyser la chaîne pour l'étiquette. Cette solution fonctionne, mais elle semble vraiment moche.

doc = Hpricot(open("http://scrape.example.com/search?q=#{ticker_symbol}")) 
elements = doc.search("//span[@class='pr']").inner_html 
string = "" 
elements.each do |attr| 
    if(attr =~ /foo_\d+_bar/) 
    string = attr 
    end 
end 
# get rid of the span tags, just get the value 
string.sub!(/<\/span>/, "") 
string.sub!(/<span.+>/, "") 

return string 

Il semble qu'il devrait y avoir une meilleure façon de procéder. Je voudrais faire quelque chose comme:

elements = doc.search("//span[@class='" + /foo_\d+_bar/ + "']").inner_html 

Mais cela ne fonctionne pas. Existe-t-il un moyen de rechercher avec une expression régulière?

Répondre

2

Cela devrait faire:

doc.search("span[@class^='foo'][@class$='bar']") 
+0

Cela ressemble à ce que je veux. Je vais essayer et voir comment ça se passe. – AaronM

+0

A travaillé parfaitement! C'est exactement ce que je voulais. – AaronM

0

On pourrait modifier le html entrant avant l'analyse.

html = open("http://scrape.example.com/search?q=#{ticker_symbol}").string 
html.gsub!(/class="(foo_\d+_bar)"/){ |s| "class=\"foo_bar #{$1}\"" } 
doc = Hpricot(html) 

Après cela, vous pouvez identifier les éléments en utilisant la classe foo_bar. Ceci est loin d'être élégant ou général mais pourrait s'avérer plus efficace.

+0

Merci pour la suggestion. Cela aurait fonctionné, sauf qu'il renvoie une chaîne. Je préfère récupérer un objet Element hpricot. – AaronM

3

Cela devrait faire:

doc.search("span[@class^='foo'][@class$='bar']") 

En plus de cela, nous pouvons donner quelques exemples sur la façon dont d'autres expressions similaires fonctionnent:

Pour une document comme le suivant:

Nous obtenons l'outp Ce qui suit pour chaque requête:

doc.search("//meta[@content='abcxy def ghi jklmn']") 
=> #<Hpricot::Elements[{emptyelem <meta content="abcxy def ghi jklmn">}]> 

C'est ce que nous attendrions.

doc.search("//meta[@content='def']") 
=> #<Hpricot::Elements[]> 

Comme vous le voyez = recherche la correspondance exacte.

doc.search("//meta[@content~='def']") 
=> #<Hpricot::Elements[{emptyelem <meta content="abcxy def ghi jklmn">}]> 

Avec ~ nous pouvons faire une correspondance de sous-chaîne; mais pas vraiment ce que vous attendez.

Par exemple, voir ce qui suit.

doc.search("//meta[@content~=' def ']") 
=> #<Hpricot::Elements[]> 

Il semble que les espaces sont traités spécialement.

Avec l'étoile, nous pouvons contourner ce problème. Nous effectuons maintenant une véritable correspondance de sous-chaîne.

doc.search("//meta[@content*=' def ']") 
=> #<Hpricot::Elements[{emptyelem <meta content="abcxy def ghi jklmn">}]> 

Nous pouvons également faire la chaîne commence et la correspondance de fin de chaîne comme suit:

doc.search("//meta[@content^='def']") 
=> #<Hpricot::Elements[]> 

doc.search("//meta[@content^='ab']") 
=> #<Hpricot::Elements[{emptyelem <meta content="abcxy def ghi jklmn">}]> 

doc.search("//meta[@content$='mn']") 
=> #<Hpricot::Elements[{emptyelem <meta content="abcxy def ghi jklmn">}]> 

Notez que pour ces caractères d'espace ne sont pas un problème.

doc.search("//meta[@content$=' jklmn']") 
=> #<Hpricot::Elements[{emptyelem <meta content="abcxy def ghi jklmn">}]>