Created KissAsianScraper.
This commit is contained in:
115
src/classes/scraping/KissAsianScraper.js
Normal file
115
src/classes/scraping/KissAsianScraper.js
Normal file
@@ -0,0 +1,115 @@
|
||||
const Logger = require('../utils/Logger');
|
||||
const { ScraperError } = require('../../errors');
|
||||
|
||||
class KissAsianScraper {
|
||||
constructor(page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
async load() {
|
||||
await this.page.goto(KissAsianScraper.BASE_URL);
|
||||
await this.page.waitForSelector(KissAsianScraper.DEFAULTS.SITE_SELECTOR);
|
||||
|
||||
Logger.info('Cloudflare DDOS Protection bypassed, redirected to main site.');
|
||||
}
|
||||
|
||||
async authenticate(credentials) {
|
||||
await this.page.click('#topHolderBox a[href="/Login"]');
|
||||
await this.page.waitForSelector('#btnSubmit');
|
||||
|
||||
Logger.info('Authenticating...');
|
||||
|
||||
await this.page.$eval('#username', (el, credentials) => el.value = credentials.username, credentials);
|
||||
await this.page.$eval('#password', (el, credentials) => el.value = credentials.password, credentials);
|
||||
|
||||
await this.page.click('#btnSubmit');
|
||||
await this.page.waitForSelector('#head a.logo');
|
||||
|
||||
Logger.success(`Successfully logged in as ${credentials.username}.`);
|
||||
}
|
||||
|
||||
async getMediaLinks(mediaURL) {
|
||||
await this.page.goto(mediaURL);
|
||||
await this.page.waitForSelector(KissAsianScraper.DEFAULTS.SITE_SELECTOR);
|
||||
|
||||
Logger.info(`Visited ${mediaURL}`);
|
||||
Logger.info('Getting media links...');
|
||||
|
||||
const links = await this.page.evaluate(() => {
|
||||
const table = document.querySelector('.episodeList table.listing');
|
||||
const tableBody = table.firstElementChild;
|
||||
|
||||
const links = [];
|
||||
for (let i = tableBody.children.length - 1; i > 1; i--) {
|
||||
const node = tableBody.children.item(i);
|
||||
const aElement = node.firstElementChild.firstElementChild;
|
||||
links.push(aElement.href);
|
||||
}
|
||||
|
||||
return links;
|
||||
});
|
||||
|
||||
Logger.success(`Scraped ${links.length} media links.`);
|
||||
|
||||
return links;
|
||||
}
|
||||
|
||||
async directlyVisitPlayerURL(playerURL) {
|
||||
await this.page.goto(`${playerURL}&s=mp`);
|
||||
await this.page.waitForSelector(KissAsianScraper.DEFAULTS.SITE_SELECTOR);
|
||||
|
||||
const isCaptchaEnabled = await this.page.evaluate(() => {
|
||||
const form = document.getElementById('formVerify');
|
||||
|
||||
return !!form;
|
||||
});
|
||||
|
||||
if (isCaptchaEnabled) {
|
||||
throw new ScraperError(`MP server not available for ${playerURL}`);
|
||||
}
|
||||
|
||||
Logger.info(`Directly visited ${playerURL}`);
|
||||
}
|
||||
|
||||
async getDownloadLinkForCurrentPlayer() {
|
||||
return await this.page.evaluate(() => {
|
||||
const divDownload = document.getElementById('divDownload');
|
||||
const aElement = divDownload.lastElementChild;
|
||||
return aElement.href;
|
||||
});
|
||||
}
|
||||
|
||||
async skipCaptcha(playerURL) {
|
||||
Logger.warn('Skipping captcha...');
|
||||
|
||||
const [skipCaptchaButton] = await this.page.$x('//a[contains(., "FE server")]');
|
||||
|
||||
if (!skipCaptchaButton) {
|
||||
throw new ScraperError(`Skip captcha button not found for ${playerURL}`);
|
||||
}
|
||||
|
||||
await skipCaptchaButton.click();
|
||||
await this.page.waitForSelector(KissAsianScraper.DEFAULTS.SITE_SELECTOR);
|
||||
|
||||
Logger.success('Successfully skipped captcha.');
|
||||
}
|
||||
|
||||
async selectEpisodeServerForCurrentPlayer(server) {
|
||||
try {
|
||||
await this.page.select('#selectServer', server);
|
||||
await this.page.waitForSelector(KissAsianScraper.DEFAULTS.SITE_SELECTOR);
|
||||
|
||||
Logger.info(`Changed streaming server to ${server}.`);
|
||||
} catch (err) {
|
||||
throw new ScraperError(`Server ${server} is unavailable.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KissAsianScraper.BASE_URL = 'https://kissasian.li';
|
||||
|
||||
KissAsianScraper.DEFAULTS = {
|
||||
SITE_SELECTOR: '#head a.logo'
|
||||
};
|
||||
|
||||
module.exports = KissAsianScraper;
|
21
src/classes/utils/Logger.js
Normal file
21
src/classes/utils/Logger.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const chalk = require('chalk');
|
||||
|
||||
class Logger {
|
||||
static info(...args) {
|
||||
console.info(chalk.blue(...args));
|
||||
}
|
||||
|
||||
static error(...args) {
|
||||
console.error(chalk.red(...args));
|
||||
}
|
||||
|
||||
static success(...args) {
|
||||
console.log(chalk.green(...args));
|
||||
}
|
||||
|
||||
static warn(...args) {
|
||||
console.warn(chalk.yellow(...args));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Logger;
|
9
src/errors/FatalError.js
Normal file
9
src/errors/FatalError.js
Normal file
@@ -0,0 +1,9 @@
|
||||
class FatalError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
|
||||
this.name = 'FatalError';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FatalError;
|
9
src/errors/ScraperError.js
Normal file
9
src/errors/ScraperError.js
Normal file
@@ -0,0 +1,9 @@
|
||||
class ScraperError extends Error {
|
||||
constructor(message) {
|
||||
super(message);
|
||||
|
||||
this.name = 'ScraperError';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ScraperError;
|
7
src/errors/index.js
Normal file
7
src/errors/index.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const FatalError = require('./FatalError');
|
||||
const ScraperError = require('./ScraperError');
|
||||
|
||||
module.exports = {
|
||||
FatalError,
|
||||
ScraperError
|
||||
};
|
24
src/index.js
Normal file
24
src/index.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const puppeteer = require('puppeteer-extra');
|
||||
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
|
||||
const AdBlockerPlugin = require('puppeteer-extra-plugin-adblocker');
|
||||
const KissAsianScraper = require('./classes/scraping/KissAsianScraper');
|
||||
const credentials = require('../data/credentials.json');
|
||||
|
||||
puppeteer.use(StealthPlugin());
|
||||
puppeteer.use(AdBlockerPlugin({ blockTrackers: true }));
|
||||
|
||||
const main = async() => {
|
||||
const browser = await puppeteer.launch({ headless: false, slowMo: 250 });
|
||||
const page = await browser.newPage();
|
||||
const scraper = new KissAsianScraper(page);
|
||||
|
||||
await scraper.load();
|
||||
await scraper.authenticate(credentials.kissasian);
|
||||
|
||||
const links = await scraper.getMediaLinks('https://kissasian.li/Drama/My-Roommate-is-a-Gumiho');
|
||||
await scraper.directlyVisitPlayerURL(links[0]);
|
||||
|
||||
console.log(await scraper.getDownloadLinkForCurrentPlayer());
|
||||
};
|
||||
|
||||
main();
|
Reference in New Issue
Block a user