摘要:前言很多程序猿在最開始學(xué)習(xí)開發(fā)的時(shí)候應(yīng)該都有一個(gè)想要自己開發(fā)一個(gè)爬蟲的想法至少我是有的。其實(shí)弄懂了爬蟲的原理,再回過頭去看,發(fā)現(xiàn)開發(fā)一個(gè)簡(jiǎn)單的爬蟲來說還是很容易的。
前言
很多程序猿在最開始學(xué)習(xí)開發(fā)的時(shí)候應(yīng)該都有一個(gè)想要自己開發(fā)一個(gè)爬蟲的想法(至少我是有的)。所以國(guó)內(nèi)網(wǎng)絡(luò)上也是爬蟲盛行!學(xué)了node.js之后發(fā)現(xiàn)比較適合寫爬蟲,不過一直沒有動(dòng)手去寫,正好這段時(shí)間比較閑,就寫個(gè)爬蟲玩下。
想著爬個(gè)什么東西呢?正好都比較喜歡看電影,那就從時(shí)光網(wǎng)爬下國(guó)內(nèi)的票房排行榜吧。
Talk is cheap. Show me the code不bb,代碼在此
如何"食用"git clone https://github.com/XNAL/node-MovieSpider cd node-MovieSpider npm init node index.js搭建環(huán)境
開發(fā)語言:node.js
發(fā)出http請(qǐng)求:superagent
并發(fā)控制:async
分析網(wǎng)頁內(nèi)容:cheerio
開始擼代碼 1. 代碼主體作為一個(gè)簡(jiǎn)單的示例,此次就不開啟node服務(wù)了,我這里就直接來個(gè)自執(zhí)行的方法。如果有需要,可以根據(jù)自己的需求擴(kuò)展。
// 啟動(dòng)時(shí)直接執(zhí)行代碼 (function spider() { util.fetch_data_get(reqUrl, reqParams) .then((result) => { // 根據(jù)頁面結(jié)構(gòu)獲取總的頁數(shù),然后再分頁獲取數(shù)據(jù) let $ = cheerio.load(result.body.html); let pageTotal = $(".bocontent .pagesize a:last-child").data("page") || 0; console.log("電影數(shù)據(jù)總頁數(shù):", pageTotal); return pageTotal; }) .then((pageTotal) => { // 分頁獲取數(shù)據(jù) getMovieData(0, pageTotal); }) .catch((err) => { console.log("獲取鏈接失?。?, err); }) })();2. 發(fā)送請(qǐng)求
因?yàn)榇a中需要多次發(fā)送http請(qǐng)求,所以把http請(qǐng)求寫成一個(gè)公共方法會(huì)比較好。使用上面提到superagent庫來實(shí)現(xiàn)。
// 公共方法:通過get請(qǐng)求獲取數(shù)據(jù) function fetch_data_get(url, queryParams) { return new Promise((reslove, reject) => { superagent .get(url) .set(setting.header) .query(queryParams) .end((err, result) => { err ? reject(err) : reslove(result); }) }) }3. 分析目標(biāo)網(wǎng)站api
根據(jù)人工操作得來的apihttp://movie.mtime.com/boxoffice/?year=2017&area=china&type=MovieRankingYear&category=all&page=0&display=list×tamp=1505818638620&version=07bb781100018dd58eafc3b35d42686804c6df8d&dataType=json可以得到以下參數(shù):
// 根據(jù)網(wǎng)站api得到相應(yīng)的url和參數(shù) const reqUrl = "http://movie.mtime.com/boxoffice/"; const reqParams = { "year": 2017, "area": "china", "type": "MovieRankingYear", "category": "all", "page": 0, "display": "list", "timestamp": 1501576013654, "version": "07bb781100018dd58eafc3b35d42686804c6df8d", "dataType": "json" };
因?yàn)榇舜我@取的是2017年內(nèi)地票房排行榜。根據(jù)分析可知:需要變動(dòng)的主要是page參數(shù),那這里就需要根據(jù)頁面返回的內(nèi)容來取得總的page。
4. 使用cheerio獲取所需參數(shù)api返回的頁面內(nèi)容可查看:將api獲取的數(shù)據(jù)格式化后的頁面代碼。
這里需要用到cheerio來取頁碼總數(shù)的代碼,cheerio可以理解為服務(wù)器端的jQuery,用法也類似:
// 根據(jù)頁面結(jié)構(gòu)獲取總的頁數(shù),然后再分頁獲取數(shù)據(jù) let $ = cheerio.load(result.body.html); let pageTotal = $(".bocontent .pagesize a:last-child").data("page") || 0;5. 開始分頁取目標(biāo)數(shù)據(jù)
<1> 調(diào)用上面所說的公共方法fetch_data_get獲取數(shù)據(jù),然后取頁面內(nèi)容,圖片地址都先保存在movieImgs中,最后再統(tǒng)一下載圖片:
// 根據(jù)頁面結(jié)構(gòu)獲取所需數(shù)據(jù) let $ = cheerio.load(result.body.html); $(".bocontent .boxofficelist dd").each((idx, elem) => { $(elem).find("div.movietopmod").each((i, el) => { let _this = $(el); let arrLeadActor = []; _this.find(".txtbox b p").eq(1).find("a").each((idx, ela) => { arrLeadActor.push($(ela).text()); }) movieData.push({ rank: _this.find(".picbox i").text(), img: _this.find(".picbox img").attr("src").replace(//u//, ""), name: _this.find(".txtbox h3").text(), director: _this.find(".txtbox b p").eq(0).find("a").text(), leadActor: arrLeadActor.join(","), point: _this.find(".gradebox .point").text(), total: _this.find(".totalbox .totalnum").text() }), movieImgs.push(_this.find(".picbox img").attr("src").replace(//u//, "")); }) })
<2> 根據(jù)頁碼循環(huán)取數(shù)據(jù)
if(pageIndex <= pageTotal) { // 設(shè)置timeout防止網(wǎng)站反爬蟲 setTimeout(() => { pageIndex ++; getMovieData(pageIndex, pageTotal); }, setting.timeout); }
<3> 全部數(shù)據(jù)取出后存儲(chǔ)數(shù)據(jù),并下載圖片。
因?yàn)橹皇且粋€(gè)簡(jiǎn)單的示例,所以此次數(shù)據(jù)只是保存到json文件中。如果需要對(duì)數(shù)據(jù)進(jìn)行后續(xù)操作的話,那就最好保存到數(shù)據(jù)庫中:
fs.writeFile(dataDir + reqParams.year + ".json", JSON.stringify(movieData), (err) => { if (err) { console.log(err); } else { console.log("數(shù)據(jù)寫入成功"); } });
調(diào)用下載圖片的方法:
let folderName = imgPrefix + reqParams.year; util.downloadImg(movieImgs, folderName);
util.js中的downloadImg方法:這里就需要用到上面所說的async,使用async是為了進(jìn)行并發(fā)控制,不然極短時(shí)間發(fā)送至少幾十幾百次的請(qǐng)求,這種情況弄不好就被網(wǎng)站的發(fā)爬蟲程序給封了,而且大量并發(fā)也會(huì)導(dǎo)致出錯(cuò)的概率更高。
// 異步下載圖片 function downloadImg(urls, folderName) { async.mapLimit(urls, setting.asyncNum, (img, callback) => { fetch_data_get(img, {}) .then((result) => { let fileName = path.basename(img); let folder = imgDir + folderName; if(!fs.existsSync(folder)) { fs.mkdirSync(folder); } fs.writeFile(folder + "/" + fileName, result.body, (err) => { if (err) { console.log(img, "圖片寫入失敗:", err); } else { console.log(img, "圖片寫入成功"); callback(null , fileName); } }) }) .catch((err) => console.log(err)) }, (err, result) => { if (err) { console.log("圖片下載失?。?, err) } else { console.log(result); } }) }結(jié)語
到此為止一個(gè)簡(jiǎn)單的node.js版的小爬蟲就開發(fā)完成了。其實(shí)弄懂了爬蟲的原理,再回過頭去看,發(fā)現(xiàn)開發(fā)一個(gè)簡(jiǎn)單的爬蟲來說還是很容易的。
最后,歡迎大家去我的github進(jìn)行star和fork。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/91965.html
摘要:爬蟲介紹二爬蟲的分類通用網(wǎng)絡(luò)爬蟲全網(wǎng)爬蟲爬行對(duì)象從一些種子擴(kuò)充到整個(gè),主要為門戶站點(diǎn)搜索引擎和大型服務(wù)提供商采集數(shù)據(jù)。 分分鐘教你用node.js寫個(gè)爬蟲 寫在前面 十分感謝大家的點(diǎn)贊和關(guān)注。其實(shí),這是我第一次在segmentfault上寫文章。因?yàn)槲乙彩乔岸螘r(shí)間偶然之間才開始了解和學(xué)習(xí)爬蟲,而且學(xué)習(xí)node的時(shí)間也不是很長(zhǎng)。雖然用node做過一些后端的項(xiàng)目,但其實(shí)在node和爬蟲方面...
摘要:一個(gè)爬蟲租房軟件。獲取導(dǎo)航頁以及數(shù)據(jù)打開同城主頁,我主要針對(duì)杭州的二手房進(jìn)行了爬取分析,所以進(jìn)入杭州租房。這次我們需要解析房屋所在地信息,用來可視化顯示。具體做法可以參照相關(guān)反爬蟲策略的文章。 一個(gè)爬蟲租房軟件。 先上一個(gè)源代碼吧。 https://github.com/answershuto/Rental 歡迎指導(dǎo)交流。 效果圖 showImg(https://segmentfau...
摘要:今天開源了一個(gè)百度云網(wǎng)盤爬蟲項(xiàng)目,地址是。推薦使用命令安裝依賴,最簡(jiǎn)單的安裝方式更多安裝的命令可以去上面找。啟動(dòng)項(xiàng)目使用進(jìn)行進(jìn)程管理,運(yùn)行啟動(dòng)所有的后臺(tái)任務(wù),檢查任務(wù)是否正常運(yùn)行可以用命令,正常運(yùn)行的應(yīng)該有個(gè)任務(wù)。 今天開源了一個(gè)百度云網(wǎng)盤爬蟲項(xiàng)目,地址是https://github.com/callmelanmao/yunshare。 百度云分享爬蟲項(xiàng)目 github上有好幾個(gè)這樣的...
摘要:這里由于京東的分界面都使用了,所以我們可以用,總之他們開發(fā)能用的選擇器,我們都可以用,否則就不可以。 難道爬蟲只能用 python 做? 不,我們上天的 Node.js 也可以做! 需要準(zhǔn)備的包 Node.js的最新版本 下載地址 Node.js官網(wǎng) npm 包管理器下載 下載最新的官網(wǎng)版本 Node.js 會(huì)自帶 npm npm的第三方包 puppeteer 在對(duì)應(yīng)...
摘要:這里由于京東的分界面都使用了,所以我們可以用,總之他們開發(fā)能用的選擇器,我們都可以用,否則就不可以。 難道爬蟲只能用 python 做? 不,我們上天的 Node.js 也可以做! 需要準(zhǔn)備的包 Node.js的最新版本 下載地址 Node.js官網(wǎng) npm 包管理器下載 下載最新的官網(wǎng)版本 Node.js 會(huì)自帶 npm npm的第三方包 puppeteer 在對(duì)應(yīng)...
閱讀 1761·2021-11-25 09:43
閱讀 1800·2021-11-24 10:41
閱讀 3115·2021-09-27 13:36
閱讀 822·2019-08-30 15:53
閱讀 3584·2019-08-30 15:44
閱讀 874·2019-08-30 14:03
閱讀 2585·2019-08-29 16:38
閱讀 1008·2019-08-29 13:23