132 lines
5.1 KiB
JavaScript
132 lines
5.1 KiB
JavaScript
const { BaseScraper } = require('./scraper.js');
|
|
const sharp = require('sharp');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
class ColaMangaScraper extends BaseScraper {
|
|
constructor() {
|
|
super();
|
|
}
|
|
|
|
async saveBufferAsWebp(buffer, filename, dir = '.') {
|
|
const dirPath = path.resolve(dir);
|
|
const filePath = path.join(dirPath, filename);
|
|
|
|
try {
|
|
await fs.promises.mkdir(dirPath, { recursive: true });
|
|
await sharp(buffer).webp({ quality: 80 }).toFormat('webp').toFile(filePath);
|
|
} catch (error) {
|
|
console.error(`Failed to save ${filename}:`, error);
|
|
}
|
|
}
|
|
|
|
async getMangaInfo(mangaUrl) {
|
|
const page = await this.loadPage(mangaUrl);
|
|
await page.waitForSelector('.fed-deta-info', { visible: true });
|
|
const mangaName = await page.$eval('.fed-deta-content h1', el => el.textContent);
|
|
const elements = await page.$$('.fed-deta-content li');
|
|
const mangaInfo = {
|
|
name: mangaName,
|
|
author: '',
|
|
nickNames: [],
|
|
genres: [],
|
|
status: '',
|
|
chapters: []
|
|
};
|
|
for (const el of elements) {
|
|
const span = await el.$eval('span', el => el.textContent.trim());
|
|
if (span === '状态') {
|
|
mangaInfo.status = await el.$eval('a', el => el.textContent);
|
|
} else if (span === '作者') {
|
|
mangaInfo.author = await el.$eval('a', el => el.textContent);
|
|
} else if (span === '别名') {
|
|
mangaInfo.nickNames = await el.$$eval('a', els => els.map(el => el.textContent));
|
|
} else if (span === '类别') {
|
|
mangaInfo.genres = await el.$$eval('a', els => els.map(el => el.textContent));
|
|
}
|
|
}
|
|
const chapterElements = await page.$$('.all_data_list li');
|
|
mangaInfo.chapters = await Promise.all(chapterElements.map(async el => {
|
|
const chapterName = await el.$eval('a', el => el.textContent);
|
|
const chapterUrl = await el.$eval('a', el => el.getAttribute('href'));
|
|
return {
|
|
name: chapterName,
|
|
url: chapterUrl
|
|
};
|
|
}));
|
|
while (!this.pages_response[this.pages.indexOf(page)]) {
|
|
await new Promise(resolve => setTimeout(resolve, 100));
|
|
}
|
|
mangaInfo.coverPic = this.pages_response[this.pages.indexOf(page)];
|
|
await this.closePage(page);
|
|
return mangaInfo;
|
|
}
|
|
|
|
async downloadChapterPics(chapter, chapterDir = ".") {
|
|
const directoryPath = path.resolve(chapterDir);
|
|
if (fs.existsSync(directoryPath)) {
|
|
console.log(`Skipping ${chapter.name} as it already exists`);
|
|
return;
|
|
}
|
|
fs.mkdirSync(directoryPath, { recursive: true });
|
|
|
|
const page = await this.loadPage(chapter.url);
|
|
const pageIndex = this.pages.indexOf(page);
|
|
await page.waitForSelector('.mh_mangalist', { visible: true });
|
|
|
|
for (let attempt = 0; attempt < 10; attempt++) {
|
|
console.log(`Downloading ${chapter.name}, attempt ${attempt + 1}`);
|
|
await this.scrollPage(page);
|
|
const loadingElements = await page.$$eval('.mh_loading:not([style*="display: none"])', elements => elements.length);
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
if (loadingElements === 0 && Object.keys(this.pages_response[pageIndex]).length !== 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
const responses = this.pages_response[pageIndex];
|
|
for (const [url, response] of Object.entries(responses)) {
|
|
const fileName = (await this.getImgOrder(page, url)) + '.webp';
|
|
const buffer = await (new Blob([response], { type: 'image/webp' })).arrayBuffer();
|
|
await this.saveBufferToWebp(buffer, fileName, chapterDir);
|
|
}
|
|
|
|
await this.closePage(page);
|
|
}
|
|
|
|
async downloadChapter(chapters, dir = ".") {
|
|
const dirPath = path.resolve(dir);
|
|
if (!fs.existsSync(dirPath)) {
|
|
fs.mkdirSync(dirPath, { recursive: true });
|
|
}
|
|
// const chapter = chapters[Math.floor(Math.random() * chapters.length)];
|
|
for (const chapter of chapters) {
|
|
await this.downloadChapterPics(chapter, path.join(dir, chapter.name));
|
|
}
|
|
}
|
|
|
|
async getImgOrder(page, src) {
|
|
const loadingAttributes = await page.$$eval('.mh_comicpic', (elements, src) => {
|
|
return elements
|
|
.filter(el => el.querySelector(`img[src="${src}"]`))
|
|
.map(el => el.getAttribute('p'))
|
|
.map(str => str.padStart(elements.length.toString().length, '0'));
|
|
}, src);
|
|
return loadingAttributes;
|
|
}
|
|
}
|
|
|
|
(async () => {
|
|
const scraper = new ColaMangaScraper();
|
|
await scraper.init();
|
|
const mangaUrl = 'https://www.colamanga.com/manga-od825111/';
|
|
const mangaInfo = await scraper.getMangaInfo(mangaUrl);
|
|
await scraper.saveBufferToWebp(mangaInfo.coverPic, 'cover.webp', 'test');
|
|
await scraper.downloadChapter(mangaInfo.chapters, 'test');
|
|
await scraper.closeAllPages();
|
|
console.log(mangaInfo);
|
|
})();
|
|
|
|
|
|
|