年前帮朋友装个系统,朋友要安装Windows8,我去MSDN下载,那速度惨不忍睹,果断开个迅雷会员。

心想只下这么点资源岂不是浪费了?然后就有了我的第一个爬虫。

页面分析

menu list

一级列表红框内

当点击红框内的文字时,会出发AJAX请求。

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
[
{
"id": "379a811e-1ef3-4d37-952e-2baf4df9e4b3",
"name": "AutoCollage 2008"
},
{
"id": "bcac9258-b652-4c1a-a828-a4fe23cc47cb",
"name": "Expression 1"
},
{
"id": "8a451b0a-b0ee-49ed-afc4-a7dc28599dd8",
"name": "Expression 2"
},
{
"id": "0f75c79d-fb44-40cf-a627-52c0519b9cd0",
"name": "Expression 3"
},
{
"id": "d5325dd4-a557-4c35-b855-3d9ac72b55a9",
"name": "Expression 4"
},
{
"id": "81635ff2-60e9-448e-aa8d-7e62bd20e029",
"name": "Songsmith"
}
]

二级列表绿框内

当点击黑色文字的时候又会触发AJAX请求。

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
    {
"status": true,
"result": [
{
"id": "c5fe5be2-1c54-49a0-80fb-bfab286484eb",
"lang": "多国语言"
},
{
"id": "e15db4de-c094-4c50-822a-98ad50daba4f",
"lang": "英语"
},
{
"id": "041dbbd2-c198-4523-b438-590128265d82",
"lang": "中文 - 简体"
},
{
"id": "0c3d9de8-73e4-401b-b9b5-562fba62993d",
"lang": "中文 - 香港"
},
{
"id": "ae1d1974-ce57-4957-9d20-172bd2b34fd0",
"lang": "中文 - 繁体"
},
{
"id": "b6515fef-2a56-4bf3-af51-06cd8d4e5557",
"lang": "韩语"
}
]
}

三级语言列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"status": true,
"result": [
{
"id": "e953d299-3667-4153-a081-afc8f26ebead",
"name": "Windows 10 Language Pack (x64) - DVD (Multiple Languages)",
"post": "/Date(1438113330377)/",
"url": "ed2k://|file|mu_windows_10_language_pack_x64_dvd_6846438.iso|1370247168|ED038183115D03F8627F22593425F246|/"
},
{
"id": "f1345f3d-86de-4094-9298-0f54f0132e38",
"name": "Windows 10 Language Pack (x86) - DVD (Multiple Languages)",
"post": "/Date(1438113330377)/",
"url": "ed2k://|file|mu_windows_10_language_pack_x86_dvd_6846439.iso|963231744|D6EF0A816846D3758B0D23894DA84159|/"
}
]
}

四级获取文件详细信息

1
2
3
4
5
6
7
8
9
10
{
"status": true,
"result": {
"FileName": "en_windows_10_multiple_editions_x64_dvd_6846432.iso",
"DownLoad": "ed2k://|file|en_windows_10_multiple_editions_x64_dvd_6846432.iso|4083853312|E59F65B0C508FB1C1FAE337EDF83058E|/",
"PostDateString": "2015-07-29",
"SHA1": "60CCE9E9C6557335B4F7B18D02CFE2B438A8B3E2",
"size": "3.8GB"
}
}

思路

其实爬并不难,因为除了首页需要GET到之后进行分析,其它的数据都可以通过数据接口的方式进行获取。

创作

创建文件夹进如文件夹

1
2
3
npm init  # 生成Package.json 文件
npm install --save request request-promise cheerio # 安装插件
mkdir lib # 创建 lib 目录

我们现在lib目录下创建一个get.js 用于网络请求

URL 请求

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
const rp = require('request-promise')
, cheerio = require('cheerio')
;

function url(method, uri, form) { // URL 请求的唯一方法 所有的请求都需要这个方法来完成并返回数据

let opstions = {
method,
uri,
headers: {
'referer': 'https://msdn.itellyou.cn/' // 因为网站采用HTTPS 所以需要在请求头中加入Referer
}
}
if (form) {
opstions.form = form
}

return rp(opstions) // 返回Promise 实例
.then(body => {
return body // 返回请求内容
})
.catch(err => {
return err // 返回错误
})
}

首页获取

async 用于声明这是一个异步函数,需要等待 await 返回才会继续执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
async function topMenu() { 
const data = await url('GET', 'https://msdn.itellyou.cn/')
if (data.error) {
console.log(`error:${data.error}`)
return
}
const $ = cheerio.load(data) // 将获取到的数据载入到 cheerio 语法类似于jQiery 只是类似!
, $item = $('#accordion > .panel-primary') // 获取一级Menu
, $len = $item.length
, menuInfo = []
for (let i = 0; i < $len; i++) { // 进行遍历
menuInfo.push({
name: $('#accordion > .panel-primary a').eq(i).text(), //获取Menu 标题
id: $('#accordion > .panel-primary a').eq(i).attr('data-menuid') // 获取 menuid 请求的时候回用到
})
}

return menuInfo // 返回数据
}

二级菜单获取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
async function twoMenu() {
const data = await topMenu() // 等待上个函数返回结果
, len = data.length
for (let i = 0; i < len; i++) {
// 传入ID
let twoData = await url('POST', 'https://msdn.itellyou.cn/Category/Index', { id: data[i].id });

if (twoData.error) {
console.log(`error:${data.error}`)
return
}

console.log(`正在获取:${data[i].name} 列表`)

data[i].data = JSON.parse(twoData)
}

return data;
}

完整项目移步Github