npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@xkairo/scrapy

v0.2.6

Published

Framework to scrape data from web pages

Downloads

26

Readme

Scrapy

Sobre el proyecto

Este proyecto tiene la idea de facilitar los scraps a sitios web ofreciendo una solucion modularizada para que parte del proceso en estos. Esto tambien permitira el uso de inversion de dependencias. Los tipos de modulos son los siguientes: -Uploaders -Processors -Services -Scrapers

Ejemplo basico de scrap:

    import Scraper, { Uploaders, Processors, ExceptionsHandlers } from "@xkairo/scrapy";
    import path from "path";
    import { RandomScraper } from "path-to-your-scraper";

    const filepath = path.join(__dirname, "result.csv");
    const config = {
      uploaders: [Uploaders.LocalUploader],
      processors: [Processors.CsvProcessor],
      scrapers: [RandomScraper],
      services: [Puppeteer],
      providers: [
        puppeteerProvider,
        {
          filepath: {
            useValue: filepath,
          },
        },
      ],
      exceptionHandler: ExceptionHandler,
    };

    const scraper = new Scraper(config);

    await scraper.init();

Creacion de modulos propios

En caso de querer crear un modulo para su uso en el paquete sin necesidad de tener que requerir la libreria puede usar el paquete diseñado para esto Scrapy interfaces, esta permitira el desarrollo del mismo sin tener que requerir toda esta libreria.

Inyeccion de dependencias

Este paquete hace uso de la libreria tsyring para resolver la inyeccion de dependencias. Podra utilizar herramientas de la misma para proveer valores/instancias en las clases creadas. Ejemplo de inyeccion:

    constructor(@inject("filepath") private filepath: string) {}

y tendra que pasar dentro de la configuracion un array providers con los valores a inyectar

    providers: [{
        filepath: {
            useValue: filepath,
        }
        otherDataToInject: {
            useClass: Class
        }
    }],

Scrapers

Estas clases seran las que se encarguen de obtener y devolver el objeto que cumpla con la interfaz cargada. Su implementacion puede ser distinta dependiendo del caso. Estas deben usar el decorador injectable e implementar la interfaz PageScraperInterface. La libreria no trae ninguna implementacion de esta por defecto por lo que debera ser creada Un ejemplo de creacion:

@injectable()
export class PageScraper implements PageScraperInterface<UserInterface> {
  async scrap() {
    //Scrap logic
    return [
      {
        name: "test",
      },
    ];
  }
}

Uploaders

Estos son los encargados del manejo del stream una vez finalizado su scrap y procesamiento, siendo el responsable del guardado de los datos. Ejemplo de creacion:

@injectable()
export class LocalUploader implements UploaderInterface {
    // In this class you need to inject filepath
  constructor(@inject("filepath") private filepath: string) {}
  /**
   * Uploads a file in system location
   */
  async upload(data: Readable): Promise<void> {
    const filepath = this.filepath;
    //Get dir of file path
    const dir = parse(filepath).dir;
    //Create dir if it doesn't exist recursively
    if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
    //Create write stream and pipe data to it
    const ws = fs.createWriteStream(filepath);
    data.pipe(ws);

    return new Promise((resolve, reject) => {
      ws.on("finish", () => {
        resolve();
      });
      ws.on("error", (err) => {
        reject(err);
      });
    });
  }
}

Note el uso de injectable y de su interfaz

Processors

Estos son los encargados de procesar los datos obtenidos por el scraper y retornarlos como un stream, pudiendo convertir los objetos en el formato de archivo que desee. Estos deben implementar la interfaz ProcessorInterface y usar el decorador injectable. Ejemplo de creacion:

@injectable()
export class CsvProcessor<T extends object> implements ProcessorInterface<T> {
  readonly extension = ".csv";
  /**
   * Process data to csv stream
   * @param { UserResultInterface[] } data Array of users to be processed
   * @returns { Readable }
   */
  public async process(data: T[]): Promise<Readable> {
    //Parse data to csv and save it to tmp file
    await new ObjectToCsv(data).toDisk(tmpPath);
    //Convert temp file to stream
    const stream = fs.createReadStream(tmpPath);
    //Delete file when stream is closed
    stream.on("close", () => {
      fs.unlinkSync(tmpPath);
    });
    return stream;
  }
}

Services

Estos son los encargados de proveer la funcionalidad necesaria para el scraper, como por ejemplo el uso de puppeteer. Se pueden usar los providers para inyectar valores en estos. Pueden ser inyectados en cualquiera de los otros modulos con la inyeccion de dependencias y esa es su principal funcionalidad. Estos no necesitan una interfaz y usar el decorador injectable.

Puppeteer

En anteriores versiones este servicio se encontraba incluido en la version base. Debido a un peso innecesario en caso de no utilizarlo se decidio extraerlo a otra libreria Scrapy Puppeteer Plugin

Scrapy Puppeteer Plugin provee la funcionalidad de puppeteer. Permite el uso de plugins de puppeteer-extra-plugin y unicamente es una capa sobre el modulo de puppeteer.

Manejo de errores

Este paquete provee una clase que se encarga de manejar los errores que se puedan dar en el proceso de scrap. Ya existe una por defecto, pero puede hacer su propia implementacion. Esta clase debe implementar la interfaz ExceptionHandlerInterface y usar el decorador injectable. Caso de creacion:

export class ExceptionHandler implements ExceptionHandlerInterface {
  handle(exception: Exception): void {
    // Log the exception
    console.error("Error", exception.message);

    // If the exception has a cry function, call it
    exception.cry && exception.cry();

    // If the exception is fatal, stop the process
    if (exception.needStop) {
      process.exit(1);
    }
  }
}