2009-04-02 6 views
0

J'ai un document HTML de ce format:Ruby aide régulière d'expression en utilisant correspondance pour extraire des morceaux de doc html

<tr><td colspan="4"><span class="fullName">Bill Gussio</span></td></tr> 
    <tr> 
     <td class="sectionHeader">Contact</td> 
     <td class="sectionHeader">Phone</td> 
     <td class="sectionHeader">Home</td> 
     <td class="sectionHeader">Work</td> 
    </tr> 
    <tr valign="top"> 
     <td class="sectionContent"><span>Screen Name:</span> <span>bhjiggy</span><br><span>Email 1:</span> <span>[email protected]</span></td> 
     <td class="sectionContent"><span>Mobile: </span><span>2404173223</span></td> 
     <td class="sectionContent"><span>NY</span><br><span>New York</span><br><span>78642</span></td> 
     <td class="sectionContent"><span>MD</span><br><span>Owings Mills</span><br><span>21093</span></td> 
    </tr> 

    <tr><td colspan="4"><hr class="contactSeparator"></td></tr> 

    <tr><td colspan="4"><span class="fullName">Eddie Osefo</span></td></tr> 
    <tr> 
     <td class="sectionHeader">Contact</td> 
     <td class="sectionHeader">Phone</td> 
     <td class="sectionHeader">Home</td> 
     <td class="sectionHeader">Work</td> 
    </tr> 
    <tr valign="top"> 
     <td class="sectionContent"><span>Screen Name:</span> <span>eddieOS</span><br><span>Email 1:</span> <span>[email protected]</span></td> 
     <td class="sectionContent"></td> 
     <td class="sectionContent"><span></span></td> 
     <td class="sectionContent"><span></span></td> 
    </tr> 

    <tr><td colspan="4"><hr class="contactSeparator"></td></tr> 

Il alterne - morceau de coordonnées et puis un « séparateur de contact ». Je veux saisir les informations de contact de sorte que mon premier obstacle est de saisir les morceaux entre le séparateur de contact. J'ai déjà compris l'expression régulière en utilisant des rubriques. C'est:

/<tr><td colspan="4"><span class="fullName">((.|\s)*?)<hr class="contactSeparator">/ 

Vous pouvez vérifier sur les rubriques pour vérifier que cela isole les morceaux.

Cependant, mon gros problème est que j'ai des problèmes avec le code ruby. J'utilise la fonction de correspondance intégrée et fais des tirages, mais n'obtiens pas les résultats que j'attends. Voici le code:

page = agent.get uri.to_s  
chunks = page.body.match(/<tr><td colspan="4"><span class="fullName">((.|\s)*?)<hr class="contactSeparator">/).captures 

chunks.each do |chunk| 
    puts "new chunk: " + chunk.inspect 
end 

Notez que page.body est que le corps du document html attrapée par Mechanize. Le document html est beaucoup plus grand mais a ce format. Ainsi, la sortie inattendue est ci-dessous:

new chunk: "Bill Gussio</span></td></tr>\r\n\t<tr>\r\n\t\t<td class=\"sectionHeader\">Contact</td>\r\n\t\t<td class=\"sectionHeader\">Phone</td>\r\n\t\t<td class=\"sectionHeader\">Home</td>\r\n\t\t<td class=\"sectionHeader\">Work</td>\r\n\t</tr>\r\n\t<tr valign=\"top\">\r\n\t\t<td class=\"sectionContent\"><span>Screen Name:</span> <span>bhjiggy</span><br><span>Email 1:</span> <span>[email protected]</span></td>\r\n\t\t<td class=\"sectionContent\"><span>Mobile: </span><span>2404173223</span></td>\r\n\t\t<td class=\"sectionContent\"><span>NY</span><br><span>New York</span><br><span>78642</span></td>\r\n\t\t<td class=\"sectionContent\"><span>MD</span><br><span>Owings Mills</span><br><span>21093</span></td>\r\n\t</tr>\r\n\t\r\n\t<tr><td colspan=\"4\">" 
new chunk: ">" 

