别再手动找电影了!教你用Node.js + 豆瓣API打造个人电影推荐小工具
用Node.js构建智能电影推荐引擎从豆瓣API到个性化筛选每次打开流媒体平台面对海量内容却不知看什么作为开发者我们完全可以用技术解决这个选择困难症。本文将带你用Node.js打造一个能理解你心情的电影推荐工具告别无目的刷片时代。1. 环境搭建与基础配置工欲善其事必先利其器。我们先搭建好开发环境mkdir movie-recommender cd movie-recommender npm init -y npm install axios chalk inquirer figlet创建基础配置文件.env存放API密钥DOUBAN_API_KEYyour_api_key_here BASE_URLhttps://api.douban.com/v2/movie建议使用dotenv包加载环境变量require(dotenv).config(); const axios require(axios); const BASE_URL process.env.BASE_URL; const API_KEY process.env.DOUBAN_API_KEY;2. 核心API功能封装2.1 电影数据获取层我们先封装几个常用API调用方法async function fetchInTheaters(city 北京, start 0, count 10) { const url ${BASE_URL}/in_theaters?apikey${API_KEY}city${city}start${start}count${count}; const response await axios.get(url); return response.data.subjects; } async function fetchTop250(start 0, count 10) { const url ${BASE_URL}/top250?apikey${API_KEY}start${start}count${count}; const response await axios.get(url); return response.data.subjects; }2.2 数据过滤与排序实现评分过滤和随机选择逻辑function filterByRating(movies, minRating 7) { return movies.filter(movie movie.rating.average minRating); } function getRandomMovies(movies, count 3) { const shuffled [...movies].sort(() 0.5 - Math.random()); return shuffled.slice(0, count); }3. 交互式命令行界面使用inquirer创建友好CLIconst questions [ { type: list, name: mood, message: 今天想看什么类型的电影, choices: [轻松喜剧, 烧脑悬疑, 感人剧情, 刺激动作, 随便看看] }, { type: number, name: duration, message: 你有多长时间观影分钟, default: 120 } ];实现交互逻辑async function startCLI() { const answers await inquirer.prompt(questions); let movies []; switch(answers.mood) { case 轻松喜剧: movies await fetchByTag(喜剧); break; case 烧脑悬疑: movies await fetchTop250(); break; // 其他情况处理... } const filtered filterByDuration(movies, answers.duration); displayMovies(getRandomMovies(filtered)); }4. 数据展示优化4.1 终端表格输出使用console.table美化输出function displayMovies(movies) { const tableData movies.map(movie ({ 片名: movie.title, 评分: movie.rating.average, 导演: movie.directors.map(d d.name).join(, ), 主演: movie.casts.slice(0,3).map(c c.name).join(, ), 时长: ${Math.floor(Math.random() * 60) 90}分钟 // 模拟数据 })); console.table(tableData); }4.2 彩色终端输出添加chalk提升可读性const chalk require(chalk); console.log(chalk.bgBlue.white.bold( 今日推荐片单 )); console.log(chalk.green(✓ 已根据你的心情筛选));5. 进阶功能实现5.1 混合推荐算法结合多种因素进行推荐function hybridRecommend(movies, userPrefs) { return movies .map(movie { const score (movie.rating.average / 10) * 0.4 (matchGenres(movie, userPrefs.genres) ? 0.3 : 0) (matchYear(movie, userPrefs.yearRange) ? 0.2 : 0) (matchDirector(movie, userPrefs.favDirectors) ? 0.1 : 0); return {...movie, score}; }) .sort((a, b) b.score - a.score); }5.2 简易Web界面用Express快速搭建Web版const express require(express); const app express(); app.get(/recommend, async (req, res) { const type req.query.type || top250; const movies await fetchMovies(type); res.json(getRandomMovies(movies, 5)); }); app.listen(3000, () console.log(推荐服务已启动));6. 项目打包与部署6.1 可执行脚本配置在package.json中添加bin: { movie-recommend: ./cli.js }添加shebang到cli.js顶部#!/usr/bin/env node6.2 全局安装开发完成后可以发布到npm或全局安装npm link # 本地测试 npm publish # 发布到npm7. 错误处理与性能优化7.1 健壮的错误处理async function safeFetch(url) { try { const response await axios.get(url, { timeout: 5000 }); return response.data; } catch (error) { console.error(chalk.red(获取数据失败:), error.message); return { subjects: [] }; } }7.2 缓存机制实现使用内存缓存减少API调用const cache new Map(); async function fetchWithCache(url) { if (cache.has(url)) { return cache.get(url); } const data await safeFetch(url); cache.set(url, data); return data; }8. 实际应用场景扩展8.1 与日历集成读取日历安排推荐合适时长的电影function getFreeTimeFromCalendar() { // 模拟从日历API获取空闲时间 return { date: 2023-06-15, freeHours: 2.5 }; }8.2 观影记录分析function analyzeHistory(watchedMovies) { const genres {}; watchedMovies.forEach(movie { movie.genres.forEach(genre { genres[genre] (genres[genre] || 0) 1; }); }); return Object.entries(genres).sort((a,b) b[1]-a[1])[0][0]; }在开发过程中发现合理设置超时时间和重试机制能显著提升稳定性。对于频繁变动的数据如正在热映缓存时间不宜超过2小时。而Top250这类稳定数据可以缓存更久。