在Puppeteer的evaluate方法中调用OpenAI API时出现openai未定义错误
Puppeteer evaluate中调用OpenAI API报ReferenceError: openai is not defined的解决方法
错误原因
- Puppeteer的
page.evaluate()回调函数运行在浏览器的JavaScript上下文,而你在Node.js环境中创建的openai实例属于Node上下文,两者完全隔离。 - 传递给
page.evaluate()的参数只能是可JSON序列化的数据(字符串、数字、普通对象等),像OpenAIApi这种包含方法和内部状态的复杂对象无法被序列化传递到浏览器上下文,因此浏览器环境中找不到openai变量。
正确解决方案
把浏览器上下文里获取的视频标题拿到Node环境中,再调用OpenAI API——这是最安全且合理的做法,能避免在浏览器中暴露API密钥。
修改后的代码:
import puppeteer from 'puppeteer'; import { Browser } from 'puppeteer'; import { Configuration } from 'openai'; import { OpenAIApi } from 'openai/dist/api'; import fs from 'fs/promises'; // 改用Promise版fs,适配async/await风格 const main = async () => { const configuration = new Configuration({ apiKey: process.env.OPENAI_SECRET_KEY, }); const openai = new OpenAIApi(configuration); const browser: Browser = await puppeteer.launch({ headless: false }); const page = await browser.newPage(); const url = `https://www.youtube.com/${"@t3dotgg"}/videos`; await page.goto(url); // 仅在浏览器上下文提取视频标题,返回纯数据给Node环境 const titles = await page.evaluate(() => { const videoObject = Array.from(document.querySelectorAll("div#contents.style-scope.ytd-rich-grid-row")); const data = videoObject.map((video: any) => ({ title: video.querySelector("h3 a")?.getAttribute("title"), // 可选链避免null报错 })); return data.slice(0, 10).map(obj => obj.title); // 直接返回标题数组 }); // 在Node环境调用OpenAI API const prompt = `The following is a list of youtube video titles. After reading the titles, you are given a topic to then write a similar title for. \nTITLES: ${titles.join('\n')}\n\nSIMILAR TITLE FOR TOPIC "${"Christmas Coding"}"`; const res = await openai.createCompletion({ model: 'text-davinci-003', prompt, temperature: 1, max_tokens: 256, top_p: 1, frequency_penalty: 0, presence_penalty: 0, }); const similarTitle = res.data.choices[0]!.text.trim(); console.log('生成的相似标题:', similarTitle); await browser.close(); await fs.writeFile('similarTitle.json', JSON.stringify({ similarTitle })); console.log('数据已写入文件!'); }; main();
关键修改点
- 简化
page.evaluate()逻辑,仅提取并返回纯标题数据,避免跨上下文传递复杂对象 - 将OpenAI API调用移至Node环境执行,保证API密钥安全
- 改用
fs/promises异步方法,与async/await代码风格统一 - 添加可选链
?.,避免DOM查询返回null时触发报错
内容的提问来源于stack exchange,提问作者mason
相关产品推荐
相关产品推荐

