Compare commits
10 Commits
e523a11069
...
dcea9e83b5
Author | SHA1 | Date | |
---|---|---|---|
dcea9e83b5 | |||
316beb2054 | |||
8265b76acf | |||
cc43fc0fcc | |||
eea2d8ae2f | |||
2e78736b63 | |||
deaee1656b | |||
0dce6d7606 | |||
d310fea974 | |||
936217f526 |
@ -1,5 +1,8 @@
|
|||||||
package es.imunnic.inversionitasBot;
|
package es.imunnic.inversionitasBot;
|
||||||
|
|
||||||
|
import es.imunnic.inversionitasBot.services.GoogleNewsScraperService;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
@ -8,9 +11,12 @@ import org.telegram.telegrambots.meta.TelegramBotsApi;
|
|||||||
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
|
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
|
||||||
import org.telegram.telegrambots.updatesreceivers.DefaultBotSession;
|
import org.telegram.telegrambots.updatesreceivers.DefaultBotSession;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableScheduling
|
@EnableScheduling
|
||||||
public class InversionitasBotApplication {
|
public class InversionitasBotApplication {
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(GoogleNewsScraperService.class);
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
ApplicationContext context = SpringApplication.run(InversionitasBotApplication.class, args);
|
ApplicationContext context = SpringApplication.run(InversionitasBotApplication.class, args);
|
||||||
@ -28,4 +34,5 @@ public class InversionitasBotApplication {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,10 @@ public class NewsArticle {
|
|||||||
private String url;
|
private String url;
|
||||||
private String content;
|
private String content;
|
||||||
|
|
||||||
|
public NewsArticle(String title, String description, String url) {
|
||||||
|
this(title,description,url,null);
|
||||||
|
}
|
||||||
|
|
||||||
public NewsArticle(String title, String description, String url, String content) {
|
public NewsArticle(String title, String description, String url, String content) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
|
@ -2,8 +2,10 @@ package es.imunnic.inversionitasBot;
|
|||||||
|
|
||||||
import es.imunnic.inversionitasBot.services.ApiService;
|
import es.imunnic.inversionitasBot.services.ApiService;
|
||||||
import es.imunnic.inversionitasBot.services.GoogleNewsScraperService;
|
import es.imunnic.inversionitasBot.services.GoogleNewsScraperService;
|
||||||
import org.json.JSONObject;
|
import es.imunnic.inversionitasBot.services.ResultadosService;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import es.imunnic.inversionitasBot.services.Trends24Scrapper;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
|
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
|
||||||
@ -11,6 +13,7 @@ import org.telegram.telegrambots.meta.api.objects.Update;
|
|||||||
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
|
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
|
||||||
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
|
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -21,12 +24,15 @@ import java.util.Map;
|
|||||||
@Component
|
@Component
|
||||||
public class TelegramBot extends TelegramLongPollingBot {
|
public class TelegramBot extends TelegramLongPollingBot {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(GoogleNewsScraperService.class);
|
||||||
private GoogleNewsScraperService scrapper = new GoogleNewsScraperService();
|
private GoogleNewsScraperService scrapper = new GoogleNewsScraperService();
|
||||||
|
private Trends24Scrapper trendScrapper = new Trends24Scrapper();
|
||||||
|
private ResultadosService resultadosService = new ResultadosService();
|
||||||
//@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}")
|
||||||
private String BOT_TOKEN = "7626026035:AAHEMp_iIN3y8AwywL0R6OTQvNi7EcJZ0iY";
|
private String BOT_TOKEN = "7626026035:AAHEMp_iIN3y8AwywL0R6OTQvNi7EcJZ0iY";
|
||||||
|
//private String BOT_TOKEN = "8017576757:AAHNGvY8RK_PbnlV1frM8KZMQ45tdMSvO3c";
|
||||||
protected String CHAT_ID = "-1002289752202";
|
protected String CHAT_ID = "-1002289752202";
|
||||||
protected Integer THREAD_INDICES = 138;
|
protected Integer THREAD_INDICES = 138;
|
||||||
protected Integer THREAD_NOTICIAS = 137;
|
protected Integer THREAD_NOTICIAS = 137;
|
||||||
@ -53,6 +59,12 @@ public class TelegramBot extends TelegramLongPollingBot {
|
|||||||
} else if (messageText.toLowerCase().startsWith("/busca ")) {
|
} else if (messageText.toLowerCase().startsWith("/busca ")) {
|
||||||
String query = messageText.substring(7).trim();
|
String query = messageText.substring(7).trim();
|
||||||
buscarNoticiasYEnviar(chatId, query);
|
buscarNoticiasYEnviar(chatId, query);
|
||||||
|
} else if (messageText.toLowerCase().startsWith("/resultados ")) {
|
||||||
|
String query = messageText.substring(12).trim();
|
||||||
|
buscarResultadosYEnviar(chatId, query);
|
||||||
|
} else if (messageText.toLowerCase().startsWith("/trends ")) {
|
||||||
|
String country = messageText.substring(8).trim().toLowerCase().replace(" ", "-");
|
||||||
|
enviarTrends(chatId, country); // NUEVO
|
||||||
} 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.");
|
||||||
}
|
}
|
||||||
@ -85,6 +97,30 @@ public class TelegramBot extends TelegramLongPollingBot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void sendMessageHtml(String chatId, String text){
|
||||||
|
this.sendMessageHtml(chatId, text, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void sendMessageHtml(String chatId, String text, Integer threadId) {
|
||||||
|
String parte = this.escapeHtml(text);
|
||||||
|
SendMessage sendMessage = new SendMessage();
|
||||||
|
sendMessage.setChatId(chatId);
|
||||||
|
sendMessage.setText(parte);
|
||||||
|
sendMessage.setParseMode("HTML"); // Se debe usar HTML si el contenido es HTML
|
||||||
|
|
||||||
|
|
||||||
|
if (threadId != null) {
|
||||||
|
sendMessage.setMessageThreadId(threadId);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
execute(sendMessage);
|
||||||
|
} catch (TelegramApiException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Scheduled(cron = "0 0 13,20 * * ?", zone = "Europe/Paris")
|
@Scheduled(cron = "0 0 13,20 * * ?", zone = "Europe/Paris")
|
||||||
private void mensajeProgramado(){
|
private void mensajeProgramado(){
|
||||||
this.construirResumenNoticias(this.CHAT_ID);
|
this.construirResumenNoticias(this.CHAT_ID);
|
||||||
@ -154,24 +190,50 @@ public class TelegramBot extends TelegramLongPollingBot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void buscarNoticiasYEnviar(String chatId, String query) {
|
private void buscarNoticiasYEnviar(String chatId, String query) {
|
||||||
List<NewsArticle> noticias = scrapper.searchNews(query);
|
String mensajeInicio = "Analizando noticias... esto puede tardar un poco, ten paciencia...";
|
||||||
|
String mensajeError = "Lo siento... se me ha licuado el cerebro... Mira los logs para saber más.";
|
||||||
|
sendMessageHtml(chatId, mensajeInicio); // Enviar mensaje inicial
|
||||||
|
|
||||||
if (noticias.isEmpty()) {
|
try {
|
||||||
sendMessage(chatId, "No encontré noticias sobre: *" + escapeMarkdown(query) + "*");
|
List<NewsArticle> noticias = scrapper.searchNews(query);
|
||||||
|
|
||||||
|
if (noticias.isEmpty()) {
|
||||||
|
sendMessageHtml(chatId, "No encontré noticias sobre: " + query);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder mensaje = new StringBuilder("<b>📰 Noticias sobre " + query + ":</b>\n\n");
|
||||||
|
|
||||||
|
for (NewsArticle noticia : noticias) {
|
||||||
|
mensaje.append("🔹 <a href=\"")
|
||||||
|
.append(noticia.getUrl()) // URL de la noticia
|
||||||
|
.append("\">")
|
||||||
|
.append(escapeHtml(noticia.getTitle())) // Título de la noticia
|
||||||
|
.append("</a>\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessageHtml(chatId, mensaje.toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
sendMessageHtml(chatId, mensajeError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buscarResultadosYEnviar(String chatId, String query){
|
||||||
|
Map<String, String> resultados = resultadosService.getBeneficioNetoAnual(query);
|
||||||
|
|
||||||
|
if (resultados.isEmpty()) {
|
||||||
|
sendMessageHtml(chatId, "<b>No se encontraron resultados financieros para:</b> " + query);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessage(chatId, "Analizando noticias...esto puede tardar un poco, ten paciencia...");
|
|
||||||
StringBuilder mensaje = new StringBuilder("📰 *Noticias sobre " + escapeMarkdown(query) + "*:\n\n");
|
|
||||||
for (NewsArticle noticia : noticias) {
|
|
||||||
mensaje.append("🔹 [")
|
|
||||||
.append(escapeMarkdown(noticia.getTitle()))
|
|
||||||
.append("](")
|
|
||||||
.append(noticia.getUrl())
|
|
||||||
.append(")\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
sendMessage(chatId, mensaje.toString());
|
StringBuilder resultMessage = new StringBuilder();
|
||||||
|
resultMessage.append("<b>Beneficio neto anual para: ").append(query).append("</b>\n\n");
|
||||||
|
|
||||||
|
resultados.forEach((año, beneficio) -> {
|
||||||
|
resultMessage.append("📅 <b>").append(año).append(":</b> ").append(beneficio).append("\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
sendMessageHtml(chatId, resultMessage.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Método para escapar caracteres especiales en Markdown
|
// Método para escapar caracteres especiales en Markdown
|
||||||
@ -179,23 +241,35 @@ public class TelegramBot extends TelegramLongPollingBot {
|
|||||||
if (text == null) {
|
if (text == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return text.replace("_", "\\_")
|
return text.replaceAll("([_*\\[\\]()~`>#+\\-=|{}.!])", "\\\\$1");
|
||||||
.replace("*", "\\*")
|
|
||||||
.replace("[", "\\[")
|
|
||||||
.replace("]", "\\]")
|
|
||||||
.replace("(", "\\(")
|
|
||||||
.replace(")", "\\)")
|
|
||||||
.replace("~", "\\~")
|
|
||||||
.replace("`", "\\`")
|
|
||||||
.replace(">", "\\>")
|
|
||||||
.replace("#", "\\#")
|
|
||||||
.replace("+", "\\+")
|
|
||||||
.replace("-", "\\-")
|
|
||||||
.replace("=", "\\=")
|
|
||||||
.replace("|", "\\|")
|
|
||||||
.replace("{", "\\{")
|
|
||||||
.replace("}", "\\}")
|
|
||||||
.replace(".", "\\.")
|
|
||||||
.replace("!", "\\!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String escapeHtml(String text) {
|
||||||
|
return text.replace("&", "&");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void enviarTrends(String chatId, String country) {
|
||||||
|
try {
|
||||||
|
List<String> trends = trendScrapper.getTopTrends(country);
|
||||||
|
|
||||||
|
if (trends.isEmpty()) {
|
||||||
|
sendMessage(chatId, "No se encontraron tendencias para: " + country);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder mensaje = new StringBuilder();
|
||||||
|
mensaje.append("📈 <b>Top 20 tendencias en ").append(country.replace("-", " ")).append(":</b>\n\n");
|
||||||
|
|
||||||
|
int index = 1;
|
||||||
|
for (String trend : trends) {
|
||||||
|
mensaje.append(index++).append(". ").append(escapeHtml(trend)).append("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessageHtml(chatId, mensaje.toString());
|
||||||
|
} catch (IOException e) {
|
||||||
|
sendMessage(chatId, "❌ Error al obtener las tendencias de Trends24, compruebe el nombre del pais");
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,39 +9,72 @@ import com.rometools.rome.feed.synd.SyndEntry;
|
|||||||
import com.rometools.rome.feed.synd.SyndFeed;
|
import com.rometools.rome.feed.synd.SyndFeed;
|
||||||
import com.rometools.rome.io.SyndFeedInput;
|
import com.rometools.rome.io.SyndFeedInput;
|
||||||
import com.rometools.rome.io.XmlReader;
|
import com.rometools.rome.io.XmlReader;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import java.net.HttpURLConnection;
|
import java.net.HttpURLConnection;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.ZoneId;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class GoogleNewsScraperService {
|
public class GoogleNewsScraperService {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(GoogleNewsScraperService.class);
|
||||||
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";
|
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) {
|
public List<NewsArticle> searchNews(String query) {
|
||||||
List<NewsArticle> newsList = new ArrayList<>();
|
List<NewsArticle> newsList = new ArrayList<>();
|
||||||
String rssUrl = "https://news.google.com/rss/search?q=" + query.replace(" ", "+") + "&hl=es&gl=ES&ceid=ES%3Aes";
|
String rssUrl = "https://news.google.com/rss/search?q=" + query.replace(" ", "+") + "&hl=es&gl=ES&ceid=ES%3Aes";
|
||||||
|
|
||||||
|
logger.info("Buscando noticias para: {}", query);
|
||||||
|
logger.info("URL del RSS: {}", rssUrl);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
URL url = new URL(rssUrl);
|
URL url = new URL(rssUrl);
|
||||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||||
conn.setRequestProperty("User-Agent", USER_AGENT);
|
conn.setRequestProperty("User-Agent", USER_AGENT);
|
||||||
|
|
||||||
SyndFeedInput input = new SyndFeedInput();
|
SyndFeedInput input = new SyndFeedInput();
|
||||||
SyndFeed feed = input.build(new XmlReader(conn.getInputStream()));
|
SyndFeed feed = input.build(new XmlReader(conn.getInputStream()));
|
||||||
|
|
||||||
for (SyndEntry entry : feed.getEntries()) {
|
List<SyndEntry> entries = feed.getEntries();
|
||||||
|
|
||||||
|
// Calcular la fecha límite (hace 8 meses)
|
||||||
|
LocalDate currentDate = LocalDate.now();
|
||||||
|
LocalDate thresholdDate = currentDate.minusMonths(8);
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (SyndEntry entry : entries) {
|
||||||
|
if (count >= 10) break;
|
||||||
|
|
||||||
|
Date pubDate = entry.getPublishedDate();
|
||||||
|
if (pubDate == null) continue;
|
||||||
|
|
||||||
|
LocalDate entryDate = pubDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
|
||||||
|
if (entryDate.isBefore(thresholdDate)) {
|
||||||
|
logger.info("Noticia descartada por antigüedad: {}", entry.getTitle());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
String title = entry.getTitle();
|
String title = entry.getTitle();
|
||||||
String link = entry.getLink();
|
String link = entry.getLink();
|
||||||
String description = (entry.getDescription() != null) ? entry.getDescription().getValue() : "Sin descripción";
|
String description = (entry.getDescription() != null) ? entry.getDescription().getValue() : "Sin descripción";
|
||||||
String finalUrl = resolveFinalUrl(link);
|
String finalUrl = resolveFinalUrl(link);
|
||||||
String content = extractArticleContent(finalUrl);
|
|
||||||
|
|
||||||
newsList.add(new NewsArticle(title, description, finalUrl, content));
|
logger.info("Noticia {}: {}", (count + 1), title);
|
||||||
|
logger.info("Enlace: {}", finalUrl);
|
||||||
|
|
||||||
|
newsList.add(new NewsArticle(title, description, finalUrl));
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info("Total de noticias procesadas: {}", newsList.size());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
logger.error("Error al obtener las noticias", e);
|
||||||
}
|
}
|
||||||
return newsList;
|
return newsList;
|
||||||
}
|
}
|
||||||
@ -52,23 +85,13 @@ public class GoogleNewsScraperService {
|
|||||||
conn.setInstanceFollowRedirects(true);
|
conn.setInstanceFollowRedirects(true);
|
||||||
conn.setRequestProperty("User-Agent", USER_AGENT);
|
conn.setRequestProperty("User-Agent", USER_AGENT);
|
||||||
conn.connect();
|
conn.connect();
|
||||||
return (conn.getHeaderField("Location") != null) ? conn.getHeaderField("Location") : url;
|
String resolvedUrl = (conn.getHeaderField("Location") != null) ? conn.getHeaderField("Location") : url;
|
||||||
} catch (Exception e) {
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String extractArticleContent(String url) {
|
logger.debug("Redirección resuelta: {} → {}", url, resolvedUrl);
|
||||||
try {
|
return resolvedUrl;
|
||||||
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) {
|
} catch (Exception e) {
|
||||||
return "Error al extraer contenido";
|
logger.warn("No se pudo resolver la URL: {}", url, e);
|
||||||
|
return url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,69 @@
|
|||||||
|
package es.imunnic.inversionitasBot.services;
|
||||||
|
|
||||||
|
import org.jsoup.Jsoup;
|
||||||
|
import org.jsoup.nodes.Document;
|
||||||
|
import org.jsoup.nodes.Element;
|
||||||
|
import org.jsoup.select.Elements;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ResultadosService {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(ResultadosService.class);
|
||||||
|
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";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Realiza el scrap de los beneficios netos anuales de la empresa dada.
|
||||||
|
*
|
||||||
|
* @param companyName nombre de la empresa en la URL
|
||||||
|
* @return Mapa con años como clave y beneficio neto como valor
|
||||||
|
*/
|
||||||
|
public Map<String, String> getBeneficioNetoAnual(String companyName) {
|
||||||
|
Map<String, String> resultados = new LinkedHashMap<>();
|
||||||
|
String url = "https://es.investing.com/equities/" + companyName + "-financial-summary"; // Cambia esta URL a la real
|
||||||
|
|
||||||
|
logger.info("Scrapeando resultados financieros de: {}", companyName);
|
||||||
|
logger.info("URL objetivo: {}", url);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Document doc = Jsoup.connect(url)
|
||||||
|
.userAgent(USER_AGENT)
|
||||||
|
.header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")
|
||||||
|
.header("Accept-Language", "es-ES,es;q=0.9")
|
||||||
|
.header("Referer", "https://www.google.com/")
|
||||||
|
.proxy("51.44.176.151", 20202)
|
||||||
|
.timeout(10000)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
// Buscar la fila con el texto "Beneficio neto"
|
||||||
|
Elements filas = doc.select("tr");
|
||||||
|
for (Element fila : filas) {
|
||||||
|
Element primeraColumna = fila.selectFirst("td");
|
||||||
|
if (primeraColumna != null && primeraColumna.text().equalsIgnoreCase("Beneficio neto")) {
|
||||||
|
Elements celdas = fila.select("td");
|
||||||
|
for (int i = 2; i < celdas.size(); i++) { // Saltar los primeros <td> con el título
|
||||||
|
String texto = celdas.get(i).text().trim();
|
||||||
|
String año = String.valueOf(2020 + (i - 2)); // Ajusta esto si hay más o menos columnas
|
||||||
|
if (!texto.equals("-") && !texto.isEmpty()) {
|
||||||
|
resultados.put(año, texto);
|
||||||
|
logger.info("Año {} → Beneficio neto: {}", año, texto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("Error durante el scraping de resultados de {}", companyName, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Beneficios netos encontrados: {}", resultados.size());
|
||||||
|
return resultados;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
package es.imunnic.inversionitasBot.services;
|
||||||
|
|
||||||
|
import org.jsoup.Jsoup;
|
||||||
|
import org.jsoup.nodes.Document;
|
||||||
|
import org.jsoup.nodes.Element;
|
||||||
|
import org.jsoup.select.Elements;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Trends24Scrapper {
|
||||||
|
|
||||||
|
private static final String BASE_URL = "https://trends24.in/";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtiene los 20 primeros trending topics de Trends24 para el país especificado.
|
||||||
|
* @param country El país en inglés, tal como aparece en la URL (ejemplo: "united-states").
|
||||||
|
* @return Lista de trending topics (Strings).
|
||||||
|
* @throws IOException Si falla la conexión o parsing.
|
||||||
|
*/
|
||||||
|
public List<String> getTopTrends(String country) throws IOException {
|
||||||
|
String url = BASE_URL + country + "/";
|
||||||
|
Document doc = Jsoup.connect(url).get();
|
||||||
|
|
||||||
|
List<String> trends = new ArrayList<>();
|
||||||
|
|
||||||
|
Element trendList = doc.selectFirst("section#timeline ol.trend-card__list");
|
||||||
|
if (trendList != null) {
|
||||||
|
Elements trendElements = trendList.select("li .trend-name a");
|
||||||
|
for (int i = 0; i < Math.min(20, trendElements.size()); i++) {
|
||||||
|
Element trend = trendElements.get(i);
|
||||||
|
trends.add(trend.text());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("❌ No se encontró la lista de tendencias.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return trends;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Reference in New Issue
Block a user