摘要:前言之前斷斷續續學習了,今天就拿拉勾網練練手,順便通過數據了解了解最近的招聘行情哈方面算是萌新一個吧,希望可以和大家共同學習和進步。
前言
之前斷斷續續學習了node.js,今天就拿拉勾網練練手,順便通過數據了解了解最近的招聘行情哈!node方面算是萌新一個吧,希望可以和大家共同學習和進步。一、概要
我們首先需要明確具體的需求:
可以通過node index 城市 職位來爬取相關信息
也可以輸入node index start直接爬取我們預定義好的城市和職位數組,循環爬取不同城市的不同職位信息
將最終爬取的結果存儲在本地的./data目錄下
生成對應的excel文件,并存儲到本地
二、爬蟲用到的相關模塊fs: 用于對系統文件及目錄進行讀寫操作
async:流程控制
superagent:客戶端請求代理模塊
node-xlsx:將一定格式的文件導出為excel
三、爬蟲主要步驟: 初始化項目新建項目目錄
在合適的磁盤目錄下創建項目目錄 node-crwl-lagou
初始化項目
進入node-crwl-lagou文件夾下
執行npm init,初始化package.json文件
安裝依賴包
命令行輸入的處理npm install async
npm install superagent
npm install node-xlsx
對于在命令行輸入的內容,可以用process.argv來獲取,他會返回個數組,數組的每一項就是用戶輸入的內容。
區分node index 地域 職位和node index start兩種輸入,最簡單的就是判斷process.argv的長度,長度為四的話,就直接調用爬蟲主程序爬取數據,長度為三的話,我們就需要通過預定義的城市和職位數組來拼湊url了,然后利用async.mapSeries循環調用主程序。關于命令分析的主頁代碼如下:
if (process.argv.length === 4) { let args = process.argv console.log("準備開始請求" + args[2] + "的" + args[3] + "職位數據"); requsetCrwl.controlRequest(args[2], args[3]) } else if (process.argv.length === 3 && process.argv[2] === "start") { let arr = [] for (let i = 0; i < defaultArgv.city.length; i++) { for (let j = 0; j < defaultArgv.position.length; j++) { let obj = {} obj.city = defaultArgv.city[i] obj.position = defaultArgv.position[j] arr.push(obj) } } async.mapSeries(arr, function (item, callback) { console.log("準備開始請求" + item.city + "的" + item.position + "職位數據"); requsetCrwl.controlRequest(item.city, item.position, callback) }, function (err) { if (err) throw err }) } else { console.log("請正確輸入要爬取的城市和職位,正確格式為:"node index 城市 關鍵詞" 或 "node index start" 例如:"node index 北京 php" 或"node index start"") }
預定義好的城市和職位數組如下:
{ "city": ["北京","上海","廣州","深圳","杭州","南京","成都","西安","武漢","重慶"], "position": ["前端","java","php","ios","android","c++","python",".NET"] }
接下來就是爬蟲主程序部分的分析了。
分析頁面,找到請求地址首先我們打開拉勾網首頁,輸入查詢信息(比如node),然后查看控制臺,找到相關的請求,如圖:
這個post請求https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false就是我們所需要的,通過三個請求參數來獲取不同的數據,簡單的分析就可得知:參數first是標注當前是否是第一頁,true為是,false為否;參數pn是當前的頁碼;參數kd是查詢輸入的內容。
通過superagent請求數據首先需要明確得是,整個程序是異步的,我們需要用async.series來依次調用。
查看分析返回的response:
可以看到content.positionResult.totalCount就是我們所需要的總頁數
我們用superagent直接調用post請求,控制臺會提示如下信息:
{"success": False, "msg": "您操作太頻繁,請稍后再訪問", "clientIp": "122.xxx.xxx.xxx"}
這其實是反爬蟲策略之一,我們只需要給其添加一個請求頭即可,請求頭的獲取方式很簡單,如下:
然后在用superagent調用post請求,主要代碼如下:
// 先獲取總頁數 (cb) => { superagent .post(`https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false&city=${city}&kd=${position}&pn=1`) .send({ "pn": 1, "kd": position, "first": true }) .set(options.options) .end((err, res) => { if (err) throw err // console.log(res.text) let resObj = JSON.parse(res.text) if (resObj.success === true) { totalPage = resObj.content.positionResult.totalCount; cb(null, totalPage); } else { console.log(`獲取數據失敗:${res.text}}`) } }) },
拿到總頁數后,我們就可以通過總頁數/15獲取到pn參數,循環生成所有url并存入urls中:
(cb) => { for (let i=0;Math.ceil(i有了所有的url,在想爬到所有的數據就不是難事了,繼續用superagent的post方法循環請求所有的url,每一次獲取到數據后,在data目錄下創建json文件,將返回的數據寫入。這里看似簡單,但是有兩點需要注意:
為了防止并發請求太多而導致被封IP:循環url時候需要使用async.mapLimit方法控制并發為3, 每次請求完都要過兩秒在發送下一次的請求
在async.mapLimit的第四個參數中,需要通過判斷調用主函數的第三個參數是否存在來區分一下是那種命令輸入,因為對于node index start這個命令,我們使用得是async.mapSeries,每次調用主函數都傳遞了(city, position, callback),所以如果是node index start的話,需要在每次獲取數據完后將null傳遞回去,否則無法進行下一次循環
主要代碼如下:
// 控制并發為3 (cb) => { async.mapLimit(urls, 3, (url, callback) => { num++; let page = url.split("&")[3].split("=")[1]; superagent .post(url) .send({ "pn": totalPage, "kd": position, "first": false }) .set(options.options) .end((err, res) => { if (err) throw err let resObj = JSON.parse(res.text) if (resObj.success === true) { console.log(`正在抓取第${page}頁,當前并發數量:${num}`); if (!fs.existsSync("./data")) { fs.mkdirSync("./data"); } // 將數據以.json格式儲存在data文件夾下 fs.writeFile(`./data/${city}_${position}_${page}.json`, res.text, (err) => { if (err) throw err; // 寫入數據完成后,兩秒后再發送下一次請求 setTimeout(() => { num--; console.log(`第${page}頁寫入成功`); callback(null, "success"); }, 2000); }); } }) }, (err, result) => { if (err) throw err; // 這個arguments是調用controlRequest函數的參數,可以區分是那種爬取(循環還是單個) if (arguments[2]) { ok = 1; } cb(null, ok) }) }, () => { if (ok) { setTimeout(function () { console.log(`${city}的${position}數據請求完成`); indexCallback(null); }, 5000); } else { console.log(`${city}的${position}數據請求完成`); } // exportExcel.exportExcel() // 導出為excel }導出的json文件如下:
json文件導出為excel將json文件導出為excel有多種方式,我使用的是node-xlsx這個node包,這個包需要將數據按照固定的格式傳入,然后導出即可,所以我們首先做的就是先拼出其所需的數據格式:
function exportExcel() { let list = fs.readdirSync("./data") let dataArr = [] list.forEach((item, index) => { let path = `./data/${item}` let obj = fs.readFileSync(path, "utf-8") let content = JSON.parse(obj).content.positionResult.result let arr = [["companyFullName", "createTime", "workYear", "education", "city", "positionName", "positionAdvantage", "companyLabelList", "salary"]] content.forEach((contentItem) => { arr.push([contentItem.companyFullName, contentItem.phone, contentItem.workYear, contentItem.education, contentItem.city, contentItem.positionName, contentItem.positionAdvantage, contentItem.companyLabelList.join(","), contentItem.salary]) }) dataArr[index] = { data: arr, name: path.split("./data/")[1] // 名字不能包含 / ? * [ ] } }) // 數據格式 // var data = [ // { // name : "sheet1", // data : [ // [ // "ID", // "Name", // "Score" // ], // [ // "1", // "Michael", // "99" // // ], // [ // "2", // "Jordan", // "98" // ] // ] // }, // { // name : "sheet2", // data : [ // [ // "AA", // "BB" // ], // [ // "23", // "24" // ] // ] // } // ] // 寫xlsx var buffer = xlsx.build(dataArr) fs.writeFile("./result.xlsx", buffer, function (err) { if (err) throw err; console.log("Write to xls has finished"); // 讀xlsx // var obj = xlsx.parse("./" + "resut.xls"); // console.log(JSON.stringify(obj)); } ); }導出的excel文件如下,每一頁的數據都是一個sheet,比較清晰明了:
我們可以很清楚的從中看出目前西安.net的招聘情況,之后也可以考慮用更形象的圖表方式展示爬到的數據,應該會更加直觀!
總結其實整個爬蟲過程并不復雜,注意就是注意的小點很多,比如async的各個方法的使用以及導出設置header等,總之,也是收獲滿滿噠!
源碼gitbug地址: https://github.com/fighting12...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/95927.html
摘要:本文代碼地址爬取豆瓣電影爬取拉勾網職位信息模擬登陸知乎為什么沒人給我點贊。職位名職位信息運行結果模擬登錄知乎通過開發者工具,獲取的數據。 我開通了公眾號【智能制造專欄】,以后技術類文章會發在專欄。用Python寫爬蟲是很方便的,最近看了xlzd.me的文章,他的文章寫的很到位,提供了很好的思路。因為他的文章部分代碼省略了。下面是基于他的文章的三個代碼片段:基于Python3,Pytho...
摘要:拉勾網的爬蟲還是有一定的難度的所以我們今天就爬取試一下其實并沒有太大的難度只要我們用好分析一下請求就會其實沒有什么難度上代碼親測可用拉鉤代碼 拉勾網的爬蟲還是有一定的難度的 所以我們今天就爬取試一下 其實并沒有太大的難度 只要我們用好network 分析一下請求 就會其實沒有什么難度 上代碼 2019-05-22 親測可用 拉鉤代碼
摘要:因為本人在成都從事前端,所以這次爬取的關鍵詞既是成都,前端。僅僅有這個是不夠的,因為貌似拉勾網有反爬蟲,沒有好像得不到數據這個還待論證,至少我這邊是。 前言 showImg(https://segmentfault.com/img/bV1g4S?w=700&h=490); 今天是2018的第一天,首先祝各位小伙伴元旦快樂!又到了新的一年,雖然離春節還有一段時間,但是程序狗打工不易啊,不...
摘要:因為本人在成都從事前端,所以這次爬取的關鍵詞既是成都,前端。僅僅有這個是不夠的,因為貌似拉勾網有反爬蟲,沒有好像得不到數據這個還待論證,至少我這邊是。 前言 showImg(https://segmentfault.com/img/bV1g4S?w=700&h=490); 今天是2018的第一天,首先祝各位小伙伴元旦快樂!又到了新的一年,雖然離春節還有一段時間,但是程序狗打工不易啊,不...
摘要:最近在研究區塊鏈,閑來無事抓取了拉勾網上條區塊鏈相關的招聘信息。拉勾網的反爬蟲做的還是比較好的,畢竟自己也知道這種做招聘信息聚合的網站很容易被爬,而且比起妹子圖這種網站,開發的技術水平應該高不少。 最近在研究區塊鏈,閑來無事抓取了拉勾網上450條區塊鏈相關的招聘信息。過程及結果如下。 拉勾網爬取 首先是從拉勾網爬取數據,用的requests庫。拉勾網的反爬蟲做的還是比較好的,畢竟自己也...
閱讀 917·2021-10-18 13:32
閱讀 3513·2021-09-30 09:47
閱讀 2155·2021-09-23 11:21
閱讀 1878·2021-09-09 09:34
閱讀 3479·2019-08-30 15:43
閱讀 1522·2019-08-30 11:07
閱讀 1061·2019-08-29 16:14
閱讀 724·2019-08-29 11:06