首頁  >  文章  >  web前端  >  如何實現百度指數爬蟲功能

如何實現百度指數爬蟲功能

php中世界最好的语言
php中世界最好的语言原創
2018-04-12 16:45:484585瀏覽

這次為大家帶來怎樣實現百度指數爬蟲功能,實現百度指數爬蟲功能的注意事項有哪些,下面就是實戰案例,一起來看一下。

# 之前看過一篇腦洞大開的文章,介紹了各個大廠的前端反爬蟲技巧,但也正如此文所說,沒有100%的反爬蟲方法,本文介紹一種簡單的方法,來繞過所有這些前端反爬蟲手段。

下面的程式碼以百度指數為例,程式碼已經封裝成一個百度指數爬蟲node庫:https://github.com/Coffcer/baidu-index-spider

  1. #

    note: 請勿濫用爬蟲給別人添麻煩

  2. #

    百度指數的反爬蟲策略

  3. 觀察百度指數的介面,指數資料是一個趨勢圖,當滑鼠懸浮在某一天的時候,會觸發兩個請求,將結果顯示在懸浮框裡

    # 可以發現,百度指數其實在前端做了一定的反爬蟲策略。當滑鼠移動到圖表上時,會觸發兩個請求,一個請求傳回一段html,一個請求傳回一張產生的圖片。 html中並不包含實際數值,而是透過設定width和
  4. margin-left
  5. ,來顯示圖片上的對應字元。而且

    請求參數

    上有res、res1這種我們不知如何模擬的參數,所以用常規的模擬請求或html爬取的方式,都很難爬到百度指數的資料。

爬蟲思路

  1. # 怎麼突破百度這種反爬蟲方法呢,其實也很簡單,就是完全不去管他是如何反爬蟲的。我們只需模擬使用者操作,將需要的數值截圖下來,做圖像辨識就行。步驟大概是:

    模擬登入
  2. # 開啟指數頁面

  3. # 滑鼠移動到指定日期

    等待請求結束,截取數值部分的圖片

# 影像辨識得到值

# 循環第3~5步,就得到每一個日期對應的值

這種方法理論上能爬任何網站的內容,接下來我們就一步一步實作爬蟲,下面會用到的函式庫:

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
### Puppeteer在安裝時會自動下載Chromium,以確保可以正常運作。但國內網路不一定能成功下載Chromium,如果下載失敗,可以使用cnpm來安裝,或是將下載位址改成淘寶的鏡像,然後再安裝:###
npm config set PUPPETEER_DOWNLOAD_HOST=https://npm.taobao.org/mirrors
npm install --save puppeteer
### 你也可以在安裝時跳過Chromium下載,透過程式碼指定本機Chrome路徑來執行:###
// 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%的反爬虫手段,我们能做的只是给爬虫增加一点难度。

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

easyui日期时间框在IE中的兼容性如何处理

vue判断input输入内容有否有空格

以上是如何實現百度指數爬蟲功能的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn