内容简介:现在网页大多是动态网页,如果只是单纯地通过爬取网页HTML文件,根本爬取不到需要后续加载的商品价格或图片等重要信息,更别谈那些丧心病狂的登录限制,对于小爬虫来说,去分析那些复杂的脚本得不偿失,更别谈网站还会与时俱进地更新,好不容易破解了,人家一更新又得从头来,这都大大提高了小爬虫的难度。但幸好,在Node.js里有那么一款神器,无惧网站的登录限制和反爬虫措施,以不变应万变,通过一招简单的模拟用户操作就能破解绝大部分限制,它就是由谷歌出品的爬取动态网页神器Puppeteer。Puppeteer本质上是一个ch
现在网页大多是动态网页,如果只是单纯地通过爬取网页HTML文件,根本爬取不到需要后续加载的商品价格或图片等重要信息,更别谈那些丧心病狂的登录限制,对于小爬虫来说,去分析那些复杂的脚本得不偿失,更别谈网站还会与时俱进地更新,好不容易破解了,人家一更新又得从头来,这都大大提高了小爬虫的难度。
但幸好,在Node.js里有那么一款神器,无惧网站的登录限制和反爬虫措施,以不变应万变,通过一招简单的模拟用户操作就能破解绝大部分限制,它就是由谷歌出品的爬取动态网页神器Puppeteer。
1.Puppeteer的好处和坏处
Puppeteer本质上是一个chrome浏览器,只不过可以通过代码进行各种操控。比如模拟鼠标点击、键盘输入等操作,有点像按键精灵,网页很难分清这是人类用户还是爬虫,所以限制也就无处谈起。
它的好处在于简单,非常简单,可能是在所有可以爬取动态网页的库里最简单的一个。
但坏处也很明显,那就是速度慢,效率有点低。它等于每次运行都会启动一个Chrome浏览器,所以运行效率上远远比不过其它库,并不适合爬取大数据。但对于小爬虫来说已经绰绰有余了。
接下来以我写过的爬取jd商品页面的小爬虫为例,来看看这款有多简单。 当初写这个爬虫是为了买苹果的妙控板,找了一圈后发现jd夺宝岛里的价格很诱人,这也应该是夺宝岛里唯一值得抢的商品,但是数量稀少,很久才会出现一个。
于是就想到了监控商品页面,一旦发现新的妙控板就弹出提醒。甚至还可以实现自动竞拍,但我没写,毕竟除了触控板以外我都不想买,没办法测试能否成功拍到。
OK,开始吧!
2.首先第一步要安装Puppeteer:
先安装Puppeteer库,用到的也就只有这个库:
npm install puppeteer 复制代码
3.第二步链接网页
链接网页也非常简单,只需要几行代码:
//启动浏览器 const browers = await puppeteer.launch() //启动新页面 const page = await browers.newPage() //链接网址 await page.goto(url) 复制代码
这样子就链接成功了!Puppeteer.launch()还可以接收很多参数,但这里我们用到的只有headless,默认为ture,如果是false的话会显示浏览器界面。我们可以利用这个特性实现弹出窗口提醒,一旦发现有符合条件的商品就将headless改成false。
4.爬取商品信息
在链接网页后接下来就是爬取商品信息,然后进行分析。
网址:妙控板
4.1获取相对应的元素标签
通过页面可以看到,一旦有同类商品会出现在旁边的同类夺宝里,我们只需要爬取那里的信息就行了,有两种方式:
一种是$eval,相当于js里的document.querySelector,只爬取符合的第一个元素;
另一种为$$eval,相当于js里的document.querySelectorAll,爬取所有符合的元素;
它们接收的第一个参数是元素地址,第二个参数是回调函数,操作和document.querySelector一样,来看代码:
//我们拿到同类夺宝里的所有子元素
const goods = page.$$eval('#auctionRecommend > div.mc > ul > li', ele => ele)
复制代码
4.2.分析商品信息
现在已经拿到了同类夺宝里所有商品的标签信息,接下来开始分析信息。 获取里面所有商品的名称,然后对照关键字是否存在,如果存在则将headless改为false弹出窗口提醒,如果不存在则在半小时后再次链接。
Puppeteer提供了一个等待命令page.waitFor(),不仅可以按时间等待,也可以按某个元素的加载进度进行等待。
const goods = page.$$eval('#auctionRecommend > div.mc > ul > li', el => {
//错误和关键字不存在都会返回false,接着循环
try {
for (let i = 0; i < el.length; i++) {
let n = el[i].querySelector('div.p-name').textContent
if(n.includes('妙控板')){
return true
} else {
return false
}
}
} catch (error) {
return false
}
})
if(!bool){
return console.log('网页已打开,不再监控')
}
await goods.then(async (b) => {
if(b){
console.log('有货了!')
await page.waitFor(2000)
await browers.close()
return requestUrl(false)
} else {
console.log('还没货')
console.log('三十分钟后再尝试')
await page.waitFor(1800000)
await browers.close()
return requestUrl(true)
}
})
复制代码
5.优化代码
对于这个小爬虫来说,损失的效率并不多,没什么优化的必要,但作为一个强迫症,还是希望能去掉的尽量去掉。
5.1拦截图片
在这个爬虫里,我们根本不用看任何图片信息,所以所有图片都没有加载的必要,为了提升一点点运行效率,将所有图片拦截掉:
//开启拦截器
await page.setRequestInterception(true)
await page.on('request',interceptedRequest => {
//判断url是否以jpg或png结尾,符合条件将不再加载
if(interceptedRequest.url().endsWith('.jpg') || interceptedRequest.url().endsWith('.png')){
interceptedRequest.abort();
}else{
interceptedRequest.continue();
}
})
复制代码
5.2调整窗口大小
在浏览器弹出时,会发现打开的窗口显示范围很小,不仅不方便浏览,可能还会导致点击或输入等操作出错,所以还是有必要进行调整:
await page.setViewport({
width: 1920,
height: 1080,
})
复制代码
至此,所有代码已经完成了,快试试效果吧!
6.完整代码
const puppeteer = require('puppeteer')
const url = 'https://paipai.jd.com/auction-detail/114533257?entryid=p0120003dbdnavi'
const requestUrl = async function(bool){
const browers = await puppeteer.launch({headless:bool})
const page = await browers.newPage()
await page.setRequestInterception(true)
await page.on('request',interceptedRequest => {
if(interceptedRequest.url().endsWith('.jpg') || interceptedRequest.url().endsWith('.png')){
interceptedRequest.abort();
}else{
interceptedRequest.continue();
}
})
await page.setViewport({
width: 1920,
height: 1080,
})
await page.goto(url)
const goods = page.$$eval('#auctionRecommend > div.mc > ul > li', el=>{
try {
for (let i = 0; i < el.length; i++) {
let n = el[i].querySelector('div.p-name').textContent
if(n.includes('妙控板')){
return true
} else {
return false
}
}
} catch (error) {
return false
}
})
if(!bool){
return console.log('网页已打开,不再监控')
}
await goods.then(async (b)=>{
if(b){
console.log('有货了!')
await page.waitFor(2000)
await browers.close()
return requestUrl(false)
} else {
console.log('还没货')
console.log('三十分钟后再尝试')
await page.waitFor(1800000)
await browers.close()
return requestUrl(true)
}
})
}
requestUrl(true)
复制代码
也可以通过Github获取完整代码: github.com/Card007/Nod… 如果对你有帮助,欢迎关注我,我会持续输出更多好文章!
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 你配置 Webpack 4 的方式可能是错的!
- Smarty 3.1.32 修复路径组装方式中可能存在的安全漏洞
- MySQL数据库性能优化的八种方式,你可能都没用过!
- IPFS:区块链“不可能三角”的可能解 | 万向区块链小课堂
- 响应慢也有可能是SQL惹的祸:Limit可能会惹祸上身
- 私有链可能没有未来?
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Data Structures and Algorithms in Java
Robert Lafore / Sams / 2002-11-06 / USD 64.99
Data Structures and Algorithms in Java, Second Edition is designed to be easy to read and understand although the topic itself is complicated. Algorithms are the procedures that software programs use......一起来看看 《Data Structures and Algorithms in Java》 这本书的介绍吧!
HTML 压缩/解压工具
在线压缩/解压 HTML 代码
HEX CMYK 转换工具
HEX CMYK 互转工具