nodejs抓取动态网页(Node.js里的爬取动态网页神器Puppeteer的好处)

优采云 发布时间: 2022-01-21 17:15

  nodejs抓取动态网页(Node.js里的爬取动态网页神器Puppeteer的好处)

  现在大部分网页都是动态网页。如果单纯的爬取网页的HTML文件,就无法爬取商品价格或后期需要加载的图片等重要信息,更别提那些疯狂的登录限制了。对于小型爬虫来说,分析那些复杂的脚本是不值得的,更何况网站会与时俱进。破解难度大,更新一次就得从头开始,大大增加了小爬虫的难度。

  不过好在Node.js中有这样一个神器,不用担心网站的登录限制和反爬虫措施,它可以在不改变的情况下响应所有的变化,而且大部分可以被简单的模拟用户破解*敏*感*词*。限制,是Puppeteer,谷歌出品的爬取动态网页神器。

  1.木偶师的优缺点

  Puppeteer 本质上是一个 chrome 浏览器,但它可以通过代码进行操作。比如模拟鼠标点击、键盘输入等操作,有点像按键精灵。一个网页很难区分是人类用户还是爬虫,所以无处可谈限制。

  它的美妙之处在于它很简单,非常简单,可能是所有可以爬取动态网页的库中最简单的。

  但缺点也很明显,就是速度慢,效率有点低。相当于每次运行都启动一个Chrome浏览器,所以它的运行效率远不如其他库,不适合大数据的爬取。但对于小爬行动物来说已经绰绰有余了。

  接下来,以我写的爬取jd产品页面的小爬虫为例,看看这有多简单。我写这个爬虫是为了买苹果的魔控板。看了一圈,发*敏*感*词*银岛的价格很诱人。这应该是金银岛上唯一值得一抢的商品了,只是数量稀少,拖了很久。一个会出现。

  于是想到了监控产品页面,一旦发现新的Magic Trackpad,就会弹出提醒。甚至可以实现自动竞价,不过我没写,毕竟我不想买除了触摸板以外的东西,所以无法测试是否能成功拍卖。

  好的,让我们开始吧!

  2.第一步是安装Puppeteer:

  先安装Puppeteer库,只用到这个库:

  npm install puppeteer

复制代码

  3.第二步,链接网页

  链接网页也很简单,只需要几行代码:

  //启动浏览器

const browers = await puppeteer.launch()

//启动新页面

const page = await browers.newPage()

//链接网址

await page.goto(url)

复制代码

  这样,链接就成功了!Puppeteer.launch() 也可以接收很多参数,但是这里我们只使用headless,默认为true,如果为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(),它不仅可以根据时间等待,还可以根据元素的加载进度等待。

  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(&#39;div.p-name&#39;).textContent

if(n.includes(&#39;妙控板&#39;)){

return true

} else {

return false

}

}

} catch (error) {

return false

}

})

if(!bool){

return console.log(&#39;网页已打开,不再监控&#39;)

}

await goods.then(async (b)=>{

if(b){

console.log(&#39;有货了!&#39;)

await page.waitFor(2000)

await browers.close()

return requestUrl(false)

} else {

console.log(&#39;还没货&#39;)

console.log(&#39;三十分钟后再尝试&#39;)

await page.waitFor(1800000)

await browers.close()

return requestUrl(true)

}

})

}

requestUrl(true)

复制代码

  也可以通过Github获取完整代码:/Card007/Nod...如果对你有帮助,请关注我,我会继续输出更多好的文章!

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线