import { exec } from 'child_process' import { promisify } from 'util' import fs from 'fs' const execAsync = promisify(exec) const PYTHON_BRIDGE = ` import scrapling from scrapling.fetchers import StealthyFetcher from bs4 import BeautifulSoup import json import re def clean_code_block(text): raw_lines = text.split('\\n') cleaned_lines = [] current_line = [] for l in raw_lines: s = l.strip() if not s: if current_line: cleaned_lines.append(" ".join(current_line)) current_line = [] continue if s.startswith('#') or s.startswith('$') or s.startswith('>>>'): if current_line: cleaned_lines.append(" ".join(current_line)) current_line = [] cleaned_lines.append(s) else: current_line.append(s) if current_line: cleaned_lines.append(" ".join(current_line)) res = "\\n".join(cleaned_lines) res = re.sub(r'\\s+([,.:;\\]\\)\\}])', r'\\1', res) res = re.sub(r'([\\[\\(\\{])\\s+', r'\\1', res) res = re.sub(r'\\s*=\\s*', ' = ', res) res = re.sub(r'\\s*\\+\\=\\s*', ' += ', res) res = re.sub(r'\\s*\\-\\=\\s*', ' -= ', res) return res.strip() def fetch_cheatsheet(): try: fetcher = StealthyFetcher() page = fetcher.fetch('https://realpython.com/cheatsheets/python/', network_idle=True) if page.status != 200: print(json.dumps({"status": False, "error": f"HTTP {page.status}"})) return soup = BeautifulSoup(page.html_content, 'html.parser') title = "Python 3 Cheat Sheet" sections = [] # Blacklist of promotional keywords PROMO_WORDS = [ 'real python', 'show/hide', 'continue your learning', 'bonus', 'download this', 'newsletter', 'quizzes', 'podcast', 'get a python cheat', 'learning paths', 'video courses', 'written tutorials', 'interactive quizzes', 'do you want to go deeper' ] for sec_tag in soup.find_all('section', class_='section2'): h2 = sec_tag.find('h2') if not h2: continue sec_title = h2.get_text().strip() # Skip promotional sections if any(pw in sec_title.lower() for pw in ['related tutorial', 'bonus', 'resources', 'curriculum']): continue items = [] for child in sec_tag.find_all(['pre', 'p']): if child.name == 'pre': code_clean = clean_code_block(child.get_text()) if code_clean: items.append({'type': 'code', 'language': 'python', 'content': code_clean}) elif child.name == 'p': t = child.get_text().strip() if t and len(t) > 3 and not any(pw in t.lower() for pw in PROMO_WORDS): items.append({'type': 'text', 'content': t}) if any(it['type'] == 'code' for it in items): sections.append({ 'title': sec_title, 'items': items }) print(json.dumps({ "status": True, "title": title, "total_sections": len(sections), "sections": sections })) except Exception as e: print(json.dumps({"status": False, "error": str(e)})) if __name__ == "__main__": fetch_cheatsheet() ` let cacheCheatsheet = null let lastFetch = 0 export async function getPythonCheatSheet(forceRefresh = false) { const now = Date.now() if (!forceRefresh && cacheCheatsheet && (now - lastFetch < 3600000)) { return cacheCheatsheet } try { const tmpScript = '/tmp/rp_cheatsheet_clean.py' await fs.promises.writeFile(tmpScript, PYTHON_BRIDGE, 'utf-8') const { stdout } = await execAsync(`${process.env.SCRAPLING_PYTHON || "/tmp/scrapping-venv/bin/python"} ${tmpScript}`, { maxBuffer: 15 * 1024 * 1024 }) const json = JSON.parse(stdout.trim().split('\n').pop()) if (!json.status) throw new Error(json.error || 'Gagal mengekstrak cheatsheet.') cacheCheatsheet = json lastFetch = now return json } catch (e) { console.error('[RealPython CheatSheet Error]:', e.message) throw e } } export default { getPythonCheatSheet }