使用Discord.js配合Nightmare抓取Instagram新帖推送至Discord如何实现
需求实现方案解答
Nightmare可行性说明
该需求可以通过Nightmare实现。你目前代码无法拿到对应数据的核心原因是Instagram的页面访问规则和渲染逻辑没有被兼容:未登录状态下访问Instagram公开账号主页会被拦截跳转到登录引导页,且Instagram页面为客户端渲染,你没有设置等待元素加载的逻辑,页面内容还没渲染完成就执行了取值操作,自然拿不到有效数据。
要基于Nightmare实现功能,需要补充以下逻辑:
- 首次运行时在Nightmare中模拟登录Instagram,保存cookie避免后续重复登录
- 访问目标账号页后添加元素等待逻辑,等待帖子容器
article标签加载完成再执行取值 evaluate方法内抓取第一条帖子的链接,格式为/p/[帖子ID]/,补全前缀即可得到完整帖子链接- 新增定时轮询逻辑,定时拉取账号页内容,将每次拿到的最新帖子ID和本地存储的上一条帖子ID比对,ID不一致即判定为有新帖发布,调用discord.js的消息发送接口推送到指定频道
当前代码输出null的原因
你当前代码重复创建了Nightmare实例,没有处理登录态、页面加载等待逻辑,未登录状态下页面甚至没有完成跳转渲染就执行了evaluate取值,所以返回null。
更稳定的替代方案
相比模拟浏览器爬虫,更推荐两种更稳定的实现方式:
- 使用Instagram官方Graph API,申请对应权限后订阅目标账号的帖子发布事件,拿到新帖数据后直接调用discord.js接口推送,不会受Instagram页面结构变动影响
- 使用RSS订阅工具生成目标Instagram账号的RSS源,搭配RSS监控工具触发Discord Webhook推送,不需要编写复杂的爬虫逻辑
参考修正代码(基于Nightmare)
const Nightmare = require('nightmare') const { Client, Intents } = require('discord.js'); const config = require("./config.json"); const accountName = 'worldstar' // 存储上一条帖子链接,用于比对新帖 let lastPostUrl = '' const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES] }); client.on('ready', async () => { console.log('Discord客户端已启动') // 每5分钟轮询一次,可根据需求调整间隔时长 setInterval(checkNewPost, 5 * 60 * 1000) // 启动时先执行一次检查 await checkNewPost() }) async function checkNewPost() { const nightmare = Nightmare({ show: false }) try { const postUrl = await nightmare // 建议首次登录后将cookie持久化存储,后续直接加载cookie跳过登录步骤,避免账号被限制 .goto(`https://www.instagram.com/accounts/login/`) .wait('input[name="username"]') .type('input[name="username"]', '替换为你的Instagram账号') .type('input[name="password"]', '替换为你的Instagram密码') .click('button[type="submit"]') .wait(5000) .goto(`https://www.instagram.com/${accountName}`) // 等待帖子链接元素加载完成 .wait('article a[href^="/p/"]') .evaluate(() => { // 取账号页第一条帖子的完整链接 const firstPost = document.querySelector('article a[href^="/p/"]') return firstPost ? `https://www.instagram.com${firstPost.getAttribute('href')}` : null }) .end() if (postUrl && postUrl !== lastPostUrl) { // 检测到新帖,推送到指定Discord频道 const targetChannel = await client.channels.fetch('替换为你的Discord频道ID') targetChannel.send(`Instagram账号@${accountName}发布了新帖:${postUrl}`) lastPostUrl = postUrl console.log('新帖推送完成', postUrl) } } catch (e) { console.error('检查新帖出错', e) } } client.login(config.token);
注意:上述代码需要替换为你自己的Instagram登录信息和Discord频道ID,频繁重复登录会触发Instagram的安全校验,建议登录后保存cookie到本地复用。
内容的提问来源于stack exchange,提问作者RasmonT
相关产品推荐
相关产品推荐

