别再手动查电影了!教你用Node.js + 豆瓣API打造个人微信电影机器人
2026/6/4 2:33:22 网站建设 项目流程

用Node.js构建智能电影助手:从豆瓣API到微信机器人实战

上周五晚上,朋友突然发微信问我:"最近有什么值得看的科幻片?"我正想打开豆瓣App查一查,突然意识到——为什么不把这个过程自动化?三个小时后,我的微信里多了一个能随时回答这类问题的机器人助手。本文将分享如何从零开始,用Node.js打造这样一个智能电影查询系统。

1. 项目架构设计与技术选型

整个系统可以分为三个核心模块:数据获取层业务逻辑层交互呈现层。我们先从技术选型开始:

graph TD A[微信客户端] -->|发送消息| B[Wechaty机器人] B -->|解析指令| C[业务逻辑处理器] C -->|调用| D[豆瓣API封装模块] D -->|返回数据| C C -->|生成回复| B B -->|返回消息| A

关键技术栈选择

  • 机器人框架:Wechaty(支持微信个人号API)
  • HTTP客户端:Axios(处理豆瓣API请求)
  • 依赖管理:npm/yarn
  • 运行环境:Node.js 14+

提示:豆瓣API有调用频率限制(40次/分钟),生产环境建议添加缓存层

安装基础依赖:

npm init -y npm install wechaty axios memory-cache

2. 豆瓣API服务封装

我们需要先创建一个可靠的豆瓣电影服务模块。新建doubanService.js

const axios = require('axios'); const cache = require('memory-cache'); const API_KEY = '0b2bdeda43b5688921839c8ecb20399b'; const BASE_URL = 'https://api.douban.com/v2/movie'; // 带缓存的请求封装 async function cachedRequest(url, ttl = 60 * 1000) { const cached = cache.get(url); if (cached) return cached; const response = await axios.get(url); cache.put(url, response.data, ttl); return response.data; } module.exports = { // 获取热映电影 getInTheaters: async (city = '北京', start = 0, count = 5) => { const url = `${BASE_URL}/in_theaters?apikey=${API_KEY}&city=${encodeURIComponent(city)}&start=${start}&count=${count}`; return cachedRequest(url); }, // 搜索电影 searchMovie: async (query, start = 0, count = 3) => { const url = `${BASE_URL}/search?apikey=${API_KEY}&q=${encodeURIComponent(query)}&start=${start}&count=${count}`; return cachedRequest(url); }, // 获取电影详情 getMovieDetail: async (id) => { const url = `${BASE_URL}/subject/${id}?apikey=${API_KEY}`; return cachedRequest(url); } };

API返回数据结构示例

字段类型说明示例
titlestring电影中文名"流浪地球"
original_titlestring电影原名"The Wandering Earth"
rating.averagenumber豆瓣评分7.9
genresarray电影类型["科幻", "灾难"]
yearstring上映年份"2019"

3. 微信机器人消息处理

创建主入口文件index.js,实现消息响应逻辑:

