|  | @@ -0,0 +1,111 @@
 | 
	
		
			
				|  |  | +import { type AnyNode, load } from "cheerio";
 | 
	
		
			
				|  |  | +import "dotenv/config";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import config from "../config";
 | 
	
		
			
				|  |  | +import Scraper from "./scraper";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import type { IScraperReportsOptions } from "../interfaces/scaper-reports-options";
 | 
	
		
			
				|  |  | +import type { IItem } from "../interfaces/item";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +import LogLevels from "../enums/log-levels";
 | 
	
		
			
				|  |  | +import Props from "../enums/props";
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +export default class ScraperReports {
 | 
	
		
			
				|  |  | +  private readonly _name: string;
 | 
	
		
			
				|  |  | +  private readonly _options: IScraperReportsOptions;
 | 
	
		
			
				|  |  | +  private readonly _scraper: Scraper;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  constructor (name: string, options: IScraperReportsOptions) {
 | 
	
		
			
				|  |  | +    this._name = name;
 | 
	
		
			
				|  |  | +    this._options = options;
 | 
	
		
			
				|  |  | +    this._scraper = new Scraper();
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  private getProperty (domNodeElement: AnyNode, selector: string, prop: Props = Props.TEXT): string {
 | 
	
		
			
				|  |  | +    const $ = load(domNodeElement);
 | 
	
		
			
				|  |  | +    let value: string | undefined = "";
 | 
	
		
			
				|  |  | +    try {
 | 
	
		
			
				|  |  | +      value = prop === Props.TEXT ? $(selector).text() : $(selector).attr(prop);
 | 
	
		
			
				|  |  | +    } catch (err) {
 | 
	
		
			
				|  |  | +      if (config.LOG_LEVEL === LogLevels.DEBUG) {
 | 
	
		
			
				|  |  | +        console.debug(`${this._name} | Error raised\n`);
 | 
	
		
			
				|  |  | +        console.debug(`From ${domNodeElement.type} can't get value using selector '${selector}'`);
 | 
	
		
			
				|  |  | +        console.error(err.message);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    return value ?? "";
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  private getDate (node: AnyNode): string {
 | 
	
		
			
				|  |  | +    const selector = this._options.dateSelector ?? "";
 | 
	
		
			
				|  |  | +    return selector !== "" ? this.getProperty(node, selector).trim() : new Date(Date.now()).toLocaleDateString("es-CL");
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  private getLocation (node: AnyNode): string {
 | 
	
		
			
				|  |  | +    const selector = this._options.locationSelector ?? "";
 | 
	
		
			
				|  |  | +    return selector !== "" ? this.getProperty(node, selector).trim() : "";
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  private getDepth (node: AnyNode): string {
 | 
	
		
			
				|  |  | +    const selector = this._options.depthSelector ?? "";
 | 
	
		
			
				|  |  | +    return selector !== "" ? this.getProperty(node, selector).trim() : "";
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  private getMagnitude (node: AnyNode): number {
 | 
	
		
			
				|  |  | +    const selector = this._options.magnitudeSelector ?? "";
 | 
	
		
			
				|  |  | +    return selector !== "" ? Number(this.getProperty(node, selector).trim()) : 0;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  private getLink (node: AnyNode): string {
 | 
	
		
			
				|  |  | +    const selector = this._options.linkSelector ?? "";
 | 
	
		
			
				|  |  | +    let link = selector !== "" ? this.getProperty(node, selector, Props.LINK).trim() : "";
 | 
	
		
			
				|  |  | +    link = this._options.url.replace("/index.html", "") + link;
 | 
	
		
			
				|  |  | +    return link;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  private async getLocationImg (link: string): Promise<File | null> {
 | 
	
		
			
				|  |  | +    return await this._scraper.scrapeFile(link);
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +  public async getItems (): Promise<IItem[]> {
 | 
	
		
			
				|  |  | +    const items: IItem[] = [];
 | 
	
		
			
				|  |  | +    const startTime = Date.now();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    try {
 | 
	
		
			
				|  |  | +      console.info("Starting scraping", this._options);
 | 
	
		
			
				|  |  | +      const response = await this._scraper.scrape({ url: this._options.url });
 | 
	
		
			
				|  |  | +      const html = response.data.data.html;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      const $ = load(html as string);
 | 
	
		
			
				|  |  | +      const domElements = $(this._options.reportsSelector);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      if (config.LOG_LEVEL === LogLevels.DEBUG) {
 | 
	
		
			
				|  |  | +        console.debug(`${this._name} | Items obtained: ${domElements.length} `);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +      for (let i = 1; i < 2; i++) {
 | 
	
		
			
				|  |  | +        const node = domElements[i];
 | 
	
		
			
				|  |  | +        const link = this.getLink(node);
 | 
	
		
			
				|  |  | +        items.push({
 | 
	
		
			
				|  |  | +          date: this.getDate(node),
 | 
	
		
			
				|  |  | +          location: this.getLocation(node),
 | 
	
		
			
				|  |  | +          depth: this.getDepth(node),
 | 
	
		
			
				|  |  | +          magnitude: this.getMagnitude(node),
 | 
	
		
			
				|  |  | +          link,
 | 
	
		
			
				|  |  | +          locationImg: await this.getLocationImg(link.replace("html", "jpeg"))
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    } catch (err) {
 | 
	
		
			
				|  |  | +      if (config.LOG_LEVEL === LogLevels.DEBUG) {
 | 
	
		
			
				|  |  | +        console.debug(`${this._name} | Error\n`);
 | 
	
		
			
				|  |  | +        console.error(err.message);
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  | +    } finally {
 | 
	
		
			
				|  |  | +      const endTime = Date.now();
 | 
	
		
			
				|  |  | +      const duration = (endTime - startTime) / 1000;
 | 
	
		
			
				|  |  | +      console.info(`${this._name} | Execution time: ${duration}s`);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return items;
 | 
	
		
			
				|  |  | +  }
 | 
	
		
			
				|  |  | +}
 |