From a3f00de87ecccfb087640ea2b2db47e3f2f536de Mon Sep 17 00:00:00 2001 From: Edward Betts <edward@4angle.com> Date: Fri, 21 Feb 2025 16:52:09 -0500 Subject: [PATCH] Initial commit. --- check.py | 156 +++++++++++++++++++++++++++++++ sample/page.html | 235 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 391 insertions(+) create mode 100755 check.py create mode 100644 sample/page.html diff --git a/check.py b/check.py new file mode 100755 index 0000000..2eba7ea --- /dev/null +++ b/check.py @@ -0,0 +1,156 @@ +#!/usr/bin/python3 + +import configparser +import json +import smtplib +from datetime import date +from email.mime.text import MIMEText +from pathlib import Path + +import lxml.html +import requests + +# Spanish months with corresponding numbers (1-12) +spanish_months = { + "enero": 1, + "febrero": 2, + "marzo": 3, + "abril": 4, + "mayo": 5, + "junio": 6, + "julio": 7, + "agosto": 8, + "septiembre": 9, + "octubre": 10, + "noviembre": 11, + "diciembre": 12, +} + +# Paths +CONFIG_DIR = Path.home() / ".config" / "ferrocarril" +CONFIG_FILE = CONFIG_DIR / "config" +DATA_DIR = Path.home() / "lib" / "data" +DATA_FILE = DATA_DIR / "ferrocarril_dates.json" +URL = "https://ferrocarrilcentral.com.pe/appfcca/" + + +def parse_dates(html_content: str) -> list[date]: + doc = lxml.html.fromstring(html_content) + dates = [] + + for tour in doc.xpath('//div[contains(@class, "tourdate")]'): + try: + day = int(tour.xpath('.//div[contains(@class, "day")]')[0].text.strip()) + yeardate = tour.xpath('.//div[contains(@class, "yeardate")]')[0] + month_str = ( + yeardate.xpath('.//div[contains(@class, "month")]')[0] + .text.strip() + .lower() + ) + year = int( + yeardate.xpath('.//div[contains(@class, "year")]')[0].text.strip() + ) + + month = spanish_months.get(month_str) + if month is None: + raise ValueError(f"Unknown month: {month_str}") + + dates.append(date(year, month, day)) + except (IndexError, ValueError) as e: + print(f"Error parsing date: {e}") + continue + + return dates + + +def load_previous_dates() -> set[str]: + """Load previously seen dates from file, return as set of ISO strings.""" + if DATA_FILE.exists(): + with open(DATA_FILE, "r") as f: + return set(json.load(f)) + return set() + + +def save_dates(dates: list[date]): + """Save current dates to file as ISO strings.""" + DATA_DIR.mkdir(parents=True, exist_ok=True) + with open(DATA_FILE, "w") as f: + json.dump([d.isoformat() for d in dates], f) + + +def load_config() -> configparser.ConfigParser: + """Load email configuration from INI file.""" + if not CONFIG_FILE.exists(): + raise FileNotFoundError( + f"Config file not found at {CONFIG_FILE}. Please create it with SMTP details." + ) + config = configparser.ConfigParser() + config.read(CONFIG_FILE) + if "mail" not in config: + raise ValueError(f"Config file {CONFIG_FILE} must have an [email] section") + return config + + +def send_email(new_dates: list[date], config: configparser.ConfigParser) -> None: + """Send email with new dates.""" + email_config = config["mail"] + subject = "New Ferrocarril Central Dates Available!" + body = "New dates found:\n" + "\n".join(d.strftime("%d %B %Y") for d in new_dates) + + msg = MIMEText(body) + msg["Subject"] = subject + msg["From"] = email_config["from_address"] + msg["To"] = email_config["to_address"] + + try: + with smtplib.SMTP(email_config["smtp_host"]) as server: + server.send_message(msg) + print("Email sent successfully") + except Exception as e: + print(f"Failed to send email: {e}") + + +def main() -> None: + # Ensure directories exist + CONFIG_DIR.mkdir(parents=True, exist_ok=True) + DATA_DIR.mkdir(parents=True, exist_ok=True) + + # Fetch webpage + try: + response = requests.get(URL, timeout=10) + response.raise_for_status() + html_content = response.text + except requests.RequestException as e: + print(f"Failed to fetch webpage: {e}") + return + + # Parse current dates + current_dates = set(parse_dates(html_content)) + if not current_dates: + print("No dates found on webpage") + return + + # Load previous dates + previous_dates = load_previous_dates() + + # Check for new dates + new_dates = [d for d in current_dates if d.isoformat() not in previous_dates] + + if new_dates: + print(f"New dates found: {new_dates}") + try: + config = load_config() + send_email(new_dates, config) + save_dates( + list(current_dates) + ) # Update stored dates only if email succeeds + except FileNotFoundError as e: + print(e) + except Exception as e: + print(f"Error in processing: {e}") + else: + print("No new dates found") + + +if __name__ == "__main__": + main() diff --git a/sample/page.html b/sample/page.html new file mode 100644 index 0000000..3708f31 --- /dev/null +++ b/sample/page.html @@ -0,0 +1,235 @@ +<!DOCTYPE html> +<html lang="es"> + +<head> + <meta charset="UTF-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>FCCA - Viajes disponibles</title> + + <link rel="icon" href="https://ferrocarrilcentral.com.pe/appfcca/assets/img/fav.png" type="image/x-icon"> + <link rel="apple-touch-icon" href="https://ferrocarrilcentral.com.pe/appfcca/assets/img/fav.png"> + + <link rel="stylesheet" href="https://ferrocarrilcentral.com.pe/appfcca/assets/css/style.css"> + + <!-- Icon Font --> + <link rel="stylesheet" href="https://ferrocarrilcentral.com.pe/appfcca/assets/css/linearicons.css"> + + <!-- Carousel --> + <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/glider-js@1.7.3/glider.min.css"> + + <link rel="preconnect" href="https://fonts.googleapis.com"> + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> + <link href="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet"> + +</head> +<body> + +<header> + <nav class="navbar navbar-expand-lg navbar-light bg-white pt-3 pb-3"> + <div class="container"> + <a class="navbar-brand logotipo" href="https://www.ferrocarrilcentral.com.pe/"> + <img src="https://ferrocarrilcentral.com.pe/appfcca/assets/img/logo_fcca.svg" alt="Ferrocarril Central FCCA" width="207" height="60"> + </a> + <div class="navbar-expand nav-fcca" id="navbarNavDropdown"> + <ul class="navbar-nav"> + <li class="nav-item home"><a class="nav-link" href="https://www.ferrocarrilcentral.com.pe/">inicio</a></li> + <li class="nav-item language dropdown"> + <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false"> + <i class="icon-fcca-20"></i> Idioma </a> + <ul class="dropdown-menu dropdown-menu-end" aria-labelledby="navbarDropdownMenuLink"> + <li><a class="dropdown-item" href="/appfcca/index.php?lang=es">Español</a></li> + <li><a class="dropdown-item" href="/appfcca/index.php?lang=en">Ingles</a></li> + </ul> + </li> + </ul> + </div> + </nav> +</header> + <section class="pt-5 pb-5"> + <div class="container"> + + <div class="d-flex justify-content-between mb-5"> + <div class="nav-reserve departure"><a href="https://ferrocarrilcentral.com.pe/appfcca/index.php"><i class="icon-fcca-05"></i> <span>1. Salida</span></a></div> + <div class="nav-reserve seating"><a href="https://ferrocarrilcentral.com.pe/appfcca/seating.php"><i class="icon-fcca-06"></i> <span>2. Asientos</span></a></div> + <div class="nav-reserve passengers"><a href="https://ferrocarrilcentral.com.pe/appfcca/passengers.php"><i class="icon-fcca-07"></i> <span>3. Pasajeros</span></a></div> + <div class="nav-reserve payment"><a href="https://ferrocarrilcentral.com.pe/appfcca/checkout.php"><i class="icon-fcca-08"></i> <span>4. Pago</span></a></div> +</div> + <h3 class="subtitles mb-4">Selecciona tu Viaje:</h3> + + <div class="carousel mb-5"> + <div class="carousel-container"> + <div class="carousel-list"> + <div class="glider-track"> + + <div class="item-glid" data-ccprog="00226" data-rutas="100"> + <div class="tourdate d-flex justify-content-center align-items-center"> + <div class="day p-1">17</div> + <div class="yeardate d-flex flex-column bd-highlight p-1"> + <div class="month">Abril</div> + <div class="year">2025</div> + </div> + </div> + </div> + + </div> + </div> + </div> + + <div class="glide-arrows"> + <button class="glide-left"><i class="icon-fcca-15"></i></button> + <button class="glide-right"><i class="icon-fcca-16"></i></button> + </div> + </div> + + <h3 class="subtitles mb-3">Selecciona tu Ruta:</h3> + + <div id="rutaselect"></div> + + <div class="heading-services d-flex justify-content-center align-items-center mt-2"> + <div class="title-item tservicio d-none d-md-block"> + <h4>Servicio</h4> + </div> + <div class="title-item tpartida"> + <h4>Partida</h4> + </div> + <div class="title-item tretorno"> + <h4>Retorno</h4> + </div> + <div class="title-item ttarifa d-none d-md-block"> + <h4>Tarifas <span>(Inc. IGV)</span></h4> + </div> + <div class="title-item tmensaje d-none d-md-block">El viaje durará<br> aproximadamente 14 horas</div> + </div> + + <!-- <div class='preloader mt-4 mb-4'><img src='./assets/img/prelouder-icon.svg'/></div> --> + <!-- + <div id="devices"> + <input type="hidden" class="mobile" value="//$devices['mobile']['status']"> + <input type="hidden" class="desktop" value="//$devices['desktop']['status']"> + </div> --> + + <div id="dataServices"></div> + + </div> + </section> + +<!-- Crear Preloder --> +<div class="preloader-wrapper"> + <div class="sniper"> + <img src='https://ferrocarrilcentral.com.pe/appfcca/assets/img/prelouder-icon.svg'/> + </div> +</div> +<footer class="footer"> + <div class="footer-top pt-4 pb-4"> + <div class="container"> + <div class="secure-payment d-md-flex justify-content-between align-items-center"> + <div class="guaranteed pt-3 pb-3"> + + </div> + <div class="cards-payment pt-3 pb-3"><img class="img-fluid" src="https://ferrocarrilcentral.com.pe/appfcca/assets/img/cads-checkout.png" alt="Sitio Web Protegido"></div> + </div> + </div> + </div> + <div class="footer-bottom bg-rojo text-white"> + <div class="container pt-5 pb-5"> + <div class="support d-lg-flex align-items-center mt-4"> + <div class="info callcenter d-flex align-items-center pt-3 pb-3"> + <div class="iconinfo"><i class="icon-fcca-02"></i></div> + <div class="textinfo">Soporte en Línea <span>(01)390-5858</span> anexo 222</div> + </div> + <div class="info office d-flex align-items-center pt-3 pb-3"> + <div class="iconinfo"><i class="icon-fcca-03"></i></div> + <div class="textinfo">Av. Circunvalación Golf Los Incas 170,<br> Edificio MORE, Oficina 302,<br> Santiago de Surco - Lima</div> + </div> + <div class="info Contact d-flex align-items-center pt-3 pb-3"> + <div class="iconinfo"><i class="icon-fcca-04"></i></div> + <div class="textinfo">Escríbenos al <span>reservas@fcca.com.pe</span></div> + </div> + </div> + <div class="nav-footer mt-5"> + <ul class="menu-footer d-md-flex align-items-center"> + <li><a href="https://www.ferrocarrilcentral.com.pe/politica-privacidad"><i class="icon-fcca-23"></i> Política De Privacidad</a></li> + <li><a href="https://www.ferrocarrilcentral.com.pe/terminos-y-condiciones"><i class="icon-fcca-23"></i> Terminos Y Condiciones</a></li> + <li><a href="https://www.ferrocarrilcentral.com.pe/preguntas-frecuentes"><i class="icon-fcca-23"></i> Preguntas Frecuentes</a></li> + <li><a href="https://www.ferrocarrilcentral.com.pe/libro-de-reclamos"><i class="icon-fcca-23"></i> Libro De Reclamaciones</a></li> + <li><a href="https://www.ferrocarrilcentral.com.pe/contactenos"><i class="icon-fcca-23"></i> Contáctenos</a></li> + </ul> + </div> + </div> + <div class="copyright pt-3 pb-3"> + <div class="container"> + <div class="credits d-flex align-items-center"> + <div class="copyfcca">copyright © <a href="https://ferrocarrilcentral.com.pe/">www.ferrocarrilcentral.com.pe</a></div> + <div class="developer">Desarrollado por: <a href="https://ferrocarrilcentral.com.pe/">www.ferrocarrilcentral.com.pe</a></div> + </div> + </div> + </div> + </div> + </footer> + + <script src="https://ferrocarrilcentral.com.pe/appfcca/assets/js/jquery.min.js"></script> + <!-- <script src="./node_modules/bootstrap/dist/js/bootstrap.min.js"></script> --> + <script src="https://ferrocarrilcentral.com.pe/appfcca/node_modules/bootstrap/dist/js/bootstrap.bundle.min.js"></script> + <script src="https://ferrocarrilcentral.com.pe/appfcca/assets/js/main.js"></script> +<script src="https://ferrocarrilcentral.com.pe/appfcca/assets/js/glider.min.js"></script> +<script src="https://ferrocarrilcentral.com.pe/appfcca/assets/js/glideslider.js"></script> + +<script type="text/javascript"> + $(document).ready(function(){ + + reloadRutas(); + + $('.carousel-list .item-glid').click(function() { + $(this).siblings('.item-glid').removeClass('active'); + $(this).addClass('active'); + + reloadRutas(); + + }); + + function reloadRutas() { + $rutas = $('.item-glid.active').data('rutas'); + if (typeof $rutas === "undefined") { + var $rutas = $('.item-glid:eq(0)').data('rutas'); + }else { + var $rutas = $('.item-glid.active').data('rutas'); + } + + $.ajax({ + type:"POST", + url:"https://ferrocarrilcentral.com.pe/appfcca/inc/ajax/rutas.php", + data:{ rutas: $rutas }, + beforeSend: function() { + $('#rutaselect').html("<div class='preloader mt-4 mb-4'><img src='https://ferrocarrilcentral.com.pe/appfcca/assets/img/prelouder-icon.svg'/></div>"); + }, + success:function(r){ + $('#rutaselect').html(r); + } + }); + } + + // Active nav progress + $('.departure').addClass('active'); + + // Reconocimiento de medida de pantalla del usuario + var mediaMobile = window.matchMedia("(max-width: 990px)"); + var mediaDesktop = window.matchMedia("(min-width: 991px)"); + + var mobile = {status: mediaMobile.matches}; + var desktop = {status: mediaDesktop.matches}; + + $.ajax({ + type: "POST", + url: "https://ferrocarrilcentral.com.pe/appfcca/config/device-screen.php", + data: { mobile: mobile, desktop: desktop }, + success: function(r) { //response + console.log('se genero correctamente'); + } + }); + + }); +</script> + +</body> +</html>