const { Wechaty } = require('wechaty'); const douban = require('./doubanService'); // 消息处理器 async function onMessage(msg) { if (msg.self()) return; // 忽略自己发的消息 const text = msg.text(); const room = msg.room(); // 私聊或@机器人的消息才处理 if (!room || (room && text.includes('@电影助手'))) { try { let reply = await processMovieQuery(text); await msg.say(reply); } catch (err) { console.error(err); await msg.say('查询失败,请稍后再试~'); } } } // 解析电影查询指令 async function processMovieQuery(text) { // 匹配"最近有什么好电影?"类问题 if (/最近|有什么|推荐|好电影/.test(text)) { const data = await douban.getInTheaters(); return formatTheaters(data); } // 匹配"《XXX》评分"类问题 const match = text.match(/《(.+?)》|"(.+?)"/); if (match) { const name = match[1] || match[2]; const data = await douban.searchMovie(name); if (data.subjects.length) { const detail = await douban.getMovieDetail(data.subjects[0].id); return formatMovieDetail(detail); } return `没找到《${name}》的相关信息呢~`; } return `试试这样问我: • "最近有什么好电影?" • "《流浪地球》评分多少?"`; } // 格式化热映电影回复 function formatTheaters(data) { let reply = `🎬 ${data.title}(共${data.total}部)\n\n`; data.subjects.forEach(movie => { reply += `▫️ ${movie.title}(${movie.rating.average}分) 类型:${movie.genres.join('/')} 主演:${movie.casts.slice(0,3).map(c => c.name).join('、')}\n\n`; }); return reply; } // 格式化电影详情回复 function formatMovieDetail(movie) { return `🎥 ${movie.title}(${movie.original_title}) ⭐ 评分:${movie.rating.average}/10(${movie.ratings_count}人评价) 📅 年份:${movie.year} | 国家:${movie.countries.join('/')} 🎭 类型:${movie.genres.join('、')} 👨‍💼 导演:${movie.directors.map(d => d.name).join('、')} 👥 主演:${movie.casts.slice(0,5).map(c => c.name).join('、')} 📖 简介:${movie.summary.substring(0, 100)}...`; } // 启动机器人 const bot = new Wechaty(); bot.on('message', onMessage); bot.start() .then(() => console.log('机器人启动成功')) .catch(e => console.error('启动失败', e));

4. 高级功能扩展

基础功能完成后,我们可以考虑添加以下增强特性:

4.1 分页查询优化

当用户查询结果较多时,实现交互式分页:

// 在processMovieQuery中添加 if (text === '下一页' && lastQuery) { const data = await douban.getInTheaters(lastQuery.city, lastQuery.start + 5); lastQuery.start += 5; return formatTheaters(data); }

4.2 个性化推荐

基于用户历史查询记录推荐相似电影:

const userPrefs = new Map(); function updateUserPref(userId, genre) { if (!userPrefs.has(userId)) { userPrefs.set(userId, new Map()); } const prefs = userPrefs.get(userId); genre.forEach(g => prefs.set(g, (prefs.get(g) || 0) + 1)); } // 在返回推荐时优先推荐用户偏好的类型

4.3 自动订阅提醒

用户可以订阅特定电影的上映提醒:

const subscriptions = new Map(); async function checkComingMovies() { const coming = await douban.getComingSoon(); coming.subjects.forEach(movie => { if (subscriptions.has(movie.id)) { subscriptions.get(movie.id).forEach(user => { bot.say(user, `您关注的《${movie.title}》已定档${movie.mainland_pubdate}!`); }); } }); } // 每6小时检查一次 setInterval(checkComingMovies, 6 * 60 * 60 * 1000);

5. 部署与运维建议

将机器人部署到服务器时,需要注意:

性能优化配置

项目推荐值说明
缓存时间5-10分钟平衡实时性与API限制
重试机制3次应对网络波动
超时设置3000ms避免长时间等待
日志记录完整记录便于问题排查

错误处理增强

// 在cachedRequest中添加重试逻辑 let retries = 3; while (retries--) { try { const response = await axios.get(url, { timeout: 3000 }); cache.put(url, response.data, ttl); return response.data; } catch (err) { if (retries === 0) throw err; await new Promise(resolve => setTimeout(resolve, 1000)); } }

实际部署中,我发现微信机器人有时会意外断开连接。最好的解决方案是使用pm2等进程管理工具,配合自动重启脚本:

pm2 start index.js --name "movie-bot" --restart-delay=3000

这个项目最有趣的部分是看到朋友们开始主动与机器人互动,甚至发展出了一些我没预料到的使用方式——有人用它来快速查询电影原声带信息,有人则用来检查某位演员的最新作品。技术真正的魅力,或许就在于它能以意想不到的方式连接人与人之间的兴趣和需求。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询