Il y a 2 surprises ici pour moi:

1) Il n'y a pas 2 matchs qui contiennent les morceaux de coordonnées, même si sur Rubular j'ai vérifié que ces morceaux devraient être extraits.

2) Tous les \ r \ n \ t (sauts de ligne, onglets, etc.) apparaissent dans les correspondances.

Quelqu'un peut-il voir le problème ici? Alternativement, si quelqu'un connaît un bon importateur de contacts AOL libre, ce serait génial. J'utilise blackbook mais ça continue à échouer pour moi sur AOL et j'essaye de le réparer. Malheureusement, AOL n'a pas encore d'API de contacts.

Merci!

Répondre

0

Ceci est le code qui analyse HTML.Ne hésitez pas à suggérer quelque chose de mieux:

contacts = [] 
    email, mobile = "","" 

    names = page.search("//span[@class='fullName']") 

    # Every contact has a fullName node, so for each fullName node, we grab the chunk of contact info 
    names.each do |n| 

     # next_sibling.next_sibling skips: 
     # <tr> 
     # <td class=\"sectionHeader\">Contact</td> 
     # <td class=\"sectionHeader\">Phone</td> 
     # <td class=\"sectionHeader\">Home</td> 
     # <td class=\"sectionHeader\">Work</td> 
     # </tr> 
     # to give us the actual chunk of contact information 
     # then taking the children of that chunk gives us rows of contact info 
     contact_info_rows = n.parent.parent.next_sibling.next_sibling.children 

     # Iterate through the rows of contact info 
     contact_info_rows.each do |row| 

     # Iterate through the contact info in each row 
     row.children.each do |info| 
      # Get Email. There are two ".next_siblings" because space after "Email 1" element is processed as a sibling 
      if info.content.strip == "Email 1:" then email = info.next_sibling.next_sibling.content.strip end 

      # If the contact info has a screen name but no email, use [email protected] 
      if (info.content.strip == "Screen Name:" && email == "") then email = info.next_sibling.next_sibling.content.strip + "@aol.com" end 

      # Get Mobile #'s 
      if info.content.strip == "Mobile:" then mobile = info.next_sibling.content.strip end 

      # Maybe we can try and get zips later. Right now the zip field can look like the street address field 
      # so we can not tell the difference. There is no label node 
      #zip_match = /\A\D*(\d{5})-?\d{4}\D*\z/i.match(info.content.strip) 
      #zip_match = /\A\D*(\d{5})[^\d-]*\z/i.match(info.content.strip)  
     end 

     end 

     contacts << { :name => n.content, :email => email, :mobile => mobile } 

     # clear variables 
     email, mobile = "", "" 
    end 
3

Si vous extrayez simplement des informations de XML, il peut être plus facile d'utiliser autre chose que des expressions régulières. XPath est un bon outil pour extraire des informations de XML. Je crois qu'il ya des bibliothèques disponibles pour Ruby qui prennent en charge XPath, peut-être essayer REXML:

+0

Plus précisément, je suis en train d'extraire du HTML. J'ai triché avec XPATH, mais à cause des données exactes que j'essaie de retirer, il semble vraiment très difficile d'obtenir ce que je veux. Il semble que XPATH est bon pour obtenir toutes les données entre 2 nœuds, ce n'est pas ce que je veux. En outre, docs XPATH pour ruby ​​est mauvais! – Tony

3

Utilisez un analyseur HTML tel que hpricot vous permettra d'économiser beaucoup de maux de tête :)

sudo gem install hpricot

Il est principalement écrit en C , donc c'est rapide aussi

Voici comment l'utiliser:

http://wiki.github.com/why/hpricot/hpricot-basics

+0

a fini par utiliser nokogiri – Tony

+0

Yup, il y a aussi nokogiri ... C'est un nouveau concurrent du domaine de l'analyseur –

Questions connexes