scraper mgkomik lengkap.
qrtz
javascript
16
3
https://web1.mgkomik.cc
13 Agu 2026
Code
const axios = require('axios');
const cheerio = require('cheerio');
const BASE_URL = 'https://web1.mgkomik.cc';
const USER_AGENTS = [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/119.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/119.0',
'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/119.0',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36',
];
function getRandomUserAgent() {
return USER_AGENTS[Math.floor(Math.random() * USER_AGENTS.length)];
}
function getRandomIP() {
const octet = () => Math.floor(Math.random() * 256);
return `${octet()}.${octet()}.${octet()}.${octet()}`;
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function fetchPage(url, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
const response = await axios.get(url, {
headers: {
'User-Agent': getRandomUserAgent(),
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'Accept-Language': 'en-US,en;q=0.5',
'Accept-Encoding': 'gzip, deflate, br',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
'Sec-Fetch-Dest': 'document',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'none',
'Sec-Fetch-User': '?1',
'Cache-Control': 'max-age=0',
'X-Forwarded-For': getRandomIP(),
'Client-IP': getRandomIP(),
},
timeout: 30000,
});
await sleep(500 + Math.random() * 1000);
return response.data;
} catch (e) {
if (i === retries - 1) throw e;
await sleep(1000 * (i + 1));
}
}
}
function cleanText(text) {
return text.replace(/\s+/g, ' ').trim();
}
function parseListPage(html) {
const $ = cheerio.load(html);
const items = [];
$('.manga-card').each(function() {
const $el = $(this);
const $cover = $el.find('.card-cover a');
const $info = $el.find('.card-info');
const $title = $info.find('.manga-title');
const $chapterCapsule = $info.find('.chapter-capsule');
const $chapterDate = $info.find('.chapter-date');
const $status = $el.find('.manga-status-badge');
const $flag = $el.find('.flag-badge');
const $img = $cover.find('img.manga-cover');
const thumbnail = $img.attr('src') || '';
const url = $cover.attr('href') || '';
const title = cleanText($title.text());
const status = cleanText($status.text());
const flagTitle = cleanText($flag.attr('title') || '');
const chapterText = cleanText($chapterCapsule.text());
const chapterLink = $chapterCapsule.attr('href') || '';
const chapterDate = cleanText($chapterDate.text());
if (title || url) {
items.push({
title,
url: url.startsWith('http') ? url : BASE_URL + url,
thumbnail,
status,
flag: flagTitle,
latestChapter: {
title: chapterText,
url: chapterLink.startsWith('http') ? chapterLink : BASE_URL + chapterLink,
date: chapterDate,
},
});
}
});
return items;
}
function parseDetailPage(html) {
const $ = cheerio.load(html);
const title = cleanText($('.manga-title').text());
const thumbnail = $('.manga-cover-large').attr('src') || '';
const type = cleanText($('.meta-item:first-child').text());
const status = cleanText($('.status-badge').text());
const genres = [];
$('.genre-tag').each(function() {
genres.push(cleanText($(this).text()));
});
const synopsis = cleanText($('.manga-description p').text());
const author = cleanText($('.meta-item:contains("Author:")').text().replace('Author:', '').trim());
const artist = cleanText($('.meta-item:contains("Artist:")').text().replace('Artist:', '').trim());
const release = cleanText($('.meta-item:contains("Release:")').text().replace('Release:', '').trim());
const chapters = [];
$('.chapter-list-item').each(function() {
const $el = $(this);
const $link = $el.find('.chapter-link');
const number = cleanText($el.find('.chapter-number').text());
const date = cleanText($el.find('.chapter-date').text());
const url = $link.attr('href') || '';
chapters.push({
number,
date,
url: url.startsWith('http') ? url : BASE_URL + url,
});
});
let prevChapter = null;
let nextChapter = null;
$('.nav-row .nav-btn').each(function() {
const $el = $(this);
const text = cleanText($el.text());
const href = $el.attr('href');
if (text.includes('Prev') && href && href !== '#') {
prevChapter = {
title: cleanText(text),
url: href.startsWith('http') ? href : BASE_URL + href,
};
}
if (text.includes('Next') && href && href !== '#') {
nextChapter = {
title: cleanText(text),
url: href.startsWith('http') ? href : BASE_URL + href,
};
}
});
return {
title,
thumbnail,
type,
status,
genres,
synopsis,
author,
artist,
release,
totalChapters: chapters.length,
chapters,
prevChapter,
nextChapter,
};
}
function parseChapterPage(html) {
const $ = cheerio.load(html);
const images = [];
$('.reading-content img').each(function() {
const src = $(this).attr('src');
if (src) images.push(src);
});
let prevChapter = null;
let nextChapter = null;
$('.nav-row .nav-btn').each(function() {
const $el = $(this);
const text = cleanText($el.text());
const href = $el.attr('href');
if (text.includes('Prev') && href && href !== '#') {
prevChapter = {
title: cleanText(text),
url: href.startsWith('http') ? href : BASE_URL + href,
};
}
if (text.includes('Next') && href && href !== '#') {
nextChapter = {
title: cleanText(text),
url: href.startsWith('http') ? href : BASE_URL + href,
};
}
});
return {
totalPages: images.length,
images,
prevChapter,
nextChapter,
};
}
function buildListUrl(opts) {
const { type, genre, order, page, status } = opts;
const params = new URLSearchParams();
if (page) params.set('page', page);
if (order) params.set('order_by', order);
if (status) {
params.set('status', status);
if (type) params.append('types[]', type);
if (genre) params.append('genres[]', genre);
return `/search/?${params.toString()}`;
}
if (type) params.set('filter', type);
else if (genre) params.set('filter', genre);
return `/komik/?${params.toString()}`;
}
function extractSlug(input) {
if (input.startsWith('http')) {
const urlObj = new URL(input);
const pathParts = urlObj.pathname.split('/').filter(p => p);
return pathParts[pathParts.length - 1] || pathParts[0];
}
return input;
}
async function fetchList(opts) {
const url = buildListUrl(opts);
const fullUrl = BASE_URL + url;
const html = await fetchPage(fullUrl);
return parseListPage(html);
}
async function fetchDetail(slugOrUrl) {
const slug = extractSlug(slugOrUrl);
const fullUrl = `${BASE_URL}/komik/${slug}/`;
const html = await fetchPage(fullUrl);
return parseDetailPage(html);
}
async function fetchChapter(slugOrUrl) {
let url = slugOrUrl;
if (!url.startsWith('http')) {
const slug = extractSlug(url);
url = `${BASE_URL}/komik/${slug}/chapter-01-1/`;
}
const html = await fetchPage(url);
return parseChapterPage(html);
}
function formatOutput(data, halaman = 'list', page = 1) {
return {
creator: 'rynaqrtz',
halaman,
page,
total: data.totalChapters || data.totalPages || data.length || 0,
data,
};
}
async function main() {
const args = process.argv.slice(2);
if (args.length === 0) {
console.log(JSON.stringify({
creator: 'rynaqrtz',
error: 'Perintah diperlukan',
usage: {
list: 'node mgkomik.js list [--type manga] [--genre action] [--order latest] [--page 1] [--status on-going]',
detail: 'node mgkomik.js detail <slug|url>',
chapter: 'node mgkomik.js chapter <slug|url>'
},
example: {
list: 'node mgkomik.js list --type manga --order latest --page 1',
detail: 'node mgkomik.js detail gimai-seikatsu',
chapter: 'node mgkomik.js chapter https://web1.mgkomik.cc/komik/gimai-seikatsu/chapter-39-2/'
}
}, null, 2));
return;
}
const command = args[0];
if (command === 'list') {
const opts = { page: 1 };
for (let i = 1; i < args.length; i++) {
const arg = args[i];
if (arg.startsWith('--')) {
const key = arg.slice(2);
const value = args[i + 1];
if (['type', 'genre', 'order', 'status'].includes(key)) {
opts[key] = value;
} else if (key === 'page') {
opts.page = parseInt(value) || 1;
}
i++;
}
}
try {
const data = await fetchList(opts);
const output = formatOutput(data, 'list', opts.page);
console.log(JSON.stringify(output, null, 2));
} catch (err) {
console.log(JSON.stringify({ creator: 'rynaqrtz', error: err.message }, null, 2));
}
} else if (command === 'detail') {
const input = args[1];
if (!input) {
console.log(JSON.stringify({ creator: 'rynaqrtz', error: 'Slug atau URL diperlukan' }, null, 2));
return;
}
try {
const data = await fetchDetail(input);
const output = formatOutput(data, 'detail', 1);
console.log(JSON.stringify(output, null, 2));
} catch (err) {
console.log(JSON.stringify({ creator: 'rynaqrtz', error: err.message }, null, 2));
}
} else if (command === 'chapter') {
const input = args[1];
if (!input) {
console.log(JSON.stringify({ creator: 'rynaqrtz', error: 'Slug atau URL chapter diperlukan' }, null, 2));
return;
}
try {
const data = await fetchChapter(input);
const output = formatOutput(data, 'chapter', 1);
console.log(JSON.stringify(output, null, 2));
} catch (err) {
console.log(JSON.stringify({ creator: 'rynaqrtz', error: err.message }, null, 2));
}
} else {
console.log(JSON.stringify({
creator: 'rynaqrtz',
error: `Perintah tidak dikenal: ${command}`,
available: ['list', 'detail', 'chapter']
}, null, 2));
}
}
if (require.main === module) {
main();
}
module.exports = { fetchList, fetchDetail, fetchChapter };Rating
Gimana snippet ini menurutmu?
Embed ke website / blog
<iframe src="https://qrtzcode.vercel.app/api/embed/comic/mgkomik" style="width:100%;height:400px;border:none;border-radius:12px;"></iframe>