写爬虫抓取页面是不是还需要等待页面有数据了才能抓取,那么页面渲染的这段时间(虽然不长但架不住多啊)是不是可以省去呢
基础不太了解的可以参考我这篇简单使用的文章
使用puppeteer抓取接口拦截ajax数据
这里有小伙伴就要说了我都知道接口了直接去请求不就完了吗,python,node,axios,原生的ajax那个不行啊
哈哈,那要是接口参数中有随机数呢,有随机时间点呢,有随机时间戳和uuid再混起来呢
分分钟怀疑人生
来看小说站的接口参数
咱们准备抓取的信息
图中标记的自上往下分别是:
- 书籍id
- 要抓取的信息
- 接口
- 接口地址
接口数据
怀疑人生的时候到了,来看请求参数
- 首先是 post 请求
- 再来分析Form Data数据
- bookID和user_id都没啥事
- timestamp这个参数是有一定间隔时间的时间戳
- 头大的是这个, sign, 黑人问号脸(这是个啥)
翻腾了好久找了一个js文件发现了sign的由来
- 还是个md5加密的
- 那么问题来了
- 这个r,通过这个接口可以知道它就是bookid了
- 小问题是这个有固定间隔时间的timestamp怎么获取,喜欢等待的小伙伴可以试试等等看,具体我也不知道,不过应该在10分钟以上了
- 大问题是这个bookKey是个啥啊,找遍了也没找到,我能怎么办,我也很绝望啊,没办法只能放大招了
在官网的api可以看到这么几个,直接上代码(详细说明在注释里)
代码关键的地方截图
结果截图
转载请附上本文章地址
const puppeteer = require('puppeteer');
const mongodb = require('mongodb')
// mongoDB
const mongo_url = 'mongodb://127.0.0.1:27017/book'
const mongoClient = mongodb.MongoClient
// 休眠函数
function sleep(second) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(' enough sleep~');
}, second);
})
}
// 站点地址url
var url = `http://t.shuqi.com/route.php?pagename=route.php#!/ct/cover/bid/6070553`
class Parse {
constructor() {
this.page = null
this.browser = null
this.bookMessage = {}
}
async init() {
// 构造浏览器对象
// 显示浏览器
this.browser = await puppeteer.launch({
'headless': false,
});
// 创建页面
this.page = await this.browser.newPage();
// 模拟浏览器信息
const UA = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36";
await Promise.all([
this.page.setUserAgent(UA),
// 允许执行js脚本
this.page.setJavaScriptEnabled(true),
// 页面视口大小
this.page.setViewport({width: 1100, height: 1080}),
]);
await this.getBook()
}
async getBook() {
// 打开页面
await this.page.goto(url);
let page = await this.page
// 等待页面请求完成
page.on('requestfinished', request => {
// 查看所有请求地址
// console.log(request.url)
// ajax
if (request.resourceType == "xhr") {
// 匹配所需数据的请求地址
if(request.url.indexOf('http://walden1.shuqireader.com/webapi/book/info') != -1) {
(async () => {
try {
// 获取数据并转为json格式
let res = await request.response();
let result = await res.json();
let res_data = result.data
// 接口数据中找到需要的数据
this.bookMessage = {
'book_name': res_data.bookName,
'book_summary': res_data.desc,
'author_name': res_data.authorName,
}
let data = await this.bookMessage
mongoClient.connect(mongo_url, (err, db) => {
db.collection('shuqi_test').insert(data,(err, result) => {
if(err) {
console.log('连接失败')
}
// 关闭浏览器
this.browser.close()
// 关闭数据库连接
db.close()
}
)
})
} catch(err) {
console.log(err)
}
})()
}
}
});
}
}
let parse = new Parse()
parse.init()
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。