tester-scraper
Version:
Sebuah Module Scraper yang dibuat oleh Sxyz dan SuzakuTeam untuk memudahkan penggunaan scraper di project ESM maupun CJS.
389 lines (334 loc) • 11.2 kB
JavaScript
import axios from "axios";
import * as cheerio from "cheerio";
import FormDatas from "form-data";
const anime = {
animeIndo: async (type, opt) => {
if (type === "latest") {
const { data } = await axios.get("https://anime-indo.lol/");
const $ = cheerio.load(data);
const result = [];
$("div.menu a").each((_, el) => {
const element = $(el);
const img = element.find("img.lazy").attr("data-original");
const title = element.find("p").text().trim();
const episode = element.find("span.eps").text().trim();
const link = "https://anime-indo.lol" + element.attr("href");
if (!title || !episode || !img) return;
result.push({
title,
episode,
img,
link,
});
});
return result;
} else if (type === "search") {
const query = opt?.query;
if (!query) return { error: "Query kosong. Masukkan `query`." };
const formattedQuery = query.replace(/\s+/g, "-").toLowerCase();
const { data: Search } = await axios.get(
`https://anime-indo.lol/search/${formattedQuery}/`,
);
const $$ = cheerio.load(Search);
const results = [];
$$(".menu table.otable").each((_, el) => {
const element = $$(el);
const linkPart = element.find("td.vithumb a").attr("href");
const link = "https://anime-indo.lol" + linkPart;
const img =
"https://anime-indo.lol" + element.find("td.vithumb img").attr("src");
const title = element.find("td.videsc a").first().text().trim();
const description = element.find("td.videsc p.des").text().trim();
results.push({
title,
img,
link,
description,
});
});
return results;
}
return {
msg: "Type Tidak Di Kenali!",
availableType: "latest, search",
availableOptions: {
query: "Pakai Jika Type Anda Adalah Search",
},
};
},
quotes: async () => {
let { data } = await axios.get(`https://otakotaku.com/quote/feed`);
let $ = cheerio.load(data);
let quotes = [];
$(".kotodama-list").each((i, el) => {
let character = $(el).find(".char-name").text().trim();
let anime = $(el).find(".anime-title").text().trim();
let episode = $(el).find(".meta").text().trim();
let quote = $(el).find(".quote").text().trim();
let image = $(el).find(".char-img img").attr("data-src");
let link = $(el).find("a.kuroi").attr("href");
quotes.push({
character,
anime,
episode,
quote,
image,
link: `https://otakotaku.com${link}`,
});
});
return quotes.length > 0
? quotes[Math.floor(Math.random() * quotes.length)]
: null;
},
anime9Search: async (anime) => {
const { data: dataa } = await axios.get(
`https://9animetv.to/search?keyword=${anime}`,
);
const $ = cheerio.load(dataa);
const result = [];
$(".flw-item").each((i, element) => {
const title = $(element).find(".film-name a").attr("title");
const url =
"https://9animetv.to" + $(element).find(".film-name a").attr("href");
const imgSrc = $(element).find(".film-poster-img").attr("data-src");
const quality = $(element).find(".tick-quality").text();
const subOrDub =
$(element).find(".tick-sub").text() ||
$(element).find(".tick-dub").text();
const episode = $(element)
.find(".tick-eps")
.text()
.replace(/\s+/g, " ")
.trim();
result.push({
title,
url,
imgSrc,
quality,
subOrDub,
episode,
});
});
return result;
},
anime9Details: async (url) => {
try {
let { data } = await axios.get(url);
let $ = cheerio.load(data);
let title = $(".film-name").text().trim();
let image = $(".film-poster img").attr("src");
let alias = $(".alias").text().trim();
let description = $(".film-description p").text().trim();
let type = $(".item-title:contains('Type:')").next().text().trim();
let studio = $(".item-title:contains('Studios:')").next().text().trim();
let aired = $(".item-title:contains('Date aired:')").next().text().trim();
let status = $(".item-title:contains('Status:')").next().text().trim();
let score = $(".item-title:contains('Scores:')").next().text().trim();
let duration = $(".item-title:contains('Duration:')")
.next()
.text()
.trim();
let quality = $(".item-title:contains('Quality:')").next().text().trim();
let views = $(".item-title:contains('Views:')").next().text().trim();
let genres = [];
$(".item-title:contains('Genre:')")
.next()
.find("a")
.each((_, el) => genres.push($(el).text().trim()));
return {
title,
image,
alias,
description,
type,
studio,
aired,
status,
score,
duration,
quality,
views,
genres,
};
} catch (error) {
console.error("Error fetching details:", error);
return null;
}
},
ikoapp: {
daftarAnime: async () => {
const { data } = await axios.get("https://ikoapp.com/daftar_anime");
const $ = cheerio.load(data);
const hasil = [];
$(".grid > div").each((i, el) => {
const element = $(el);
const link = element.find("a").attr("href")?.trim();
const thumb = element.find("img").attr("src")?.trim();
const title = element.find("h3").text().trim();
const episode = element.find("span").first().text().trim();
const type = element.find("span").last().text().trim();
hasil.push({
title,
link: "https://ikoapp.com" + link,
thumbnail: "https://ikoapp.com" + thumb,
episode,
type,
});
});
return hasil;
},
search: async (animeh) => {
if (!animeh) return "Masukkan Nama Anime";
const formData = new FormDatas();
formData.append("q", animeh);
formData.append("type", "");
formData.append("genre", "");
formData.append("status", "");
formData.append("sort", "");
const headers = {
headers: {
...formData.getHeaders(),
},
};
const { data } = await axios.post(
"https://ikoapp.com/anime/filter",
formData,
headers,
);
const $ = cheerio.load(data);
const results = [];
$(".grid > div").each((_, el) => {
const $el = $(el);
const link = $el.find("a").attr("href");
const title = $el.find("h3").text().trim();
const image = $el.find("img").attr("src");
const episode = $el.find("span").eq(0).text().trim();
const type = $el.find("span").eq(1).text().trim();
results.push({
title,
link: "https://ikoapp.com" + link,
image: image.startsWith("http")
? image
: "https://ikoapp.com" + image,
episode,
type,
});
});
return results;
},
sedangTayang: async () => {
const { data } = await axios.get("https://ikoapp.com/");
const $ = cheerio.load(data);
const hasil = [];
$("#sedang-tayang .card-anime").each((i, el) => {
const $el = $(el);
const title = $el.find("h5.title").text().trim();
const image = "https://ikoapp.com" + $el.find("img").attr("src");
const type = $el.find(".badge-type").text().trim();
const episode = $el.find(".episode").text().trim();
const views = $el.find(".views").text().trim();
const link =
"https://ikoapp.com" + $el.find("a.play-icon").attr("href");
hasil.push({
title,
image,
type,
episode,
views,
link,
});
});
return hasil;
},
animeAdd: async () => {
try {
const { data } = await axios.get("https://ikoapp.com");
const $ = cheerio.load(data);
const result = [];
$("#baru-ditambahkan .col-6.col-md-4.col-lg-3").each((_, el) => {
const element = $(el);
const image = element.find("img").attr("src");
const title = element.find("h5.title").text().trim();
const type = element.find(".badge-type").text().trim();
const status = element.find(".status").text().trim();
const link = element.find("a.play-icon").attr("href");
result.push({
title,
image: image?.startsWith("/")
? `https://ikoapp.com${image}`
: image,
type,
status,
link: link?.startsWith("/") ? `https://ikoapp.com${link}` : link,
});
});
return result;
} catch (err) {
console.error("Gagal mengambil data:", err.message);
}
},
recommended: async () => {
const { data } = await axios.get("https://ikoapp.com/recommendations");
const $ = cheerio.load(data);
const results = [];
$("main .grid > a").each((_, el) => {
const $el = $(el);
const title = $el.find("h2").text().trim();
const href = $el.attr("href")?.trim();
const image = $el.find("img").attr("src")?.trim();
const year = $el.find(".fa-calendar-alt").parent().text().trim();
const descShort = $el.find("p.italic").text().trim();
const descFull = $el.find("p.text-gray-400").text().trim();
const genres = [];
$el.find(".flex.flex-wrap.gap-2 span").each((_, span) => {
genres.push($(span).text().trim());
});
const rating = $el.find(".fa-star").parent().text().trim();
const status = $el.find(".fa-check-circle").parent().text().trim();
const views = $el.find(".fa-users").parent().text().trim();
results.push({
title,
link: "https://ikoapp.com" + href,
image: "https://ikoapp.com" + image,
year,
descShort,
descFull,
genres,
rating,
status,
views,
});
});
return results;
},
},
otakudesu: {
search: async (anime) => {
if (!anime) throw new Error("Please Input A Anime Name");
const { data } = await axios.get(
`https://otakudesu8.com/search/?q=${encodeURIComponent(anime)}`,
);
const $ = cheerio.load(data);
const results = [];
$(".xrelated").each((_, el) => {
const title = $(el).find(".titlelist").text().trim();
const link = $(el).find("a").attr("href");
const thumbnail = $(el).find("img").attr("src");
const rating = $(el).find(".starlist").text().trim();
const episode = $(el).find(".eplist").text().trim();
results.push({
title,
link,
thumbnail,
rating,
episode,
});
});
return {
success: true,
searchResult: results,
};
},
},
};
export default anime;