学习笔记

对 Puppeteer 进行了一个练习,记录一下笔记代码:

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
let puppeteer = require('puppeteer')

async function test() {
// puppeteer.launch实例开启浏览器,可以传入一个options对象,可以配置为无界面浏览器,也可以配置为有界面浏览器
// 无界面浏览器性能更好
let options = {
// 设置视窗宽高
defaultViewport: {
width: 1920,
height: 1080,
},
// 设置为有界面,无界面为true
headless: false,
// 设置每个每个步骤的延迟时间
slowMo: 300,
}
let browser = await puppeteer.launch(options)
// 打开新页面
const page = await browser.newPage()
// 访问页面
await page.goto('https://www.dytt8.net/index.htm')

// 获取页面对象
// elementHandles = await page.$$("#menu li a");
// // 点击页面对象进行跳转
// elementHandles[2].click()

// 通过表单输入进行搜索
InputEle = await page.$('.searchl .formhue')
// 让光标聚焦到搜索框
await InputEle.focus()
// 在搜索框输入内容
await page.keyboard.type('蝙蝠侠')
// 添加一个绑定事件来取消掉点击时候触发广告
await page.$eval('.bd3rl .search', (element) => {
element.addEventListener('click', (event) => (event.cancelBubble = true))
})
// 点击按钮搜索
let btn = await page.$('.searchr input[name = "Submit"]')
await btn.click()
// 截屏
// await page.screenshot({path:'screenshot.png'})
// $$eval函数使我们的回调函数可以运行在浏览器中,并且可以通过浏览器的方式进行输出
// let elements =await page.$$eval('#menu li a',(elements) => {
// // 创建一个数组收集元素的信息,这里收集的是地址和url
// let eles = []
// elements.forEach(function(item,i){
// if(item.getAttribute('href')!='#'){
// var eleObj = {
// href: item.getAttribute('href'),
// text: item.innerText
// }
// eles.push(eleObj)
// }
// console.log(eleObj);
// })
// return eles
// })
// 浏览器的内容可以监听控制台输出
// page.on('console',function(eventMsg){
// // console.log(eventMsg.text());
// })
// 打开国内页面
// let gnPage = await browser.newPage()
// await gnPage.goto(elements[2].href)
}
test()

node演示

node演示

图片演示

实战代码

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
let puppeteer = require('puppeteer')
let url = require('url')
let fs = require('fs')

// 目标:抓取https://sobooks.cc/网站下 所有电子书的书名和下载链接
// 实现思路:
// 1.进入网站,获取整个网站的列表页的页数
// 2.获取列表页所有的连接
// 3.进入每个电子书的详情页获取下载电子书的网盘地址
// 4.将获取的数据保存到book.txt

// 目标地址:
let httpUrl = 'https://sobooks.cc/'

// 浏览器
;(async function () {
// 配置options
let debugOptions = {
// 设置视窗宽高
defaultViewport: {
width: 1400,
height: 720,
},
// 设置为有界面,无界面为true
headless: false,
// 设置每个每个步骤的延迟时间
slowMo: 300,
}
let options = { headless: true }
// 启动浏览器
let browser = await puppeteer.launch(options)

function wait(millSeconds) {
return new Promise(function (resolve, reject) {
setTimeout(() => {
resolve('成功执行延迟函数,延迟时间:' + millSeconds)
}, millSeconds)
})
}

async function getAllNum(link) {
let page = await browser.newPage()
await page.goto(link)
await page.setRequestInterception(true)
// 监听请求事件,并对请求进行拦截
page.on('request', (interceptedRequest) => {
// 通过URL模块对请求的地址进行解析
let urlObj = url.parse(interceptedRequest.url())
if (urlObj.hostname == 'googleads.g.doubleclick.net') {
// 如果是谷歌的广告太慢了
interceptedRequest.abort()
} else {
interceptedRequest.continue()
}
})
// 获取总页数
let pageNum = await page.$eval(
'.pagination li:last-child span',
(element) => {
// let text = element.innerHTML.split(' ')[1]
let text = element.innerHTML
.substring(1, element.innerHTML.length - 2)
.trim()
return text
}
)
return pageNum
}

// let pageNum = await getAllNum()
// console.log(pageNum);

// 进入列表页
async function pageList(num) {
let pageListUrl = 'https://sobooks.cc/page/' + num
// 打开一个新页面
let page = await browser.newPage()

// 在新页面中访问列表页地址
await page.goto(pageListUrl)
await page.setRequestInterception(true)
// 监听请求事件,并对请求进行拦截
page.on('request', (interceptedRequest) => {
// 通过URL模块对请求的地址进行解析
let urlObj = url.parse(interceptedRequest.url())
if (urlObj.hostname == 'googleads.g.doubleclick.net') {
// 如果是谷歌的广告太慢了
interceptedRequest.abort()
} else {
interceptedRequest.continue()
}
})
let arrPage = await page.$$eval(
'.card .card-item .thumb-img>a',
(elements) => {
let arr = []
elements.forEach((element, i) => {
var obj = {
href: element.getAttribute('href'),
title: element.getAttribute('title'),
}
arr.push(obj)
})
console.log(arr)
return arr
}
)
page.close()
// 通过获取的数组的地址和标题请求详情页
arrPage.forEach(async (pageObj, i) => {
await wait(500 * i)
getPageInfo(pageObj)
})
}

async function getPageInfo(pageObj) {
let page = await browser.newPage()
await page.goto(pageObj.href)
// 截取谷歌请求
await page.setRequestInterception(true)
// 监听请求事件,并对请求进行拦截
page.on('request', (interceptedRequest) => {
// 通过URL模块对请求的地址进行解析
let urlObj = url.parse(interceptedRequest.url())
if (urlObj.hostname == 'googleads.g.doubleclick.net') {
// 如果是谷歌的广告太慢了
interceptedRequest.abort()
} else {
interceptedRequest.continue()
}
})
let eleA = await page.$('.dltable tr:nth-child(3) a:last-child')
let aHref = await eleA.getProperty('href')
aHref = aHref._remoteObject.value
aHref = aHref.split('?url=')[1]
let content = `{\n"title":"${pageObj.title}",\n"href":"${aHref}"\n}\n`
fs.writeFile('book.txt', content, { flag: 'a' }, () => {
console.log('正在写入数据:' + pageObj.title)
page.close()
})
}

async function spider(link) {
let allPageNum = await getAllNum(link)
console.log('成功获取页面总数:' + allPageNum)

for (let i = 1; i <= allPageNum; i++) {
await wait(4000 * i) // 每个页面延迟3秒
pageList(i)
}
}
spider(httpUrl)
})()

