目录
  1. 1. 安装Node.js
  2. 2. 引入模块
    1. 2.1. HTTP/HTTPS
    2. 2.2. FS
    3. 2.3. cheerio
  3. 3. 安装依赖
  4. 4. 爬取数据
  5. 5. 爬取多页数据
  6. 6. 保存到本地文件
  7. 7. 数据整理和清洗
Node.js爬取豆瓣电影Top250

用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) // 运行方法

文章作者: Hyman Choi
文章链接: http://yoursite.com/2019/08/30/Node.js爬取豆瓣电影Top250/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 凌晨四点的拖拉机