Last active
April 28, 2025 04:02
-
-
Save DungGramer/03b8820ea2b2b5430c8b1c8b3b23959d to your computer and use it in GitHub Desktop.
Get React content return to API
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const response = await fetch('/api/extract-react-content', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ | |
url: | |
iframe.url, | |
key: conversation.text.substring(key + 1, keyEnd) || '', | |
loginInfo: { | |
loginUrl: 'https://example.com' | |
'usernameSelector': '#username', | |
'passwordSelector': '#password', | |
'submitSelector': '#kc-login', | |
'username': 'username', | |
'password': 'password', | |
'waitForNavigation': true, | |
}, | |
}), | |
}); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// app/api/extract-react-content/route.ts | |
import { NextResponse } from 'next/server'; | |
import * as cheerio from 'cheerio'; | |
import puppeteer from 'puppeteer'; | |
async function launchBrowser() { | |
// return await puppeteer.launch({ headless: true }); | |
return await puppeteer.launch({ | |
headless: false, // Show the browser | |
slowMo: 50, // Slow down each operation by 50ms (optional, easier to see typing) | |
devtools: true, // Open Chrome DevTools automatically (optional) | |
args: ['--start-maximized'] // Start maximized window | |
}); | |
} | |
async function loginIfNeeded(page, loginInfo) { | |
if (!loginInfo) return; | |
const { | |
loginUrl, | |
usernameSelector, | |
passwordSelector, | |
submitSelector, | |
username, | |
password, | |
waitForNavigation = true, | |
} = loginInfo; | |
if ( | |
!loginUrl || | |
!usernameSelector || | |
!passwordSelector || | |
!submitSelector || | |
!username || | |
!password | |
) { | |
throw new Error('Incomplete login information provided'); | |
} | |
// Go to the login page | |
await page.goto(loginUrl, { waitUntil: 'networkidle2', timeout: 30000 }); | |
// Type username and password | |
await page.type(usernameSelector, username, { delay: 100 }); | |
await page.type(passwordSelector, password, { delay: 100 }); | |
// Click login button | |
await Promise.all([ | |
page.click(submitSelector), | |
waitForNavigation | |
? page.waitForNavigation({ waitUntil: 'networkidle2', timeout: 30000 }) | |
: Promise.resolve(), | |
]); | |
} | |
export async function GET(request) { | |
try { | |
const { searchParams } = new URL(request.url); | |
const url = searchParams.get('url'); | |
const key = searchParams.get('key'); | |
if (!url) { | |
return NextResponse.json({ error: 'URL parameter is required' }, { status: 400 }); | |
} | |
if (!key) { | |
return NextResponse.json({ error: 'Key parameter is required' }, { status: 400 }); | |
} | |
const browser = await launchBrowser(); | |
const page = await browser.newPage(); | |
await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 }); | |
await new Promise(resolve => setTimeout(resolve, 2000)); | |
const renderedHtml = await page.content(); | |
await browser.close(); | |
const $ = cheerio.load(renderedHtml); | |
let value = null; | |
$('.label-item').each((_, element) => { | |
const keyElement = $(element).find('.lb-key'); | |
if (keyElement.text() === key) { | |
value = $(element).find('.lb-value').text(); | |
return false; | |
} | |
}); | |
if (value === null) { | |
return NextResponse.json({ error: `No label found with key "${key}"` }, { status: 404 }); | |
} | |
return NextResponse.json({ key, value }); | |
} catch (error) { | |
console.error('Error processing React content:', error); | |
return NextResponse.json({ error: 'Failed to process the React content' }, { status: 500 }); | |
} | |
} | |
export async function POST(request) { | |
try { | |
const { url, key, selector, loginInfo } = await request.json(); | |
if (!url) { | |
return NextResponse.json({ error: 'URL parameter is required' }, { status: 400 }); | |
} | |
const browser = await launchBrowser(); | |
const page = await browser.newPage(); | |
// If login info provided, login first | |
await loginIfNeeded(page, loginInfo); | |
// Navigate to target page after login | |
await page.goto(url, { waitUntil: 'networkidle2', timeout: 30000 }); | |
await new Promise(resolve => setTimeout(resolve, 2000)); | |
let result; | |
if (selector) { | |
await page.waitForSelector(selector, { timeout: 5000 }).catch(() => { | |
console.warn(`Selector ${selector} not found`); | |
}); | |
result = await page.evaluate((sel) => { | |
const element = document.querySelector(sel); | |
return element ? element.textContent : null; | |
}, selector); | |
} else if (key) { | |
result = await page.evaluate((labelKey) => { | |
const labelItems = document.querySelectorAll('.label-item'); | |
for (const item of labelItems) { | |
const keyElement = item.querySelector('.lb-key'); | |
if (keyElement && keyElement.textContent === labelKey) { | |
const valueElement = item.querySelector('.lb-value'); | |
return valueElement ? valueElement.textContent : null; | |
} | |
} | |
return null; | |
}, key); | |
} else { | |
result = await page.content(); | |
} | |
await browser.close(); | |
if (result === null) { | |
return NextResponse.json( | |
{ | |
error: selector | |
? `No content found for selector "${selector}"` | |
: `No label found with key "${key}"`, | |
}, | |
{ status: 404 } | |
); | |
} | |
return NextResponse.json({ content: result }); | |
} catch (error) { | |
console.error('Error extracting React content:', error); | |
return NextResponse.json( | |
{ error: 'Failed to extract content from React application' }, | |
{ status: 500 } | |
); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// app/api/extract-label/route.ts | |
import { NextResponse, type NextRequest } from 'next/server'; | |
import * as cheerio from 'cheerio'; | |
export async function GET(request: NextRequest) { | |
const { searchParams } = new URL(request.url); | |
const url = searchParams.get('url'); | |
if (!url) { | |
return NextResponse.json({ error: 'URL parameter is required' }, { status: 400 }); | |
} | |
try { | |
// Fetch the external page | |
const response = await fetch(url); | |
const html = await response.text(); | |
console.log(`📕 html - 17:route.ts \n`, html); | |
const $ = cheerio.load(html); | |
const title = $('title').text(); | |
const paragraphs = $('p') | |
.map((i, el) => $(el).text()) | |
.get(); | |
const headings = $('h1, h2, h3') | |
.map((i, el) => $(el).text()) | |
.get(); | |
// Return the HTML content | |
return NextResponse.json({ content: html, title, paragraphs, headings }); | |
} catch (error) { | |
console.error('Error fetching iframe content:', error); | |
return NextResponse.json({ error: 'Failed to fetch content' }, { status: 500 }); | |
} | |
} | |
export async function POST(request) { | |
try { | |
const { url, html, key } = await request.json(); | |
if (!key) { | |
return NextResponse.json({ error: 'The "key" parameter is required' }, { status: 400 }); | |
} | |
let htmlContent = html; | |
// If URL is provided, fetch the HTML content | |
if (url && !html) { | |
const response = await fetch(url); | |
htmlContent = await response.text(); | |
} | |
if (!htmlContent) { | |
return NextResponse.json( | |
{ error: 'Either "url" or "html" must be provided' }, | |
{ status: 400 } | |
); | |
} | |
// Parse HTML with Cheerio | |
const $ = cheerio.load(htmlContent); | |
// Find the label-item div that contains the specified key | |
let value = null; | |
$('.label-item').each((_, element) => { | |
const keyElement = $(element).find('.lb-key'); | |
if (keyElement.text() === key) { | |
value = $(element).find('.lb-value').text(); | |
return false; // Break the loop if found | |
} | |
}); | |
if (value === null) { | |
return NextResponse.json({ error: `No label found with key "${key}"` }, { status: 404 }); | |
} | |
return NextResponse.json({ key, value }); | |
} catch (error) { | |
console.error('Error processing HTML:', error); | |
return NextResponse.json({ error: 'Failed to process the content' }, { status: 500 }); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment