Back to Home
Gistify Snippet
kyiov
Sep 5·1 file(s)
Public

vanceai.js — scrape halaman tool VanceAI (meta + JSON-LD)

vanceai.js — scrape halaman tool VanceAI (meta + JSON-LD)

#github-gist#javascript#gist:9f69d12e75e708a972298c9ee1d4647f#gistsync:2026-09-04T02:20:26Z
3
Raw
vanceai.jsjavascript
136 lines
1// vanceai.js — scrape halaman tool VanceAI (make-photo-hd).
2// Ambil meta + JSON-LD (HowTo steps, FAQ, info tool). Pure JS.
3
4const TARGET = 'https://vanceai.com/make-photo-hd/'
5const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36'
6
7async function get(url) {
8 const res = await fetch(url, {
9 headers: { 'User-Agent': UA, Accept: 'text/html,*/*;q=0.9' },
10 redirect: 'follow',
11 signal: AbortSignal.timeout(60000),
12 })
13 if (!res.ok) throw new Error(`HTTP ${res.status} ${url}`)
14 return { status: res.status, text: await res.text() }
15}
16
17function meta(html, prop) {
18 let m = new RegExp(`<meta[^>]+(?:property|name)=["']${prop}["'][^>]+content=["']([^"']*)["']`, 'i').exec(html)
19 if (!m) m = new RegExp(`<meta[^>]+content=["']([^"']*)["'][^>]+(?:property|name)=["']${prop}["']`, 'i').exec(html)
20 return m ? m[1].replace(/&amp;/g, '&').trim() : ''
21}
22
23// ambil JSON-LD (@graph) dari halaman
24function ld(html) {
25 const m = /<script type="application\/ld\+json"[^>]*>([\s\S]*?)<\/script>/i.exec(html)
26 if (!m) return []
27 try {
28 const d = JSON.parse(m[1])
29 return Array.isArray(d) ? d : d['@graph'] || [d]
30 } catch {
31 return []
32 }
33}
34
35function howTo(graph) {
36 const h = graph.find((x) => x['@type'] === 'HowTo')
37 if (!h) return null
38 return {
39 name: h.name || '',
40 totalTime: h.totalTime || '',
41 steps: (h.step || []).map((s, i) => ({
42 no: i + 1,
43 name: s.name || '',
44 text: s.text || '',
45 })),
46 }
47}
48
49function faq(graph) {
50 const f = graph.find((x) => x['@type'] === 'FAQPage')
51 if (!f) return []
52 return (f.mainEntity || []).map((q) => ({
53 q: q.name || '',
54 a: q.acceptedAnswer?.text || '',
55 }))
56}
57
58function appInfo(graph) {
59 const a = graph.find((x) => x['@type'] === 'WebApplication')
60 if (!a) return {}
61 const pick = (o) => (o && o['@type'] === 'Offer' ? { price: o.price, currency: o.priceCurrency } : null)
62 return {
63 name: a.name || '',
64 url: a.url || '',
65 applicationCategory: a.applicationCategory || '',
66 operatingSystem: a.operatingSystem || '',
67 offers: (Array.isArray(a.offers) ? a.offers : [a.offers]).filter(Boolean).map(pick).filter(Boolean),
68 aggregateRating: a.aggregateRating || undefined,
69 }
70}
71
72const isDirectRun = process.argv[1] && import.meta.url === new URL(`file://${process.argv[1]}`).href
73
74if (isDirectRun) {
75 ;(async () => {
76 const args = process.argv.slice(2)
77 const asJson = args.includes('--json')
78 const url = args.find((a) => /^https?:\/\//i.test(a)) || TARGET
79
80 if (!asJson) {
81 console.log(`== vanceai scraper ==`)
82 console.log(`target : ${url}`)
83 }
84
85 try {
86 const page = await get(url)
87 const html = page.text
88 const graph = ld(html)
89 const data = {
90 url,
91 status: page.status,
92 title: meta(html, 'og:title') || meta(html, 'twitter:title'),
93 description: meta(html, 'description') || meta(html, 'og:description'),
94 canonical: meta(html, 'og:url'),
95 howto: howTo(graph),
96 faq: faq(graph),
97 app: appInfo(graph),
98 }
99
100 if (asJson) {
101 console.log(JSON.stringify(data, null, 2))
102 } else {
103 console.log(`\n== ${data.title || url} ==`)
104 if (data.description) console.log(`desc : ${data.description.slice(0, 200)}`)
105 if (data.app && data.app.aggregateRating) {
106 const r = data.app.aggregateRating
107 console.log(`rating : ${r.ratingValue} (${r.reviewCount} ulasan)`)
108 }
109 if (data.howto) {
110 console.log(`\nhow-to : ${data.howto.name}`)
111 data.howto.steps.forEach((s) => {
112 console.log(` ${s.no}. ${s.name}${s.text ? ' — ' + s.text.slice(0, 100) : ''}`)
113 })
114 }
115 if (data.faq.length) {
116 console.log(`\nfaq : ${data.faq.length} item`)
117 data.faq.forEach((f, i) => {
118 console.log(` ${i + 1}. ${f.q}`)
119 console.log(` ${f.a.slice(0, 160)}`)
120 })
121 }
122 console.log('\ndone')
123 }
124 } catch (e) {
125 console.error(`ERROR: ${e.message || e}`)
126 process.exit(1)
127 }
128 })()
129}
130
131/*
132 * USAGE
133 * node vanceai.js scrape make-photo-hd (URL di code)
134 * node vanceai.js <url> scrape tool VanceAI lain
135 * node vanceai.js --json json lengkap
136 */
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.