javascript – Node.js html parser class

I have a simple class, called website which is able to get the html of a website (if the website html is not provided), the urls inside the website, the contents of the title, and description tag. As well as providing an array populated with the words, and objects representing the website image. My main concern is whether I should use existing libraries like cheerio or not, because I only want these 5 functions (where cheerio has many more) so it may be overkill. Also, cheerio cannot return an array populated with words and images (like in my content function), so I am still wondering if the advantages of cheerio outweigh the benefits. Also are there any alternatives to using regex to parse html as html is irregular?

Here is the class

function Query(haystack) {
  this.haystack = haystack;

  this.find = function(needle) {
    let position = 0;
    let positions = ();
    let i = -1;
    
    while (position !== -1) {
      position = this.haystack.indexOf(needle, i + 1);
      positions.push(position);
      i = position;
    };
    
    positions.pop();
    
    return positions;
  };

  this.count = function(needle) {
    let position = 0;
    let count = -1;
    let i = -1;

    while (position !== -1) {
      position = this.haystack.indexOf(needle, i + 1);
      count += 1;
      i = position;
    };

    return count;
  };

  this.individualize = function () {
    const seen = {};

    for (item of this.haystack) {
      seen(item) = true;
    };

    return Object.keys(seen);
  };
};

function Website(url, html) {
  this.url = url;
  this.html = html;

  this.request = function () {
    return new Promise(async (resolve) => {
      try {
        const response = await fetch(this.url);
        const htmlCode = await response.text();

        resolve({
          url,
          htmlCode
        });
      } catch {
        resolve("Error");
      };
    });
  };

  this.urls = function () {
    const query = new Query(this.html);
    const urlStarts = query.find("<a");
    
    return urlStarts.map((index) => {
      const start = this.html.indexOf('href="', index) + 6;
      const end = this.html.indexOf('"', start);

      return this.html.substring(start, end);
    }).filter((urlItem) => {
      return urlItem(0) !== "#" && 
             urlItem.substring(0, 11) !== ":javascript"
    })
    .map(urlItem => new URL(urlItem, this.url).href);
  };

  this.title = function () {
    const titlePosition = this.html.indexOf("<title");
    const start = this.html.indexOf(">", titlePosition) + 1;
    const end = this.html.indexOf("<", start);

    return this.html.substring(start, end);
  };

  this.description = function () {
    const descriptionMeta = this.html.indexOf('name="description"');

    if (descriptionMeta !== -1) {
      const query = new Query(this.html);
      const metaStarts = query.find("<meta");

      for (metaStart of metaStarts) {
        const metaEnd = this.html.indexOf(">", metaStart);

        if (descriptionMeta < metaEnd) {
          const contentStart = this.html.indexOf('content="', metaStart) + 9;
          const contentEnd = this.html.indexOf('"', contentStart);

          return this.html.substring(contentStart, contentEnd);
        };
      };
    };

    return "undefined";
  };

  this.content = function () {
    const parsedHtml = this.html.split(/(?!<img.+?>)<.+?>/g).join(" ")
                                .split(/(n|r|t)/g).join(" ");
    let contentList = ();

    for (i = 0; i < parsedHtml.length; i++) {
      const previousToken = i === 0 ? " " : parsedHtml(i - 1);
      const currentToken = parsedHtml(i);
      
      if (parsedHtml.substring(i, i + 4) === "<img") {
        const end = parsedHtml.indexOf(">", i) + 1;
        const srcStart = parsedHtml.indexOf('src="', i) + 5
        const srcEnd = parsedHtml.indexOf('"', srcStart);
        const srcRelative = parsedHtml.substring(srcStart, srcEnd);
        const src = new URL(srcRelative, this.url).href;
        const altStart = parsedHtml.indexOf('alt="', i) + 5;
        const altEnd = parsedHtml.indexOf('"', altStart);
        let alt = parsedHtml.substring(altStart, altEnd);

        if (alt === "") alt = "undefined";

        contentList.push({
          alt,
          src,
          parent: this.url
        });
        
        i = end;
      } else if (currentToken !== " " && previousToken === " ") {
        let end = parsedHtml.indexOf(" ", i) ;
        
        if (end === -1) end = parsedHtml.length;

        const words = parsedHtml.substring(i, end);

        contentList = contentList.concat(
          words.split(/(!"#$%&'()*+, -./:;<=>?@()^_`{|}~)/g)
               .map(word => stemmer(word.toLowerCase()))
        );
        i = end;
      };
    };

    return contentList;
  };
};