cookpad
cari resep, dan detail resep
2 Agustus 2026722 file
cookpad.jsjavascript · 118 baris
import axios from 'axios';import * as cheerio from 'cheerio';const client = axios.create({ baseURL: 'https://cookpad.com', timeout: 15000, headers: { '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', 'Accept-Language': 'id-ID,id;q=0.9,en;q=0.8' }});export async function search(query, page = 1) { const { data } = await client.get(`/id/cari/${encodeURIComponent(query)}`, { params: page > 1 ? { page } : undefined }); const $ = cheerio.load(data); const results = []; $('#search-recipes-list > li[id^="recipe_"]').each((_, el) => { const $el = $(el); const id = ($el.attr('id') || '').replace('recipe_', ''); if (!id) return; const title = $el.find('a.block-link__main').first().text().trim().replace(/\s+/g, ' '); if (!title) return; const author = $el.find('img[alt][title]').last().attr('alt') || $el.find('span.break-all span').last().text().trim() || null; const duration = $el.find('.mise-icon-time').parent().find('.mise-icon-text').first().text().trim() || null; const servings = $el.find('.mise-icon-user').parent().find('.mise-icon-text').first().text().trim() || null; const ingredientsPreview = []; const ingText = $el.find('[data-ingredients-redesign-target="ingredients"] .line-clamp-2').text() || ''; ingText.split('•').forEach(t => { const clean = t.trim(); if (clean && clean.length > 1) ingredientsPreview.push(clean); }); const image = $el.find('img[src*="cpcdn.com/recipes"]').attr('src') || null; results.push({ id, title, author, duration, servings, ingredientsPreview: ingredientsPreview.slice(0, 8), image, url: `https://cookpad.com/id/resep/${id}` }); }); return results;}export async function detail(idOrUrl) { const id = String(idOrUrl).match(/(\d+)/)?.[1] || idOrUrl; const { data } = await client.get(`/id/resep/${id}`); const $ = cheerio.load(data); let recipe = null; $('script[type="application/ld+json"]').each((_, el) => { try { const json = JSON.parse($(el).html()); if (json['@type'] === 'Recipe') recipe = json; } catch {} }); if (!recipe) throw new Error('Recipe not found'); return { id, title: recipe.name, description: recipe.description || '', image: Array.isArray(recipe.image) ? recipe.image[0] : recipe.image, author: recipe.author?.name || '', authorUrl: recipe.author?.url || '', yield: recipe.recipeYield || '', cuisine: recipe.recipeCuisine || '', datePublished: recipe.datePublished || '', ingredients: (recipe.recipeIngredient || []).map(i => i.trim()).filter(Boolean), steps: (recipe.recipeInstructions || []).map(s => { let images = []; if (Array.isArray(s.image)) images = s.image; else if (s.image) images = [s.image]; return { text: s.text || s, images }; }), url: `https://cookpad.com/id/resep/${id}` };}// CLIconst isMain = process.argv[1] && ( import.meta.url.endsWith(process.argv[1].replace(/\\/g, '/')) || process.argv[1].endsWith('cookpad.js'));if (isMain) { const args = process.argv.slice(2); (async () => { try { if (args[0] === 'detail' && args[1]) { console.log(JSON.stringify(await detail(args[1]), null, 2)); } else if (args[0]) { console.log(JSON.stringify(await search(args[0]), null, 2)); } else { console.log('Usage:'); console.log(' node cookpad.js "nasi goreng"'); console.log(' node cookpad.js detail 26390975'); } } catch (e) { console.error(e.message); process.exit(1); } })();}README.mdmarkdown · 27 baris
Komentar
Masuk untuk ikut berkomentar.
Belum ada komentar.