Back to Home
Gistify Snippet
Public
GitHub Trending Repositories Scraper
Modul JavaScript ini mengekstrak daftar repositori trending GitHub secara asinkron, memanfaatkan Cheerio untuk parsing HTML efisien dan menyediakan fallback data saat gagal.
#scraper#github#cheerio#nodejs#web-scraping
1
Rawgithub_trending.jsjavascript
89 lines| 1 | /** |
| 2 | * @fileoverview Modul Scraper GitHub Trending Repositories. |
| 3 | * |
| 4 | * Mengimplementasikan web scraper ringan untuk mengekstrak daftar repositori yang sedang tren di GitHub. |
| 5 | * Dilengkapi dengan penanganan kesalahan otomatis, fallback data analitik, dan parsing elemen DOM |
| 6 | * yang efisien tanpa ketergantungan library eksternal yang berat. |
| 7 | * |
| 8 | * @module scrapers/github-trending |
| 9 | * @version 1.1.0 |
| 10 | * @author kyiov |
| 11 | * @license MIT |
| 12 | */ |
| 13 | |
| 14 | import * as cheerio from 'cheerio' |
| 15 | import { pathToFileURL } from 'node:url' |
| 16 | |
| 17 | /** |
| 18 | * @typedef {Object} TrendingRepo |
| 19 | * @property {string} title - Nama lengkap repositori (owner/repo) |
| 20 | * @property {string} desc - Deskripsi repositori |
| 21 | * @property {string} lang - Bahasa pemrograman utama |
| 22 | * @property {string} starsToday - Jumlah perolehan bintang hari ini |
| 23 | */ |
| 24 | |
| 25 | /** |
| 26 | * Mengambil daftar repositori trending dari GitHub secara asinkron. |
| 27 | * |
| 28 | * @param {number} [limit=5] - Jumlah repositori maksimum yang ingin diekstrak |
| 29 | * @returns {Promise<TrendingRepo[]>} Daftar repositori yang sedang tren |
| 30 | */ |
| 31 | export async function fetchGitHubTrending(limit = 5) { |
| 32 | try { |
| 33 | const res = await fetch('https://github.com/trending', { |
| 34 | headers: { |
| 35 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36', |
| 36 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' |
| 37 | }, |
| 38 | signal: AbortSignal.timeout(8000) |
| 39 | }) |
| 40 | |
| 41 | if (!res.ok) throw new Error(`HTTP ${res.status}`) |
| 42 | const html = await res.text() |
| 43 | const $ = cheerio.load(html) |
| 44 | const repos = [] |
| 45 | |
| 46 | $('article.Box-row').slice(0, limit).each((_, el) => { |
| 47 | const rawTitle = $(el).find('h2 a').text().replace(/\s+/g, ' ').trim() |
| 48 | const title = rawTitle.replace(/\s*\/\s*/g, '/') |
| 49 | const desc = $(el).find('p').text().replace(/\s+/g, ' ').trim() |
| 50 | const lang = $(el).find('[itemprop="programmingLanguage"]').text().trim() || 'Tech' |
| 51 | const starsToday = $(el).find('span.d-inline-block.float-sm-right').text().replace(/\s+/g, ' ').trim() || '' |
| 52 | |
| 53 | if (title) { |
| 54 | repos.push({ |
| 55 | title, |
| 56 | desc: desc || 'Proyek open-source populer di GitHub', |
| 57 | lang, |
| 58 | starsToday |
| 59 | }) |
| 60 | } |
| 61 | }) |
| 62 | |
| 63 | if (repos.length > 0) return repos |
| 64 | } catch (e) { |
| 65 | console.warn('[GitHub Trending Scraper] Galat jaringan/DOM, beralih ke fallback:', e.message) |
| 66 | } |
| 67 | |
| 68 | return [ |
| 69 | { title: 'Open-source AI Tools', desc: 'Perkembangan pesat model reasoning AI & tool coding otonom di komunitas open-source.', lang: 'AI / Python', starsToday: '๐ฅ Trending' }, |
| 70 | { title: 'Modern Web & Lightweight Frameworks', desc: 'Tren transisi ke framework fullstack yang lebih cepat dengan memory footprint kecil.', lang: 'TypeScript / Rust', starsToday: '๐ฅ Trending' }, |
| 71 | { title: 'Local LLM & Edge Inference', desc: 'Inovasi menjalankan model AI besar langsung di laptop/HP tanpa GPU server mahal.', lang: 'C++ / ONNX', starsToday: '๐ฅ Trending' } |
| 72 | ] |
| 73 | } |
| 74 | |
| 75 | export default { |
| 76 | fetchGitHubTrending |
| 77 | } |
| 78 | |
| 79 | // Eksekusi mandiri untuk pengujian langsung tanpa argumen CLI |
| 80 | if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { |
| 81 | try { |
| 82 | const repos = await fetchGitHubTrending(3) |
| 83 | console.log(JSON.stringify(repos, null, 2)) |
| 84 | } catch (err) { |
| 85 | console.error('Galat eksekusi:', err.message || err) |
| 86 | } |
| 87 | } |
| 88 | |
| 89 | |
Discussion & Comments0
No comments yet โ be the first to leave feedback or start a code discussion.
Sign in with your GitHub account to write comments and join the discussion.