node抓取王者榮耀英雄資料庫
阿新 • • 發佈:2018-12-03
用node寫的爬蟲,抓取王者榮耀英雄資料庫,只是為了學習,侵刪!
主要包括(基本上相關的都抓取):
- 召喚師技能
- 銘文
- 裝備
- 英雄
- 面板
- 英雄故事
- 英雄技能
- 推薦銘文
- 推薦裝備
- 技能加點
沒有搞懂如何動態抓取內容,我覺得抓取之前你要知道網頁的js邏輯,emmmm....
這裡我已經下載所需要的json檔案到專案裡面,如何下載:node下載檔案
資料庫的配置:
module.exports = { host: 'localhost', database: 'glory_of_kings', user: 'root', password: 'root' };
也可以直接配置,不那麼麻煩,只是為了學習新的方式。
// mysql的包 很多安利easymysql的,暫時還沒改 let mysql = require('mysql'); // 檔案操作 let fs = require('fs'); // mysql配置 let mysqlConfig = require('./mysql.config'); // 爬蟲所需要的庫 let http = require('http'); let cheerio = require('cheerio'); let iconv = require('iconv-lite'); //建立連線,資料操作完成之後要關閉連線 let connection = mysql.createConnection(mysqlConfig); //連線mysql connection.connect(function (err) { if (err) { console.log('資料庫連線失敗'); throw err; } }); // json檔案的基礎路徑 const BASE_PATH = '../assets/jsons/'; // 檔案編碼方式 const FILE_TYPE = 'utf-8'; // 英雄資料頁面基礎路徑 const HERO_DETAIL_PATH = `http://pvp.qq.com/web201605/herodetail/`; //英雄圖片的基礎路徑 const HERO_IMG_PATH = `http://game.gtimg.cn/images/yxzj/img201606/heroimg/`; // 英雄面板大圖的基礎路徑 const HERO_BIGSKIN_PATH = `http://game.gtimg.cn/images/yxzj/img201606/skin/hero-info/`; // 裝備圖片的基礎路徑 const EQUIP_IMG_PATH = `http://game.gtimg.cn/images/yxzj/img201606/itemimg/`; //技能圖片的基礎路徑 const SUMMONER_PATH = `http://game.gtimg.cn/images/yxzj/img201606/summoner/`; // 銘文圖片的基礎路徑 const INSCRIPTION_PATH = `http://game.gtimg.cn/images/yxzj/img201606/mingwen/`; // 召喚師技能的插入語句 const SUMMONER_SQL = `insert into summoner(summoner_id,name,rank,cd,description,img_url,big_img_url) values(?,?,?,?,?,?,?)`; // 銘文的插入語句 const INSCRIPTION_INSERT = `insert into inscription(inscription_id,type,grade,name,description,img_url) values(?,?,?,?,?,?)`; // 英雄的插入語句 const HERO_INSERT = `insert into hero(hero_id,name,pay_type,new_type,hero_type,hero_type2,skin_name,img_url,live,attack,skill,difficulty) values (?,?,?,?,?,?,?,?,?,?,?,?)`; //英雄面板的插入語句 const HERO_SKIN_INSERT = `insert into skin(skin_id,hero_id,skin_name,small_img_url,big_img_url) values (?,?,?,?,?)`; // 裝備的插入語句 const EQUIP_INSERT = `insert into equip(equip_id,name,type,sale_price,total_price,des1,des2,img_url) values (?,?,?,?,?,?,?,?)`; //英雄故事插入語句 const STORY_INSERT = `insert into story(hero_id,story) values (?,?)`; // 英雄技能插入語句 const SKILL_INSERT = `insert into skill(skill_id,hero_id,name,cool,waste,description,tips,img_url) values (?,?,?,?,?,?,?,?)`; // 推薦銘文的插入語句 const HERO_INSCRIPTION_INSERT = `insert into hero_inscription(hero_id,inscription_ids,tips) values (?,?,?)`; // 推薦裝備的插入語句 const HERO_EQUIP_INSERT = `insert into hero_equip(hero_id,equip_ids1,tips1,equip_ids2,tips2) values (?,?,?,?,?)`; // 英雄關係的插入語句 // 網頁中每個項都是兩個英雄,所以這裡一次插入兩條資料 const LINKS_INSERT = `insert into links(hero_id,hero_id1,type,tips) values (?,?,?,?),(?,?,?,?)`; // 技能加點的建議 const SKILL_SUMMONER_INSERT = `insert into skill_summoner(ename,skill_id1,skill_id2,summoner_id1,summoner_id2) values (?,?,?,?,?)`; /** * 更新召喚師技能 */ function updateSummoner() { fs.readFile(`${BASE_PATH}summoner.json`, FILE_TYPE, function (err, data) { if (err) { console.log(`檔案讀取失敗`) } else { if (JSON.parse(data).length === 0) { console.log(`暫無資料`); } else { let params = []; JSON.parse(data).forEach(function (it, index) { params = [ it.summoner_id, it.summoner_name, parseInt(it.summoner_rank.substring(3)), parseInt(it.summoner_description), it.summoner_description.split(':')[1], `${SUMMONER_PATH}${it.summoner_id}.jpg`, `${SUMMONER_PATH}${it.summoner_id}-big.jpg` ]; connection.query(SUMMONER_SQL, params, function (error, res) { if (error) { console.log(error); throw error; } console.log(`技能${it.summoner_name}插入成功!`); }); }); } } }); } /** * 更新銘文 */ function updateInscription() { fs.readFile(`${BASE_PATH}ming.json`, FILE_TYPE, function (err, data) { if (err) { console.log(`檔案讀取失敗`) } else { if (JSON.parse(data).length === 0) { console.log(`暫無資料`); } else { let params = []; JSON.parse(data).forEach(function (it, index) { params = [ it.ming_id, it.ming_type, it.ming_grade, it.ming_name, it.ming_des, `${INSCRIPTION_PATH}${it.ming_id}.png` ]; connection.query(INSCRIPTION_INSERT, params, function (error, res) { if (error) { console.log(error); throw error; } console.log(`銘文${it.ming_name}插入成功!`); }); }); } } }); } /** * 更新裝備 */ function updateEquipments() { fs.readFile(`${BASE_PATH}item.json`, FILE_TYPE, function (err, data) { if (err) { console.log(`檔案讀取失敗`) } else { if (JSON.parse(data).length === 0) { console.log(`暫無裝備資料`); } else { let params = []; JSON.parse(data).forEach(function (it, index) { params = [ it.item_id, it.item_name, it.item_type, it.price, it.total_price, it.des1, it.des2, `${EQUIP_IMG_PATH}${it.item_id}.jpg` ]; connection.query(EQUIP_INSERT, params, function (error, res) { if (error) { console.log(error); throw error; } console.log(`裝備:${it.item_name} 插入成功!`); }); }); } } }); } /** * 更新英雄 */ function updateHero() { fs.readFile(`${BASE_PATH}heros.json`, FILE_TYPE, function (err, data) { if (err) { console.log(`檔案讀取失敗`) } else { if (JSON.parse(data).length === 0) { console.log(`暫無資料`); } else { let params = []; JSON.parse(data).forEach(function (it, index) { // 測試 http.get(`${HERO_DETAIL_PATH}${it.ename}.shtml`, function (res) { let chunks = []; res.on('data', function (item) { chunks.push(item); }); res.on('end', function () { // 解碼頁面,防止亂碼 let html = iconv.decode(Buffer.concat(chunks), 'gbk'); let $ = cheerio.load(html, {decodeEntities: false}); let list = $('.ibar'); params = [ it.ename, it.cname, it.pay_type, it.new_type, it.hero_type, it.hero_type2, it.skin_name, `${HERO_IMG_PATH}${it.ename}/${it.ename}.jpg`, parseInt(list[0].attribs.style.substring(6)), parseInt(list[1].attribs.style.substring(6)), parseInt(list[2].attribs.style.substring(6)), parseInt(list[3].attribs.style.substring(6)) ]; connection.query(HERO_INSERT, params, function (error, res) { if (error) { console.log(error); throw error; } console.log(`英雄${it.ename}插入成功!`); }); }) }).on('error', function () { console.log(`獲取頁面資料出錯`); }); }); } } }); } /** * 更新面板 */ function updateSkin() { fs.readFile(`${BASE_PATH}heros.json`, FILE_TYPE, function (err, data) { if (err) { console.log(`檔案讀取失敗`) } else { if (JSON.parse(data).length === 0) { console.log(`暫無資料`); } else { let params = []; let names = []; JSON.parse(data).forEach(function (it, index) { names = it.skin_name.split('|'); names.forEach(function (item, ind) { params = [ it.ename + '' + (ind + 1), it.ename, item, `${HERO_IMG_PATH}${it.ename}/${it.ename}-smallskin-${ind + 1}.jpg`, `${HERO_BIGSKIN_PATH}${it.ename}/${it.ename}-bigskin-${ind + 1}.jpg` ]; connection.query(HERO_SKIN_INSERT, params, function (error, res) { if (error) { console.log(error); throw error; } }); console.log(`面板${item}插入成功!`); }); }); } } }); } /** * 更新故事 */ function updateStory() { fs.readFile(`${BASE_PATH}heros.json`, FILE_TYPE, function (err, data) { if (err) { console.log(`檔案讀取失敗`); } else { let datas = JSON.parse(data); if (datas.length === 0) { console.log(`暫無英雄故事`); } else { let params = []; datas.forEach(function (it, index) { http.get(`${HERO_DETAIL_PATH}${it.ename}.shtml`, function (res) { let chunks = []; res.on('data', function (item) { chunks.push(item); }); res.on('end', function () { // 解碼頁面,防止亂碼 let html = iconv.decode(Buffer.concat(chunks), 'gbk'); let $ = cheerio.load(html, {decodeEntities: false}); params = [ it.ename, $('.pop-story .pop-bd p').html() ]; connection.query(STORY_INSERT, params, function (error, res) { if (error) { console.log(error); throw error; } console.log(`${it.ename}的故事插入成功`); }); }) }).on('error', function () { console.log(`獲取頁面資料出錯`); }); }); } } }); } /** * 更新技能 */ function updateSkill() { fs.readFile(`${BASE_PATH}heros.json`, FILE_TYPE, function (err, data) { if (err) { console.log(`檔案讀取失敗`); } else { if (JSON.parse(data).length === 0) { console.log(`暫無資料`); } else { let params = []; JSON.parse(data).forEach(function (it, index) { // 測試 http.get(`${HERO_DETAIL_PATH}${it.ename}.shtml`, function (res) { let chunks = []; res.on('data', function (item) { chunks.push(item); }); res.on('end', function () { // 解碼頁面,防止亂碼 let html = iconv.decode(Buffer.concat(chunks), 'gbk'); let $ = cheerio.load(html, {decodeEntities: false}); let skills = $('.skill-show .show-list'); skills.each(function (ind, el) { let name = $(el).find('.skill-name b').html(); if (name) { params = [ it.ename + '' + ind, it.ename, name, parseInt($($(el).find('.skill-name span')[0]).html().substring(4)), parseInt($($(el).find('.skill-name span')[1]).html().substring(3)), $(el).find('.skill-desc').html(), $(el).find('.skill-tips').html(), `${HERO_IMG_PATH}${it.ename}/${it.ename}${ind}0.png`, ]; connection.query(SKILL_INSERT, params, function (error, res) { if (error) { console.log(error); throw error; } }); console.log(`技能${name}插入成功!`); } }); }) }).on('error', function () { console.log(`獲取頁面資料出錯`); }); }); } } }); } /** * 獲取搭配銘文 */ function updateHeroInscription() { fs.readFile(`${BASE_PATH}heros.json`, FILE_TYPE, function (err, data) { if (err) { console.log("檔案讀取失敗"); } else { if (JSON.parse(data).length === 0) { console.log('暫無資料'); } else { let params = []; JSON.parse(data).forEach(function (it, index) { http.get(`${HERO_DETAIL_PATH}${it.ename}.shtml`, function (res) { let chunks = []; res.on('data', function (item) { chunks.push(item); }); res.on('end', function () { // 解碼頁面,防止亂碼 let html = iconv.decode(Buffer.concat(chunks), 'gbk'); let $ = cheerio.load(html, {decodeEntities: false}); params = [ it.ename, $('.sugg-info ul').attr('data-ming').split('|').join(','), $('.sugg-tips').text().substring('5') ]; connection.query(HERO_INSCRIPTION_INSERT, params, function (err, result) { if (err) { console.log(err); throw err; } console.log(`第${index}條資料插入成功!`); }) }) }).on('error', function () { console.log("獲取頁面資料出錯"); }) }); } } }); } /** * 獲取推薦裝備 */ function updateHeroEquip() { fs.readFile(`${BASE_PATH}heros.json`, FILE_TYPE, function (err, data) { if (err) { console.log("檔案讀取失敗"); } else { if (JSON.parse(data).length === 0) { console.log('暫無資料'); } else { let params = []; JSON.parse(data).forEach(function (it, index) { http.get(`${HERO_DETAIL_PATH}${it.ename}.shtml`, function (res) { let chunks = []; res.on('data', function (item) { chunks.push(item); }); res.on('end', function () { // 解碼頁面,防止亂碼 let html = iconv.decode(Buffer.concat(chunks), 'gbk'); let $ = cheerio.load(html, {decodeEntities: false}); params = [ it.ename, $($('.equip-info ul')[0]).attr('data-item').split('|').join(','), $($('.equip-tips')[0]).text().substring('5'), $($('.equip-info ul')[1]).attr('data-item').split('|').join(','), $($('.equip-tips')[1]).text().substring('5') ]; // console.log(params); connection.query(HERO_EQUIP_INSERT, params, function (err, result) { if (err) { console.log(err); throw err; } console.log(`第${index}條資料插入成功!`); }) }) }).on('error', function () { console.log("獲取頁面資料出錯"); }) }); } } }); } /** * 獲取英雄關係 */ function updateLinks() { fs.readFile(`${BASE_PATH}heros.json`, FILE_TYPE, function (err, data) { if (err) { console.log("檔案讀取失敗"); } else { if (JSON.parse(data).length === 0) { console.log('暫無資料'); } else { let params = []; JSON.parse(data).forEach(function (it, index) { http.get(`${HERO_DETAIL_PATH}${it.ename}.shtml`, function (res) { let chunks = []; res.on('data', function (item) { chunks.push(item); }); res.on('end', function () { // 解碼頁面,防止亂碼 let html = iconv.decode(Buffer.concat(chunks), 'gbk'); let $ = cheerio.load(html, {decodeEntities: false}); $('.hero-info').each(function (ind, el) { params = [ it.ename, $($(el).find('ul a')[0]).attr('href').substr(0, 3), ind, $($(el).find('p')[0]).html(), it.ename, $($(el).find('ul a')[1]).attr('href').substr(0, 3), ind, $($(el).find('p')[1]).html(), ]; connection.query(LINKS_INSERT, params, function (err, result) { if (err) { console.log(err); throw err; } }) }); console.log(`第${index}條資料插入成功!`); }) }).on('error', function () { console.log("獲取頁面資料出錯"); }) }); } } }); } /** * 英雄技能加點推薦 */ function updateSkillSummoner() { fs.readFile(`${BASE_PATH}heros.json`, FILE_TYPE, function (err, data) { if (err) { console.log("檔案讀取失敗"); } else { if (JSON.parse(data).length === 0) { console.log('暫無資料'); } else { let params = []; JSON.parse(data).forEach(function (it, index) { http.get(`${HERO_DETAIL_PATH}${it.ename}.shtml`, function (res) { let chunks = []; res.on('data', function (item) { chunks.push(item); }); res.on('end', function () { // 解碼頁面,防止亂碼 let html = iconv.decode(Buffer.concat(chunks), 'gbk'); let $ = cheerio.load(html, {decodeEntities: false}); params = [ it.ename, $($('.sugg-skill img')[0]).attr('src').substring(50, 54), $($('.sugg-skill img')[1]).attr('src').substring(50, 54), $($('.sugg-info2 p')[5]).attr('data-skill').substring(0, 5), $($('.sugg-info2 p')[5]).attr('data-skill').substring(6) ]; connection.query(SKILL_SUMMONER_INSERT, params, function (err, result) { if (err) { console.log(err); throw err; } console.log(`第${index}條資料插入成功!`); }); }) }).on('error', function () { console.log("獲取頁面資料出錯"); }) }); } } }); } // 關閉資料庫連線 connection.end(function (e) { if (e) { console.log(`關閉資料庫失敗`); throw e; } }); exports.updateSummoner = updateSummoner; exports.updateInscription = updateInscription; exports.updateHero = updateHero; exports.updateSkin = updateSkin; exports.updateEquipments = updateEquipments; exports.updateStory = updateStory; exports.updateSkill = updateSkill; exports.updateHeroInscription = updateHeroInscription; exports.updateHeroEquip = updateHeroEquip; exports.updateLinks = updateLinks; exports.updateSkillSummoner = updateSkillSummoner;
所有英雄的herolist.json檔案有點問題,解析json物件,老是報錯,然後手動修改成了heros.json,兩個檔案內容是一樣的,但是heros可以,herolist不可以,很尷尬,如果你解決了,可以和我說下,謝謝
周免英雄這裡也有點意思,動態插入的,不方便直接獲取,然後費了老大勁才發現,抓取的所有英雄的json檔案中,pay_type=10的英雄就是周免,pay_type=11的英雄是新手推薦,header.js裡面處理了,emmmm........(傳送:周免英雄,程式碼在339-347)
var freeHeroData = [], freeHeroHtml = ""; for (var i = 0; i < data.length; i++) { var payarr = [], payarr = ('' + data[i].pay_type).split(','); // 如果pay_type=10,插入的freeHeroData if (payarr == 10 || payarr[0] == 10 || payarr[1] == 10) { freeHeroData.push(data[i]); } } // console.log(freeHeroData);
OK!