用Node.js爬取豆瓣电影Top250数据,并简单储存到本地文件。
安装Node.js
根据系统类型,选择对应版本,其中LTS为长期支持版本,Current为当前发布版本。
Node.js官网下载
引入模块
1 2 3
| const https = require('https'); const fs = require('fs'); const cheerio = require('cheerio');
|
HTTP/HTTPS
HTTP 和 HTTPS 都为 Node.js 的内置模块,用于 HTTP 服务器和客户端。
用 HTTP 还是 HTTPS?
看要爬的网站是使用协议,豆瓣使用的协议是 HTTPS。
FS
FS 为 Node.js 的内置模,用于以模仿标准 POSIX 函数的方式与文件系统进行交互。
cheerio
cheerio 为快速,灵活和精简的核心 jQuery 实现,专为服务器而设计。
安装依赖
npm install cheerio
HTTPS 和 FS 是Node.js内置模块,无需另外安装依赖,安装Node.js后便可直接使用。
爬取数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| // 豆瓣电影Top250第一页 URL let url = 'https://movie.douban.com/top250?start=0&filter='; let Info = [];
https.get(url, res => { let chunks = [];
// 将请求到的数据放入 chunk 中 res.on('data', chunk => { chunks.push(chunk); });
res.on('end', () => { // 将 chunk 的所有 Buffer 对象合并为一个 Buffer 对象 let html = Buffer.concat(chunks);
// 用 $ 来选择元素,decodeEntities:false 用于防止出现中文乱码 let $ = cheerio.load(html, { decodeEntities: false });
// 爬取数据,注意用id或者唯一的class来选择元素 $('.grid_view .item .info').each(function (index, element) { let $element = $(element);
// 将选择的文本存入 Info 的 data 对象中 Info.push({ data: $element.text() }) })
// 输出爬取内容 console.log(Info); }); });
|
![文本结构.png]()
![爬取到的数据.png]()
爬取多页数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| // 豆瓣电影Top250前段相同的 URL let url = 'https://movie.douban.com/top250?start='; let Info = [];
let page = 0; // 第一页 let index = 1; // 初始化计数器
/* *函数描述 * *@param {number} page 当前爬取页数 */ function getTitles(page) { console.log("正在抓取第" + index + "页");
// 将变量 page添加至 URL 中 https.get(url + page + '&filter=', res => { let chunks = []; res.on('data', chunk => { chunks.push(chunk); });
res.on('end', () => { // 将 chunk 的所有 Buffer 对象合并为一个 Buffer 对象 let html = Buffer.concat(chunks);
// 用 $ 来选择元素,decodeEntities:false 用于防止出现中文乱码 let $ = cheerio.load(html, { decodeEntities: false });
// 爬取数据,注意用id或者唯一的class来选择元素 $('.grid_view .item .info').each(function (index, element) { let $element = $(element);
// 将选择的文本存入 Info 的 data 对象中 Info.push({ data: $element.text() }) }) // 一直爬到第十页,一页显示25部电影 if (page < 225) { // 翻到下一页 page += 25; index++; getTitles(page); } else { console.log("Info获取完毕!"); } }); }); }
getTitles(page) // 运行方法
|
保存到本地文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
| // 豆瓣电影Top250前段相同的 URL let url = 'https://movie.douban.com/top250?start='; let Info = [];
let page = 0; // 第一页 let index = 1; // 初始化计数器
/* *函数描述 * *@param {number} page 当前爬取页数 */ function getTitles(page) { console.log("正在抓取第" + index + "页");
// 将变量 page添加至 URL 中 https.get(url + page + '&filter=', res => { let chunks = []; res.on('data', chunk => { chunks.push(chunk); });
res.on('end', () => { // 将 chunk 的所有 Buffer 对象合并为一个 Buffer 对象 let html = Buffer.concat(chunks);
// 用 $ 来选择元素,decodeEntities:false 用于防止出现中文乱码 let $ = cheerio.load(html, { decodeEntities: false });
// 爬取数据,注意用id或者唯一的class来选择元素 $('.grid_view .item .info').each(function (index, element) { let $element = $(element);
// 将选择的文本存入 Info 的 data 对象中 Info.push({ data: $element.text() }) }) // 一直爬到第十页,一页显示25部电影 if (page < 225) { // 翻到下一页 page += 25; index++; getTitles(page); } else { console.log("Info获取完毕!"); // 将爬取的数据保存至当前目录 data 文件夹下的 Info.json 文件,必须先创建文件后才能保存 saveData('./data/Info.json', Info); } }); }); }
/* *函数描述 * *@param {string} path 存储文件路径 *@param {array} content 爬取数据 *@return {object} 错误返回 */ function saveData(path, content) { fs.writeFile(path, JSON.stringify(content, null, ' '), function (err) { if (err) { return console.log(err); } console.log('数据已保存!'); }); }
getTitles(page) // 运行方法
|
数据整理和清洗
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| // 豆瓣电影Top250前段相同的 URL let url = 'https://movie.douban.com/top250?start='; let Info = [];
let page = 0; // 第一页 let index = 1; // 初始化计数器
/* *函数描述 * *@param {number} page 当前爬取页数 */ function getTitles(page) { console.log("正在抓取第" + index + "页");
// 将变量 page添加至 URL 中 https.get(url + page + '&filter=', res => { let chunks = []; res.on('data', chunk => { chunks.push(chunk); });
res.on('end', () => { // 将 chunk 的所有 Buffer 对象合并为一个 Buffer 对象 let html = Buffer.concat(chunks);
// 用 $ 来选择元素,decodeEntities:false 用于防止出现中文乱码 let $ = cheerio.load(html, { decodeEntities: false }); // 爬取数据,注意用id或者唯一的class来选择元素 // 中文标题 $('.grid_view .item .info .title:nth-child(1)').each(function (index, element) { let $element = $(element);
// 将选择的文本存入 Info 的 data 对象中 Info[page + index] = { "ChineseTitles": $element.text() }; })
// 英文标题 $('.grid_view .item .info .title:nth-child(2)').each(function (index, element) { let $element = $(element); Info[page + index].EnglishTitles = $element.text().replace('/', '').trim(); })
// 其他标题 $('.grid_view .item .info .other').each(function (index, element) { let $element = $(element); let arr = $element.text().split('/').filter(d => d.trim()).map(d => d.replace(/^\s+|\s+$/g, "")); Info[page + index].OtherTitles = arr; }) // 一直爬到第十页,一页显示25部电影 if (page < 225) { // 翻到下一页 page += 25; index++; getTitles(page); } else { console.log("Info获取完毕!"); // 将爬取的数据保存至当前目录 data 文件夹下的 Info.json 文件,必须先创建文件后才能保存 saveData('./data/Info.json', Info); } }); }); }
/* *函数描述 * *@param {string} path 存储文件路径 *@param {array} content 爬取数据 *@return {object} 错误返回 */ function saveData(path, content) { fs.writeFile(path, JSON.stringify(content, null, ' '), function (err) { if (err) { return console.log(err); } console.log('数据已保存!'); }); }
getTitles(page) // 运行方法
|