code wiki / _hdl_build / nx_html_extract_data.nx

nx_html_extract_data.nx source

↩ module page · 76 lines · 3866 B

1// nx_html_extract_data.nx -- JS-RENDER FETCHER rung 1: STRUCTURED-DATA EXTRACTION. 2// 3// Many "JS-rendered" pages embed content as JSON-LD (<script application/ld+json>) 4// + OpenGraph meta -- recoverable WITHOUT executing JS. Pulls prose fields 5// (headline/name/description/articleBody) AND og:description out of raw HTML so the 6// researcher can read JS sites' structured content. Reuses re_find/re_strlen (DRY). 7// HONEST SCOPE: embedded/SSR data only; fully client-fetched content needs rung 2 8// (API discovery) then rung 3 (a sovereign JS interpreter + DOM). license_tier: ORIGINAL. 9 10import "nx_syscalls.nx" 11import "nx_research_extract.nx" 12const K_MAGIC_65536: i64 = 65536 13 14// copy a JSON string value following keypat (e.g. "description":) into out: 15// skips optional spaces, requires an opening quote, reads to the closing quote 16// (handles \-escapes). Returns length (0 if absent / not a string value). 17func hed_field(html: *u8, n: i64, keypat: *u8, out: *u8, cap: i64) -> i64 { 18 let p: i64 = re_find(html, n, keypat) 19 if p < 0 { return 0 } 20 var i: i64 = p + re_strlen(keypat) 21 while i < n { if html[i] == (32 as u8) { i = i + 1 } else { break } } // skip optional spaces 22 if i >= n { return 0 } 23 if html[i] != (34 as u8) { return 0 } // value must be a string 24 i = i + 1 25 var k: i64 = 0 26 while i < n { 27 let c: u8 = html[i] 28 if c == (34 as u8) { i = n } 29 else { 30 if c == (92 as u8) { i = i + 1; if i < n { if k < cap - 1 { out[k] = html[i]; k = k + 1 } } i = i + 1 } 31 else { if k < cap - 1 { out[k] = c; k = k + 1 } i = i + 1 } 32 } 33 } 34 out[k] = 0 as u8 35 return k 36} 37 38// extract an HTML meta value: find marker (e.g. og:description), then the next 39// content="..." after it; reads until the matching quote. Returns length. 40func hed_meta(html: *u8, n: i64, marker: *u8, out: *u8, cap: i64) -> i64 { 41 let p: i64 = re_find(html, n, marker) 42 if p < 0 { return 0 } 43 let cp: i64 = re_find(html + p, n - p, "content=" as *u8) 44 if cp < 0 { return 0 } 45 var i: i64 = p + cp + 8 // past "content=" 46 var q: u8 = 34 as u8 // default closing quote = " 47 if i < n { if html[i] == (39 as u8) { q = 39 as u8 } } 48 if i < n { if html[i] == (34 as u8) { i = i + 1 } else { if html[i] == (39 as u8) { i = i + 1 } } } 49 var k: i64 = 0 50 while i < n { if html[i] == q { i = n } else { if k < cap - 1 { out[k] = html[i]; k = k + 1 } i = i + 1 } } 51 out[k] = 0 as u8 52 return k 53} 54 55func hed_app(out: *u8, off: *i64, s: *u8, slen: i64, cap: i64) -> i64 { 56 var i: i64 = 0 57 while i < slen { if off[0] < cap - 2 { out[off[0]] = s[i]; off[0] = off[0] + 1 } i = i + 1 } 58 if off[0] < cap - 2 { out[off[0]] = 10 as u8; off[0] = off[0] + 1 } 59 return 0 60} 61 62// extract JSON-LD prose + og:description from raw HTML -> out 63func nx_html_extract_data(html: *u8, n: i64, out: *u8, cap: i64) -> i64 { 64 let off: *i64 = (sys_mmap(8)) as *i64 65 off[0] = 0 66 let tmp: *u8 = sys_mmap(K_MAGIC_65536) 67 var L: i64 = 0 68 L = hed_field(html, n, "\"headline\":" as *u8, tmp, K_MAGIC_65536); if L > 0 { hed_app(out, off, tmp, L, cap) } 69 L = hed_field(html, n, "\"name\":" as *u8, tmp, K_MAGIC_65536); if L > 0 { hed_app(out, off, tmp, L, cap) } 70 L = hed_field(html, n, "\"description\":" as *u8, tmp, K_MAGIC_65536); if L > 0 { hed_app(out, off, tmp, L, cap) } 71 L = hed_field(html, n, "\"articleBody\":" as *u8, tmp, K_MAGIC_65536); if L > 0 { hed_app(out, off, tmp, L, cap) } 72 L = hed_meta(html, n, "og:description" as *u8, tmp, K_MAGIC_65536); if L > 0 { hed_app(out, off, tmp, L, cap) } 73 L = hed_meta(html, n, "og:title" as *u8, tmp, K_MAGIC_65536); if L > 0 { hed_app(out, off, tmp, L, cap) } 74 out[off[0]] = 0 as u8 75 return off[0] 76}