Bueno, varias horas después y sin respuesta de Lunar Pages, me decidí a reescribir el programa usando Java. Lo primero que intenté fue tratar de procesar la página de noticias de Globovision.com, pero quienes hicieron el código del sitio Web simplemente no saben de programación HTML, y el daño es demasiado para el ya sensible JTidy:
line 15 column 1 - Warning: unexpected </head> in <link>line 20 column 165 - Warning: unexpected </a> in <img>line 20 column 169 - Warning: unexpected </td> in <img>line 23 column 97 - Warning: unexpected </td> in <img>line 24 column 5 - Warning: unexpected </tr> in <img>line 26 column 93 - Warning: unexpected </a> in <img>line 26 column 97 - Warning: unexpected </td> in <img>This document has errors that must be fixed beforeusing HTML Tidy to generate a tidied up version.
Asi que, ¿como procesar un documento que está así de roto en Java?
Bueno, el sitio de Java tiene mucha documentación y una de las cosas interesantes que muestran es como usar el parser que tiene Swing pero afuera de sus componentes gráficos. Esto resolvió perfectamente como obtener e iterar un documento roto, ahora sólo quedaba resolver el problema de escribir el RSS lo más fácil posible.
Después de buscar un poco me decidí a usar la librería Rome. No es pesada, lo único fastidioso es que requiere JDOM. Bueno, antes tuve que pedir que instalarn Expat para Perl, asi que mejor no me quejo
El código como siempre está en Source Forge, en el sitio de KodeGeek. Se los pongo aquí por comodidad:
1 package com.kodegeek.blog.rss; 2 3 import java.io.BufferedReader; 4 import java.io.FileWriter; 5 import java.io.InputStreamReader; 6 import java.io.Reader; 7 import java.io.Writer; 8 import java.net.URL; 9 import java.util.ArrayList; 10 import java.util.Date; 11 import java.util.List; 12 import java.util.logging.Level; 13 import java.util.logging.Logger; 14 15 import javax.swing.text.AttributeSet; 16 import javax.swing.text.MutableAttributeSet; 17 import javax.swing.text.html.HTML; 18 import javax.swing.text.html.HTML.Tag; 19 import javax.swing.text.html.HTMLEditorKit.ParserCallback; 20 import javax.swing.text.html.parser.ParserDelegator; 21 22 import com.sun.syndication.feed.synd.SyndEntry; 23 import com.sun.syndication.feed.synd.SyndEntryImpl; 24 import com.sun.syndication.feed.synd.SyndFeed; 25 import com.sun.syndication.feed.synd.SyndFeedImpl; 26 import com.sun.syndication.io.SyndFeedOutput; 27 28 29 /** 30 * Program that converts the main summary news from Globovision.comto RSS format. 31 * @author josevnz at kodeeek.com 32 *
License: GPL
33 * I use a combination of Yahoo Pipes and Google Reader to keep meupdated about news of any kind. However, some websites like 34 * Globovision.com still don't have a proper RSS feed,so one day Idecided to create my own mashup
. 35 * It worked for a while until my Blog hosting providerdecided toremove the XML::RSS Perl module I asked to install for me.Because of that, 36 * this Java version was born. 37 */ 38 public final class GlobovisionHtml2Rss { 39 40 public static final StringGLOBOVISION_URL = "http://globovision.com"; 41 public static final String NEWS_URL =GLOBOVISION_URL + "/history.php?cha=1&pag=1"; 42 43 private static Logger log; 44 private static final long DEFAULT_WAIT = 1000L*60L*5L; 45 46 // Do not alow instances of this class to be created 47 private GlobovisionHtml2Rss() { 48 // Empty 49 } 50 51 static { 52 53 log = Logger.getLogger(GlobovisionHtml2Rss.class.getName()); 54 } 55 56 /** 57 * @param args 58 */ 59 public static void main(String[] args) throws Exception { 60 61 try { 62 fetch(NEWS_URL, args[0]); 63 } catch (Exception exp) { 64 log.log(Level.SEVERE, "Cannot recover from thisexception", exp); 65 } 66 } 67 68 /** 69 * Try to fetch the URL and convert it to a Document 70 * @param url 71 * @param outfile 72 * @return 73 * @throws Exception 74 */ 75 private static void fetch(String url, String outfile) throws Exception { 76 Reader reader = null; 77 Writer writer = null; 78 SyndFeed feed; 79 List <SyndEntry>news = new ArrayList<SyndEntry>(); 80 try { 81 feed = new SyndFeedImpl(); 82 feed.setAuthor("Jose Nunez, josevnz at kodegeek.com"); 83 feed.setDescription("Globovision.com news - Brough toyou by http://KodeGeek.com"); 84 feed.setFeedType("rss_1.0"); 85 feed.setLink("http://www.kodegeek.com/rss/globovision.rss"); 86 feed.setTitle("Globovision.com Venezuelan News"); 87 URL globovisionURL = new URL(url); 88 reader = new BufferedReader(new InputStreamReader(globovisionURL.openStream())); 89 ParserDelegator parser = new ParserDelegator(); 90 parser.parse(reader, new GlobovisionHtml2Rss().new GlobovisionParser(news), false); 91 if (news.size() > 0) { 92 feed.setEntries(news); 93 writer = new FileWriter(outfile); 94 SyndFeedOutput feedOut = new SyndFeedOutput(); 95 feedOut.output(feed, writer); 96 } 97 } catch (Exception exp) { 98 throw new Exception("Unexpected problem", exp); 99 } finally {100101 if (reader != null) {102 reader.close();103 }104105 if (writer != null) {106 writer.close();107 }108 news.clear();109 }110 }111112 /**113 * Helper class used to parse Globovision news website114 * @author josevnz115 */116 class GlobovisionParser extends ParserCallback {117118 private boolean getHeadline = false;119 private AttributeSet attribute;120 private List <SyndEntry>entries;121122 public GlobovisionParser(List <SyndEntry>entries) {123 this.entries = entries;124 }125126 /**127 * Globovision HTML is so broken than we will ignore the errorssilently.128 * Increase the logger verbosity to see the errors129 */130 public void handleError(String errorMsg, int pos) {131 log.log(Level.FINE, String.format("%s, %d", errorMsg, pos));132 }133134 /**135 * Looking for: tag = "a" and attr{href} =~ /news.php?nid=\d+/136 * @param t Tag137 * @param a Attribute set138 * @param pos position139 */140 public void handleStartTag(Tag t, MutableAttributeSet a, int pos) {141 if (142 (t == Tag.A) &&143 (a.getAttribute(HTML.Attribute.HREF) != null)&&144 (a.getAttribute(HTML.Attribute.HREF).toString().matches("news\\.php\\?nid=\\d+"))145 ) {146 attribute = a.copyAttributes();147 log.log(Level.FINE,String.format("Tag: %s, attributes: %s", t, a));148 getHeadline = true;149 }150151 }152153 /**154 * Get the headline and also write the RSS entry155 * @param data Text next to the headline156 * @param pos position157 */158 public void handleText(char[] data, int pos) {159 if (getHeadline) {160 SyndEntry entry = new SyndEntryImpl();161 entry.setLink(String.format("%s/%s",GLOBOVISION_URL, attribute.getAttribute(HTML.Attribute.HREF).toString()));162 entry.setPublishedDate(new Date());163 entry.setTitle(new String(data));164 entries.add(entry);165 getHeadline = false;166 attribute = null;167 }168 }169170171172 }173174 }
Debo admitir que el proceso para volver a crear el RSS de Globovision desde Java fué más complejo y requirió más código que el de Perl (aunque terminé mi nueva versión antes que Lunar Pages reemplazara el modulo perdido, unas cuantas horas después) . Pero por otro lado, aprendí más trucos con este y al menos ya no tengo que preocuparme por pedirles que instalen módulos no estandares.
Nota a los subscriptores del la fuente de Globovision en RSS: La versión vieja ya funciona de nuevo. Pienso montar la nueva dentro de poco con nuevas mejoras. Una de ellas es que este tipo de error no afectará el programa (aunque no doy ningún tipo de garantias por soporte gratis
).
To Lunar Pages: Response to this issue was kind of slow, thanks for fixing the issue on my account anyways.
Buscar en otros sitios:
Blogalaxia:java, perl, XML::RSS, HTMLEditorKit, Lunar Pages
Technorati:java, perl, XML::RSS, HTMLEditorKit, Lunar Pages
To2blogs:java, perl, XML::RSS, HTMLEditorKit, Lunar Pages
Del.icio.us:java, perl, XML::RSS, HTMLEditorKit, Lunar Pages
java
HTMLEditorKit, java, Lunar Pages, perl, XML::RSS
Comentarios recientes