feat(newParser): added animeAboutInfo parser
This commit is contained in:
@@ -0,0 +1,185 @@
|
|||||||
|
import axios, { AxiosError } from "axios";
|
||||||
|
import { load, CheerioAPI, SelectorType } from "cheerio";
|
||||||
|
import {
|
||||||
|
SRC_BASE_URL,
|
||||||
|
ACCEPT_HEADER,
|
||||||
|
USER_AGENT_HEADER,
|
||||||
|
ACCEPT_ENCODING_HEADER,
|
||||||
|
extractMostPopularAnimes,
|
||||||
|
extractAnimes,
|
||||||
|
} from "../utils";
|
||||||
|
|
||||||
|
import createHttpError, { HttpError } from "http-errors";
|
||||||
|
import { ScrapedAnimeAboutInfo } from "../models";
|
||||||
|
|
||||||
|
// /anime/info?id=${anime-id}
|
||||||
|
async function scrapeAnimeAboutInfo(
|
||||||
|
id: string
|
||||||
|
): Promise<ScrapedAnimeAboutInfo | HttpError> {
|
||||||
|
const res: ScrapedAnimeAboutInfo = {
|
||||||
|
anime: {
|
||||||
|
info: {
|
||||||
|
id: null,
|
||||||
|
name: null,
|
||||||
|
poster: null,
|
||||||
|
description: null,
|
||||||
|
stats: {
|
||||||
|
rating: null,
|
||||||
|
quality: null,
|
||||||
|
episodes: {
|
||||||
|
sub: null,
|
||||||
|
dub: null,
|
||||||
|
},
|
||||||
|
type: null,
|
||||||
|
duration: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
moreInfo: {},
|
||||||
|
},
|
||||||
|
seasons: [],
|
||||||
|
mostPopularAnimes: [],
|
||||||
|
relatedAnimes: [],
|
||||||
|
recommendedAnimes: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const animeUrl: URL = new URL(id, SRC_BASE_URL);
|
||||||
|
const mainPage = await axios.get(animeUrl.href, {
|
||||||
|
headers: {
|
||||||
|
"User-Agent": USER_AGENT_HEADER,
|
||||||
|
"Accept-Encoding": ACCEPT_ENCODING_HEADER,
|
||||||
|
Accept: ACCEPT_HEADER,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const $: CheerioAPI = load(mainPage.data);
|
||||||
|
|
||||||
|
const selector: SelectorType = "#ani_detail .container .anis-content";
|
||||||
|
|
||||||
|
res.anime.info.id =
|
||||||
|
$(selector)
|
||||||
|
?.find(".anisc-detail .film-buttons a.btn-play")
|
||||||
|
?.attr("href")
|
||||||
|
?.split("/")
|
||||||
|
?.pop() || null;
|
||||||
|
res.anime.info.name =
|
||||||
|
$(selector)
|
||||||
|
?.find(".anisc-detail .film-name.dynamic-name")
|
||||||
|
?.text()
|
||||||
|
?.trim() || null;
|
||||||
|
res.anime.info.description =
|
||||||
|
$(selector)
|
||||||
|
?.find(".anisc-detail .film-description .text")
|
||||||
|
.text()
|
||||||
|
?.split("[")
|
||||||
|
?.shift()
|
||||||
|
?.trim() || null;
|
||||||
|
res.anime.info.poster =
|
||||||
|
$(selector)?.find(".film-poster .film-poster-img")?.attr("src")?.trim() ||
|
||||||
|
null;
|
||||||
|
|
||||||
|
// stats
|
||||||
|
res.anime.info.stats.rating =
|
||||||
|
$(`${selector} .film-stats .tick .tick-pg`)?.text()?.trim() || null;
|
||||||
|
res.anime.info.stats.quality =
|
||||||
|
$(`${selector} .film-stats .tick .tick-quality`)?.text()?.trim() || null;
|
||||||
|
res.anime.info.stats.episodes = {
|
||||||
|
sub:
|
||||||
|
Number($(`${selector} .film-stats .tick .tick-sub`)?.text()?.trim()) ||
|
||||||
|
null,
|
||||||
|
dub:
|
||||||
|
Number($(`${selector} .film-stats .tick .tick-dub`)?.text()?.trim()) ||
|
||||||
|
null,
|
||||||
|
};
|
||||||
|
res.anime.info.stats.type =
|
||||||
|
$(`${selector} .film-stats .tick`)
|
||||||
|
?.text()
|
||||||
|
?.trim()
|
||||||
|
?.replace(/[\s\n]+/g, " ")
|
||||||
|
?.split(" ")
|
||||||
|
?.at(-2) || null;
|
||||||
|
res.anime.info.stats.duration =
|
||||||
|
$(`${selector} .film-stats .tick`)
|
||||||
|
?.text()
|
||||||
|
?.trim()
|
||||||
|
?.replace(/[\s\n]+/g, " ")
|
||||||
|
?.split(" ")
|
||||||
|
?.pop() || null;
|
||||||
|
|
||||||
|
// more information
|
||||||
|
$(`${selector} .anisc-info-wrap .anisc-info .item:not(.w-hide)`).each(
|
||||||
|
(i, el) => {
|
||||||
|
let key = $(el)
|
||||||
|
.find(".item-head")
|
||||||
|
.text()
|
||||||
|
.toLowerCase()
|
||||||
|
.replace(":", "")
|
||||||
|
.trim();
|
||||||
|
key = key.includes(" ") ? key.replace(" ", "") : key;
|
||||||
|
|
||||||
|
const value = [
|
||||||
|
...$(el)
|
||||||
|
.find("*:not(.item-head)")
|
||||||
|
.map((i, el) => $(el).text().trim()),
|
||||||
|
]
|
||||||
|
.map((i) => `${i}`)
|
||||||
|
.toString()
|
||||||
|
.trim();
|
||||||
|
|
||||||
|
if (key === "genres") {
|
||||||
|
res.anime.moreInfo[key] = value.split(",").map((i) => i.trim());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (key === "producers") {
|
||||||
|
res.anime.moreInfo[key] = value.split(",").map((i) => i.trim());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.anime.moreInfo[key] = value;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// more seasons
|
||||||
|
const seasonsSelector: SelectorType = "#main-content .os-list a.os-item";
|
||||||
|
$(seasonsSelector).each((i, el) => {
|
||||||
|
res.seasons.push({
|
||||||
|
id: $(el)?.attr("href")?.slice(1)?.trim() || null,
|
||||||
|
name: $(el)?.attr("title")?.trim() || null,
|
||||||
|
title: $(el)?.find(".title")?.text()?.trim(),
|
||||||
|
poster:
|
||||||
|
$(el)
|
||||||
|
?.find(".season-poster")
|
||||||
|
?.attr("style")
|
||||||
|
?.split(" ")
|
||||||
|
?.pop()
|
||||||
|
?.split("(")
|
||||||
|
?.pop()
|
||||||
|
?.split(")")[0] || null,
|
||||||
|
isCurrent: $(el).hasClass("active"),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const relatedAnimeSelector: SelectorType =
|
||||||
|
"#main-sidebar .block_area.block_area_sidebar.block_area-realtime:nth-of-type(1) .anif-block-ul ul li";
|
||||||
|
res.relatedAnimes = extractMostPopularAnimes($, relatedAnimeSelector);
|
||||||
|
|
||||||
|
const mostPopularSelector: SelectorType =
|
||||||
|
"#main-sidebar .block_area.block_area_sidebar.block_area-realtime:nth-of-type(2) .anif-block-ul ul li";
|
||||||
|
res.mostPopularAnimes = extractMostPopularAnimes($, mostPopularSelector);
|
||||||
|
|
||||||
|
const recommendedAnimeSelector: SelectorType =
|
||||||
|
"#main-content .block_area.block_area_category .tab-content .flw-item";
|
||||||
|
res.recommendedAnimes = extractAnimes($, recommendedAnimeSelector);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
} catch (err: any) {
|
||||||
|
if (err instanceof AxiosError) {
|
||||||
|
throw createHttpError(
|
||||||
|
err?.response?.status || 500,
|
||||||
|
err?.response?.statusText || "Something went wrong"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
throw createHttpError.InternalServerError(err?.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default scrapeAnimeAboutInfo;
|
||||||
Reference in New Issue
Block a user