本篇文章主要介紹了Node Puppeteer圖像辨識實現百度指數爬蟲的範例,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟著小編過來看看吧
之前看過一篇腦洞大開的文章,介紹了各個大廠的前端反爬蟲技巧,但也正如此文所說,沒有100%的反爬蟲方法,本文介紹一種簡單的方法,來繞過所有這些前端反爬蟲手段。
下面的程式碼以百度指數為例,程式碼已經封裝成一個百度指數爬蟲node庫:https://github.com/Coffcer/baidu-index-spider
# note: 請勿濫用爬蟲給他人添麻煩
百度指數的反爬蟲策略
觀察百度指數的介面,指數資料是趨勢圖,當滑鼠懸浮在某一天的時候,會觸發兩個請求,將結果顯示在懸浮框裡面:
#按照常規思路,我們先看下這個請求的內容:
請求1:
請求2:
可以發現,百度指數其實在前端做了一定的反爬蟲策略。當滑鼠移動到圖表上時,會觸發兩個請求,一個請求傳回一段html,一個請求傳回一張產生的圖片。 html中並不包含實際數值,而是透過設定width和margin-left,來顯示圖片上的對應字元。而且請求參數上帶有res、res1這種我們不知如何模擬的參數,所以用常規的模擬請求或html爬取的方式,都很難爬到百度指數的資料。
爬蟲思路
怎麼突破百度這種反爬蟲方法呢,其實也很簡單,就是完全不去管他是如何反爬蟲的。我們只需模擬使用者操作,將需要的數值截圖下來,做圖像辨識就行。步驟大概是:
模擬登入
#開啟指數頁面
滑鼠移動到指定日期
等待請求結束,截取數值部分的圖片
#圖片辨識得到值
puppeteer 模擬瀏覽器操作
node-tesseract tesseract的封裝,用來做圖像辨識
#jimp 圖片裁切
安裝Puppeteer, 模擬使用者操作
Puppeteer是Google Chrome團隊出品的Chrome自動化工具,用來控制Chrome執行指令。可以模擬使用者操作,做自動化測試、爬蟲等。用法非常簡單,網路上有不少入門教程,順著本文看完也大概可以知道如何使用。 API文件: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md安裝:npm install --save puppeteer
npm config set PUPPETEER_DOWNLOAD_HOST=https://npm.taobao.org/mirrors npm install --save puppeteer
// npm npm install --save puppeteer --ignore-scripts // node puppeteer.launch({ executablePath: '/path/to/Chrome' });
實作
為版面整潔,下面只列出了主要部分,程式碼涉及selector的部分都用了...代替,完整程式碼參考文章頂部的github倉庫。開啟百度指數頁面,模擬登入
這裡做的就是模擬使用者操作,一步步點選並輸入。沒有處理登入驗證碼的情況,處理驗證碼又是另一個話題了,如果你在本機登入過百度,一般不需要驗證碼。// 启动浏览器, // headless参数如果设置为true,Puppeteer将在后台操作你Chromium,换言之你将看不到浏览器的操作过程 // 设为false则相反,会在你电脑上打开浏览器,显示浏览器每一操作。 const browser = await puppeteer.launch({headless:false}); const page = await browser.newPage(); // 打开百度指数 await page.goto(BAIDU_INDEX_URL); // 模拟登陆 await page.click('...'); await page.waitForSelecto('...'); // 输入百度账号密码然后登录 await page.type('...','username'); await page.type('...','password'); await page.click('...'); await page.waitForNavigation(); console.log(':white_check_mark: 登录成功');
模擬移動滑鼠,取得所需的資料
需要將頁面捲動到趨勢圖的區域,然後移動滑鼠到某個日期上,等待請求結束, tooltip顯示數值,再截圖儲存圖片。// 获取chart第一天的坐标 const position = await page.evaluate(() => { const $image = document.querySelector('...'); const $area = document.querySelector('...'); const areaRect = $area.getBoundingClientRect(); const imageRect = $image.getBoundingClientRect(); // 滚动到图表可视化区域 window.scrollBy(0, areaRect.top); return { x: imageRect.x, y: 200 }; }); // 移动鼠标,触发tooltip await page.mouse.move(position.x, position.y); await page.waitForSelector('...'); // 获取tooltip信息 const tooltipInfo = await page.evaluate(() => { const $tooltip = document.querySelector('...'); const $title = $tooltip.querySelector('...'); const $value = $tooltip.querySelector('...'); const valueRect = $value.getBoundingClientRect(); const padding = 5; return { title: $title.textContent.split(' ')[0], x: valueRect.x - padding, y: valueRect.y, width: valueRect.width + padding * 2, height: valueRect.height } });
截圖
計算數值的座標,截圖並用jimp對裁切圖片。await page.screenshot({ path: imgPath }); // 对图片进行裁剪,只保留数字部分 const img = await jimp.read(imgPath); await img.crop(tooltipInfo.x, tooltipInfo.y, tooltipInfo.width, tooltipInfo.height); // 将图片放大一些,识别准确率会有提升 await img.scale(5); await img.write(imgPath);
圖像識別
這裡我們用Tesseract來做圖像識別,Tesseracts是Google開源的一款OCR工具,用來識別圖片中的文字,並且可以透過訓練提高準確率。 github上已經有一個簡單的node封裝: node-tesseract ,需要你先安裝Tesseract並設定到環境變數。Tesseract.process(imgPath, (err, val) => { if (err || val == null) { console.error(':x: 识别失败:' + imgPath); return; } console.log(val);
实际上未经训练的Tesseracts识别起来会有少数几个错误,比如把9开头的数字识别成`3,这里需要通过训练去提升Tesseracts的准确率,如果识别过程出现的问题都是一样的,也可以简单通过正则去修复这些问题。
封装
实现了以上几点后,只需组合起来就可以封装成一个百度指数爬虫node库。当然还有许多优化的方法,比如批量爬取,指定天数爬取等,只要在这个基础上实现都不难了。
const recognition = require('./src/recognition'); const Spider = require('./src/spider'); module.exports = { async run (word, options, puppeteerOptions = { headless: true }) { const spider = new Spider({ imgDir, ...options }, puppeteerOptions); // 抓取数据 await spider.run(word); // 读取抓取到的截图,做图像识别 const wordDir = path.resolve(imgDir, word); const imgNames = fs.readdirSync(wordDir); const result = []; imgNames = imgNames.filter(item => path.extname(item) === '.png'); for (let i = 0; i < imgNames.length; i++) { const imgPath = path.resolve(wordDir, imgNames[i]); const val = await recognition.run(imgPath); result.push(val); } return result; } }
反爬虫
最后,如何抵挡这种爬虫呢,个人认为通过判断鼠标移动轨迹可能是一种方法。当然前端没有100%的反爬虫手段,我们能做的只是给爬虫增加一点难度。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
在Node.js中使用cheerio制作简单的网页爬虫(详细教程)
在React中使用Native如何实现自定义下拉刷新上拉加载的列表
以上是使用Puppeteer影像辨識技術如何實現百度指數爬蟲的詳細內容。更多資訊請關注PHP中文網其他相關文章!