node演示

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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
let puppeteer = require('puppeteer')
let url = require('url')
let fs = require('fs')
let { fsRead, fsWrite, fsDir } = require('./rw')
let axios = require('axios')
// 目标:下载电子书
// 目标地址:
let httpUrl = 'https://sobooks.cc/'
// 浏览器
;(async function () {
// 配置options
let debugOptions = {
// 设置视窗宽高
defaultViewport: {
width: 1400,
height: 800,
},
// 设置为有界面,无界面为true
headless: false,
// 设置每个每个步骤的延迟时间
slowMo: 300,
}
let options = { headless: true }
// 启动浏览器
let browser = await puppeteer.launch(debugOptions)

function wait(millSeconds) {
return new Promise(function (resolve, reject) {
setTimeout(() => {
resolve('成功执行延迟函数,延迟时间:' + millSeconds)
}, millSeconds)
})
}
async function parseTxt() {
// 读取文本内容
let textContent = await fsRead('./book.txt')
// 正则匹配字符串
let reg = /(\{.*?\})/gis
var tempRes
let bookArr = []
while ((tempRes = reg.exec(textContent))) {
// 获取匹配结果
let jsonStr = tempRes[1]
// 将字符串解析成对象
let jsonObj = JSON.parse(jsonStr)
// 获取连接属性
// let bookHreg = jsonObj.href;
await bookArr.push(jsonObj)
// downloadBook(jsonObj)
}
return bookArr
}
let bookArr = await parseTxt()
let index = 0
async function downloadBook() {
// 根据索引值下载电子书
if (index == bookArr.length) {
return '下载完成'
}
let bookObj = bookArr[index]
index++
// 打开新页面下载
let page = await browser.newPage()
await page.goto(bookObj.href)
// 因为是JS渲染出来的内容,并不是页面请求回来就有的内容,而是js通过ajax访问后台才渲染回来的所以我们需要做一个等待操作
await page.waitForSelector('#table_files tbody .even a', { visible: true })
// 找到下载链接对象,
let elementAHref = await page.$eval(
'#table_files tbody .even a',
(element) => {
return element.getAttribute('href')
}
)
bookLinkPage(elementAHref, bookObj.title)
page.close()
}
async function bookLinkPage(link, title) {
let page = await browser.newPage()
await page.setRequestInterception(true)
// 监听请求事件,并对请求进行拦截
page.on('request', (interceptedRequest) => {
// 通过URL模块对请求的地址进行解析
let urlObj = url.parse(interceptedRequest.url())
if (urlObj.hostname == 'u066.164-ctc-dd.tv002.com') {
console.log('截获下载地址:' + urlObj.href)
interceptedRequest.abort()
let ws = fs.createWriteStream('./book/' + title + '.epub')
axios.get(urlObj.href, { responseType: 'stream' }).then(function (res) {
res.data.pipe(ws)
ws.on('close', function () {
console.log('下载完成:' + title)
})
})
// 下完一本再下另一本
downloadBook()
page.close()
} else {
interceptedRequest.continue()
}
})
await page.goto('https://590m.com' + link)
await page.waitForSelector('.btn.btn-outline-secondary.fs--1')
let btn = await page.$('.btn.btn-outline-secondary.fs--1')
await btn.click()
}
downloadBook()
})()

这个下载代码好像还有点问题,主要是有广告页和验证码弹出来。