busqueda de noticias
This commit is contained in:
@ -24,6 +24,8 @@ dependencies {
|
|||||||
implementation 'org.springframework.boot:spring-boot-starter-logging'
|
implementation 'org.springframework.boot:spring-boot-starter-logging'
|
||||||
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
|
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
|
||||||
implementation 'org.json:json:20230227'
|
implementation 'org.json:json:20230227'
|
||||||
|
implementation 'org.jsoup:jsoup:1.15.4'
|
||||||
|
implementation 'com.rometools:rome:1.18.0'
|
||||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||||
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package es.imunnic.inversionitasBot;
|
||||||
|
|
||||||
|
public class NewsArticle {
|
||||||
|
private String title;
|
||||||
|
private String description;
|
||||||
|
private String url;
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
public NewsArticle(String title, String description, String url, String content) {
|
||||||
|
this.title = title;
|
||||||
|
this.description = description;
|
||||||
|
this.url = url;
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUrl() {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package es.imunnic.inversionitasBot;
|
package es.imunnic.inversionitasBot;
|
||||||
|
|
||||||
import es.imunnic.inversionitasBot.services.ApiService;
|
import es.imunnic.inversionitasBot.services.ApiService;
|
||||||
|
import es.imunnic.inversionitasBot.services.GoogleNewsScraperService;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
@ -20,6 +21,7 @@ import java.util.Map;
|
|||||||
@Component
|
@Component
|
||||||
public class TelegramBot extends TelegramLongPollingBot {
|
public class TelegramBot extends TelegramLongPollingBot {
|
||||||
|
|
||||||
|
private GoogleNewsScraperService scrapper = new GoogleNewsScraperService();
|
||||||
//@Value("${telegram.bot.username}")
|
//@Value("${telegram.bot.username}")
|
||||||
private String BOT_USERNAME = "Inversionitas_Bot";
|
private String BOT_USERNAME = "Inversionitas_Bot";
|
||||||
//@Value("${telegram.bot.token}")
|
//@Value("${telegram.bot.token}")
|
||||||
@ -48,6 +50,9 @@ public class TelegramBot extends TelegramLongPollingBot {
|
|||||||
|
|
||||||
if (messageText.equalsIgnoreCase("/resumen")) {
|
if (messageText.equalsIgnoreCase("/resumen")) {
|
||||||
construirResumenNoticias(chatId);
|
construirResumenNoticias(chatId);
|
||||||
|
} else if (messageText.toLowerCase().startsWith("/busca ")) {
|
||||||
|
String query = messageText.substring(7).trim();
|
||||||
|
buscarNoticiasYEnviar(chatId, query);
|
||||||
} else {
|
} else {
|
||||||
sendMessage(chatId, "Comando no reconocido. Usa /resumen para obtener el resumen diario.");
|
sendMessage(chatId, "Comando no reconocido. Usa /resumen para obtener el resumen diario.");
|
||||||
}
|
}
|
||||||
@ -147,6 +152,20 @@ public class TelegramBot extends TelegramLongPollingBot {
|
|||||||
|
|
||||||
return partes;
|
return partes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void buscarNoticiasYEnviar(String chatId, String query) {
|
||||||
|
List<NewsArticle> noticias = scrapper.searchNews(query);
|
||||||
|
|
||||||
|
if (noticias.isEmpty()) {
|
||||||
|
sendMessage(chatId, "No encontré noticias sobre: *" + query + "*");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder mensaje = new StringBuilder("📰 *Noticias sobre " + query + "*:\n\n");
|
||||||
|
for (NewsArticle noticia : noticias) {
|
||||||
|
mensaje.append("🔹 [").append(noticia.getTitle()).append("](").append(noticia.getUrl()).append(")\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage(chatId, mensaje.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//TODO ajustar los mensajes para que no se pasen
|
|
||||||
//TODO ajustar la presentación con la negrita
|
|
||||||
|
@ -0,0 +1,75 @@
|
|||||||
|
package es.imunnic.inversionitasBot.services;
|
||||||
|
|
||||||
|
import es.imunnic.inversionitasBot.NewsArticle;
|
||||||
|
import org.jsoup.Jsoup;
|
||||||
|
import org.jsoup.nodes.Document;
|
||||||
|
import org.jsoup.nodes.Element;
|
||||||
|
import org.jsoup.select.Elements;
|
||||||
|
import com.rometools.rome.feed.synd.SyndEntry;
|
||||||
|
import com.rometools.rome.feed.synd.SyndFeed;
|
||||||
|
import com.rometools.rome.io.SyndFeedInput;
|
||||||
|
import com.rometools.rome.io.XmlReader;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class GoogleNewsScraperService {
|
||||||
|
|
||||||
|
private static final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36";
|
||||||
|
|
||||||
|
public List<NewsArticle> searchNews(String query) {
|
||||||
|
List<NewsArticle> newsList = new ArrayList<>();
|
||||||
|
String rssUrl = "https://news.google.com/rss/search?q=" + query.replace(" ", "+") + "&hl=es&gl=ES&ceid=ES%3Aes";
|
||||||
|
|
||||||
|
try {
|
||||||
|
URL url = new URL(rssUrl);
|
||||||
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
|
conn.setRequestProperty("User-Agent", USER_AGENT);
|
||||||
|
SyndFeedInput input = new SyndFeedInput();
|
||||||
|
SyndFeed feed = input.build(new XmlReader(conn.getInputStream()));
|
||||||
|
|
||||||
|
for (SyndEntry entry : feed.getEntries()) {
|
||||||
|
String title = entry.getTitle();
|
||||||
|
String link = entry.getLink();
|
||||||
|
String description = (entry.getDescription() != null) ? entry.getDescription().getValue() : "Sin descripción";
|
||||||
|
String finalUrl = resolveFinalUrl(link);
|
||||||
|
String content = extractArticleContent(finalUrl);
|
||||||
|
|
||||||
|
newsList.add(new NewsArticle(title, description, finalUrl, content));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return newsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveFinalUrl(String url) {
|
||||||
|
try {
|
||||||
|
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
|
||||||
|
conn.setInstanceFollowRedirects(true);
|
||||||
|
conn.setRequestProperty("User-Agent", USER_AGENT);
|
||||||
|
conn.connect();
|
||||||
|
return (conn.getHeaderField("Location") != null) ? conn.getHeaderField("Location") : url;
|
||||||
|
} catch (Exception e) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String extractArticleContent(String url) {
|
||||||
|
try {
|
||||||
|
Document doc = Jsoup.connect(url).userAgent(USER_AGENT).get();
|
||||||
|
Elements paragraphs = doc.select("article p, .post-content p, .entry-content p, .content p, #article-body p");
|
||||||
|
StringBuilder content = new StringBuilder();
|
||||||
|
for (Element p : paragraphs) {
|
||||||
|
content.append(p.text()).append("\n");
|
||||||
|
}
|
||||||
|
return content.length() > 0 ? content.toString() : "No se encontró contenido relevante";
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "Error al extraer contenido";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Reference in New Issue
Block a user