/* * Name: Zix Anjay Slebeww * saluran: https://whatsapp.com/channel/0029Vb6P2e1E50UZYaX4wI0W * support zix: http://unggah.web.id/7cL2Sj1qEbxw.jpeg * * site download video: https://savenest.web.id */ const axios = require('axios'); const cheerio = require('cheerio'); class WebtoonScraper { constructor() { this.baseUrl = 'https://m.webtoons.com/id'; this.imageBaseUrl = 'https://webtoon-phinf.pstatic.net'; this.client = axios.create({ headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36', 'Referer': 'https://www.webtoons.com/id', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8' } }); } async getTrending() { try { const { data } = await this.client.get(this.baseUrl); const $ = cheerio.load(data); const results = []; $('ul._trending_page li.item').each((i, el) => { const link = $(el).find('a.link'); const title = $(el).find('.info_text .title').text().trim(); const genre = $(el).find('.info_text .genre').text().trim(); const url = link.attr('href'); const titleNo = link.attr('data-title-no'); const imageUrl = $(el).find('.image_wrap img').attr('src'); const rank = $(el).find('.ranking_text strong span.blind').text().replace(/"/g, '').trim(); if(title) { results.push({ rank: parseInt(rank), titleNo: parseInt(titleNo), title, genre, url, imageUrl }); } }); return results; } catch (error) { console.error('Gagal mengambil data Trending:', error.message); return []; } } async getDaily(day = 'thursday') { try { const url = `${this.baseUrl}/originals/${day}/title?sortOrder=MANA`; const { data } = await this.client.get(url); return data.map(item => ({ titleNo: item.titleNo, title: item.title, genre: item.representGenre, likes: item.likeitCount, isMature: item.unsuitableForChildren, url: `${this.baseUrl}/${item.representGenreSeoCode}/${item.titleGroupName}/list?title_no=${item.titleNo}`, imageUrl: `${this.imageBaseUrl}${item.posterThumbnail}?type=q70` })); } catch (error) { console.error(`Gagal mengambil API JSON (${day}):`, error.message); return []; } } async search(keyword) { try { const [thursdayData, fridayData] = await Promise.all([ this.getDaily('thursday'), this.getDaily('friday') ]); const allWebtoons = [...thursdayData, ...fridayData]; return allWebtoons.filter(item => item.title.toLowerCase().includes(keyword.toLowerCase()) ); } catch (error) { console.error('Gagal melakukan pencarian:', error.message); return []; } } async getPopular() { try { const { data } = await this.client.get(this.baseUrl); const $ = cheerio.load(data); const results = []; $('ul._popular_page li.item').each((i, el) => { const link = $(el).find('a.link'); const title = $(el).find('.info_text .title').text().trim(); const genre = $(el).find('.info_text .genre').text().trim(); const url = link.attr('href'); const titleNo = link.attr('data-title-no'); const imageUrl = $(el).find('.image_wrap img').attr('src'); const rankText = $(el).find('[class^="ranking_number_"] span.blind').text().replace(/"/g, '').trim(); if(title) { results.push({ rank: parseInt(rankText) || (i + 1), titleNo: parseInt(titleNo), title, genre, url, imageUrl }); } }); return results; } catch (error) { console.error('Gagal mengambil data Populer:', error.message); return []; } } async getByCategory() { try { const { data } = await this.client.get(this.baseUrl); const $ = cheerio.load(data); const results = {}; $('#genre_list ul[role="tabpanel"]').each((i, listEl) => { const categoryName = $(listEl).attr('aria-label'); if(!categoryName) return; results[categoryName] = []; $(listEl).find('li.item').each((j, itemEl) => { const link = $(itemEl).find('a.link'); const title = $(itemEl).find('.info_text .title').text().trim(); const viewCount = $(itemEl).find('.info_text .view_count').text().trim(); const url = link.attr('href'); const titleNo = link.attr('data-title-no'); const imageUrl = $(itemEl).find('.image_wrap img').attr('src'); results[categoryName].push({ titleNo: parseInt(titleNo), title, viewCount, url, imageUrl }); }); }); return results; } catch (error) { console.error('Gagal mengambil data Kategori:', error.message); return {}; } } async getNewReleases() { try { const { data } = await this.client.get(this.baseUrl); const $ = cheerio.load(data); const results = []; $('ul.newly_released li.item').each((i, el) => { const link = $(el).find('a.link'); const url = link.attr('href'); const titleNo = link.attr('data-title-no'); const imageUrl = $(el).find('.image_wrap img').attr('src'); let title = "Unknown"; if (url) { const urlParts = url.split('/'); title = urlParts[urlParts.length - 2].replace(/-/g, ' '); } if(titleNo) results.push({ titleNo: parseInt(titleNo), title, url, imageUrl }); }); return results; } catch (error) { console.error('Gagal mengambil Rilis Terbaru:', error.message); return []; } } async getCanvas() { try { const canvasUrl = `${this.baseUrl}/canvas`; const { data } = await this.client.get(canvasUrl); const $ = cheerio.load(data); const results = []; $('ul.type_canvas li.item').each((i, el) => { const link = $(el).find('a.link'); const title = $(el).find('.info_text .title').text().trim(); const genre = $(el).find('.info_text .genre').text().trim() || "Tidak ada"; const url = link.attr('href'); const titleNo = link.attr('data-title-no'); const imageUrl = $(el).find('.image_wrap img').attr('src'); if(title) results.push({ titleNo: parseInt(titleNo), title, genre, url, imageUrl }); }); return results; } catch (error) { console.error('Gagal mengambil data Canvas:', error.message); return []; } } async getDailyViewCount() { try { const { data } = await this.client.get(this.baseUrl); const $ = cheerio.load(data); const results = []; $('#daily_list li.item').each((i, el) => { const title = $(el).find('.info_text .title').text().trim(); const genre = $(el).find('.info_text .genre').text().trim(); const link = $(el).find('a.link').attr('href'); const titleNo = $(el).find('a.link').attr('data-title-no'); const imageUrl = $(el).find('.image_wrap img').attr('src'); const viewCount = $(el).find('.info_text .view_count.type_like').text().trim(); const badge = $(el).find('.icon_area .ico').text().trim() || null; if(title) results.push({ titleNo: parseInt(titleNo), title, genre, badge, viewCount, link, imageUrl }); }); return results; } catch (error) { console.error('Gagal mengambil data Jadwal Harian (HTML):', error.message); return []; } } async getCanvasDiscoverView() { try { const canvasUrl = `${this.baseUrl}/canvas`; const { data } = await this.client.get(canvasUrl); const $ = cheerio.load(data); const results = []; $('.list_discover li').each((i, el) => { const title = $(el).find('.tit_discover').text().trim(); const genre = $(el).find('.genre').text().trim(); const link = $(el).find('a.link_discover').attr('href'); const imageUrl = $(el).find('.thumb_discover img.img_discover').attr('src'); const likes = $(el).find('.info_grade .grade_num').text().trim(); if(title) results.push({ title, genre, likes, link, imageUrl }); }); return results; } catch (error) { console.error('Gagal mengambil data Canvas Discover:', error.message); return []; } } async getEpisodeImages(episodeUrl) { try { const targetUrl = episodeUrl.replace('https://m.', 'https://www.'); const { data } = await this.client.get(targetUrl); const $ = cheerio.load(data); const images = []; $('#_imageList img._images').each((i, el) => { let imgUrl = $(el).attr('data-url'); if (imgUrl && imgUrl.startsWith('http') && !imgUrl.includes('warning')) { images.push(imgUrl); } }); return [...new Set(images)]; } catch (error) { console.error('Gagal mengambil gambar episode:', error.message); return []; } } } (async () => { const scraper = new WebtoonScraper(); console.log("Memulai pengujian SEMUA fitur scraper...\n"); console.log("=== 1. TEST TRENDING ==="); const trending = await scraper.getTrending(); console.log(`Berhasil mengambil ${trending.length} judul trending.`); if (trending.length > 0) console.log("Top 1 Trending:", trending[0]); console.log("\n=== 2. TEST JADWAL HARIAN (JSON) ==="); const thursday = await scraper.getDaily('thursday'); console.log(`Berhasil mengambil ${thursday.length} judul rilis hari Kamis.`); if (thursday.length > 0) console.log("Data pertama:", thursday[0]); console.log("\n=== 3. TEST SEARCH ==="); const keyword = 'King'; const searchRes = await scraper.search(keyword); console.log(`Ditemukan ${searchRes.length} judul dengan kata '${keyword}'.`); if (searchRes.length > 0) console.log("Hasil pencarian pertama:", searchRes[0].title); console.log("\n=== 4. TEST POPULER ==="); const popular = await scraper.getPopular(); console.log(`Berhasil mengambil ${popular.length} judul populer.`); if (popular.length > 0) console.log("Top 1 Populer:", popular[0].title); console.log("\n=== 5. TEST KATEGORI (GENRE) ==="); const category = await scraper.getByCategory(); const listAksi = category['Aksi'] || []; console.log(`Ditemukan ${listAksi.length} webtoon di kategori Aksi.`); if (listAksi.length > 0) console.log("Contoh Aksi Pertama:", listAksi[0].title, "->", listAksi[0].viewCount); console.log("\n=== 6. TEST RILIS TERBARU ==="); const newReleases = await scraper.getNewReleases(); console.log(`Berhasil mengambil ${newReleases.length} judul rilis terbaru.`); if (newReleases.length > 0) console.log("Rilis terbaru pertama:", newReleases[0]); console.log("\n=== 7. TEST CANVAS ==="); const canvas = await scraper.getCanvas(); console.log(`Berhasil mengambil ${canvas.length} judul canvas.`); if (canvas.length > 0) console.log("Canvas pertama:", canvas[0].title); console.log("\n=== 8. TEST JADWAL HTML (VIEW COUNT & BADGE) ==="); const dailyHtml = await scraper.getDailyViewCount(); console.log(`Berhasil mengambil ${dailyHtml.length} jadwal HTML.`); if (dailyHtml.length > 0) console.log("Jadwal HTML pertama:", dailyHtml[0].title, "| Views:", dailyHtml[0].viewCount); console.log("\n=== 9. TEST CANVAS TERPOPULER MINGGU INI ==="); const canvasDiscover = await scraper.getCanvasDiscoverView(); console.log(`Berhasil mengambil ${canvasDiscover.length} canvas terpopuler.`); if (canvasDiscover.length > 0) console.log("Terpopuler 1:", canvasDiscover[0].title, "| Likes:", canvasDiscover[0].likes); console.log("\n=== 10. TEST AMBIL PANEL GAMBAR VIEWER ==="); const episodeUrl = "https://m.webtoons.com/id/action/manajer-kim/episode-1/viewer?title_no=3856&episode_no=1"; const panelImages = await scraper.getEpisodeImages(episodeUrl); console.log(`Berhasil mengekstrak ${panelImages.length} panel gambar dari episode Manajer Kim.`); if (panelImages.length > 0) { console.log("URL Gambar Panel 1:", panelImages[0]); console.log("URL Gambar Panel 2:", panelImages[1]); console.log("URL Gambar Panel 3:", panelImages[2]); } console.log("\nSemua pengujian selesai! 🚀"); })();