摘要:前言之前初學(xué)的時候,有用爬蟲爬過一些磁力鏈接詳情見羞羞的爬蟲但是沒有并發(fā),沒有代理,那時也對異步不是很了解所以這次又寫了個爬蟲,爬取壁紙站的所有壁紙并且爬取開心代理的條,并將有用的存進(jìn)文件中用到的模塊控制并發(fā)解析庫使用代理讀寫文件其中的具
前言
之前初學(xué)node的時候,有用爬蟲爬過一些磁力鏈接
詳情見羞羞的node爬蟲
但是沒有并發(fā),沒有代理,那時也對異步不是很了解
所以這次又寫了個爬蟲,爬取bilibili壁紙站的所有壁紙
并且爬取開心代理的100條ip,并將有用的ip存進(jìn)json文件中
async (控制并發(fā))
cheerio (解析DOM)
superagent (http庫)
superagent-proxy (使用代理)
fs (讀寫文件)
其中cheerio, superagent的具體用法見我之前的 羞羞的node爬蟲
不過之前初學(xué),代碼寫得很難看就對了
代理ip是干嘛的
我們訪問互聯(lián)網(wǎng)資源時,都是用我們自己的ip(身份證)去訪問的
而爬蟲得頻繁地去獲取互聯(lián)網(wǎng)資源
因此如果你在某個時間點(diǎn)頻繁地訪問某網(wǎng)站的某資源
造成該網(wǎng)站的服務(wù)器壓力
就有可能被網(wǎng)站管理者禁ip, 從而訪問不了該網(wǎng)站
代理ip就是偽造身份去訪問
怎么檢驗(yàn)ip的可用性
這里面就使用到了 superagent 的一個拓展 superagent-proxy
然后用其去訪問http://ip.chinaz.com/getip.aspx
若 3s 內(nèi)能返回值,則證明該 ip 可用
const superagent = require("superagent") require("superagent-proxy")(superagent); // 寫上你先要測試的 ip,下面僅為測試ip let testIp = "http://61.178.238.122:63000"; (async function() { superagent.get("http://ip.chinaz.com/getip.aspx").proxy(testIp).timeout(3000) .end((err, res) => { if(res === undefined) { console.log("掛了"); return } if(err) { console.log("報錯啦") } console.log("成功: " + res.text) }) }())
爬取ip并存儲
首先我們先看下我們要爬取的開心代理的DOM
我們要爬取得ip地址放在tr 標(biāo)簽的第一個td上
并且點(diǎn)擊第二頁時,鏈接變?yōu)?b>http://www.kxdaili.com/dailiip/1/2.html#ip
鏈接上的數(shù)組表示得是頁數(shù),也就是說我們只要改變鏈接上數(shù)字的值
就可以獲取到其他頁的html
代碼如下:
const superagent = require("superagent") const cheerio = require("cheerio") const fs = require("fs") const apiFunc = require("../common/apiFunc") // 封裝的一些讀寫api // 爬取開心代理的 ip const website = "http://www.kxdaili.com" let url = website + "/dailiip/1/" // 總執(zhí)行函數(shù) let getIp = async function() { // promise 存放的數(shù)組 let tasks = [] // 讀取 ip.js 本身存儲的ip let ips = await apiFunc.readFile("./ip.js") ips = JSON.parse(ips) for(let page = 1; page <= 10; page++) { let res = await superagent.get(url + page +".html") let $ = cheerio.load(res.text) let tr = $("tbody>tr") for(let i = 0; i < tr.length; i++) { let td = $(tr[i]).children("td") let proxy = "http://" + $(td[0]).text() + ":" + $(td[1]).text() let pro = apiFunc.filterIp(proxy) // 將所有的IP過濾Promise存入一個tasks數(shù)組中 tasks.push(pro) } } // 使用 all 等待所有ip過濾完畢后執(zhí)行 寫入 ip.js過程 Promise.all(tasks).then((arr) => { // 過濾掉返回值為 undefined 的數(shù)據(jù) let usefulIp = arr.filter((item) => { return (item !== undefined) }) ips = JSON.stringify(ips.concat(usefulIp)) console.log(ips) apiFunc.writeFile("./ip.js", ips) }) } getIp() module.exports = getIp爬取bilibili壁紙站
我們先進(jìn)入bilibili壁紙站
發(fā)現(xiàn)有一個點(diǎn)擊加載更多的按鈕
如果有對前端有了解的話,我們應(yīng)該知道這是通過 ajax 請求來異步獲取數(shù)據(jù)
因此我們打開開發(fā)者的NetWork
果然在 XHR 這一欄發(fā)現(xiàn)了一個api
里面返回的是存儲了當(dāng)前頁面所有壁紙縮略圖信息的json文件
僅依靠這個json文件,我們便可以爬取所有壁紙的縮略圖
可我們要的可是高清大圖啊
于是我們隨意點(diǎn)擊一張縮略圖
發(fā)現(xiàn)它的url的參數(shù)(il_id, width, height)都來自我們之前獲取的json內(nèi)的數(shù)據(jù)
也就是說我們可以拼接該鏈接來獲取到該高清圖片的鏈接,再利用cheerio來解析DOM獲取圖片地址就ok了
!!!
!!!
!!!
然而,哈哈哈哈哈哈哈哈哈哈哈哈
當(dāng)我們獲取到該網(wǎng)頁的html后,發(fā)現(xiàn)該標(biāo)簽內(nèi)的src是空的
也就是說該也是js賦值,所以下意識又去看了NetWork的XHR
果然發(fā)現(xiàn)了另一個api
而高清圖片的url就是該api返回的json數(shù)據(jù)中的il_file
因此我們只需要拼接該api鏈接,再用superagent請求就可以獲取到高清圖片的url
理下思路
獲取縮略圖api返回的包含高清圖片數(shù)據(jù)的json
將1的json數(shù)據(jù)拼接到高清圖片api鏈接上,并將所有api鏈接存入數(shù)組
并發(fā)獲取2數(shù)組中的api, 獲取所有的圖片url,并將url存入數(shù)組
并發(fā)下載數(shù)組中的圖片url, 存進(jìn)本地文件夾
結(jié)果在爬取bilibili壁紙站時,是不需要解析DOM的,也就是不需要使用cheerio模塊啦
代碼如下:
const superagent = require("superagent") require("superagent-proxy")(superagent); const fs = require("fs") const cheerio = require("cheerio") const async = require("async") // 獲取bilibili API的json數(shù)據(jù) let jsonUrl = "http://h.bilibili.com/wallpaperApi?action=getOptions&page=1" let proxy = "http://218.201.98.196:3128" let getPicJson = function () { return new Promise((resolve, reject) => { superagent .get(jsonUrl) .proxy(proxy) .end((err, res) => { if (err) console.log("代理出錯啦") if (res === undefined) return if (res.statusCode == 200) { let json = JSON.parse(res.text) resolve(json) } }) }) } // 獲取高清圖片api的json數(shù)據(jù) let dealHd = async function () { let picHd = [] let picJson = await getPicJson() let picLength = picJson.length for (let i = 1; i < picLength; i++) { let item = {} // let width = picJson[i].detail[0].width // let height = picJson[i].detail[0].height let il_id = picJson[i].detail[0].il_id item.title = picJson[i].detail[0].title item.url = `http://h.bilibili.com/wallpaperApi?action=getDetail&il_id=${il_id}` picHd.push(item) // item.url = `http://h.bilibili.com/wallpaper?action=detail&il_id=${il_id}&type=Bilibili&width=${width}&height=${height}` // picHtmlJson.push(item) } return picHd } // 獲取高清圖片的url ===== queue let dealPicJson = async function () { console.log("獲取高清圖片url,開始執(zhí)行....") var concurrencyCount = 0; let result = [] let hdJson = await dealHd() return new Promise((resolve, reject) => { let q = async.queue((hDJson, callback) => { var delay = parseInt((Math.random() * 30000000) % 1000, 10); //設(shè)置延時并發(fā)爬取 concurrencyCount++; console.log("現(xiàn)在的并發(fā)數(shù)是", concurrencyCount, ",正在獲取的是", hDJson.title, "延遲", delay, "毫秒"); superagent.get(hDJson.url).proxy(proxy).end((err, res) => { if (err) { console.log(err); callback(null); } else { // let $ = cheerio.load(res.text) // let hdUrl = $("#wallpaper").attr("id") // console.log("鏈接是" + hdUrl) let pic = {} pic.title = hDJson.title pic.url = res.body[0].detail[0].il_file pic.format = pic.url.match(/.{3}$/)[0] // console.log(result) result.push(pic) concurrencyCount -- callback(null) } }) }, 5) q.drain = function () { resolve(result) } q.push(hdJson) }) } // 下載HD圖片 let downloadImg = async function () { console.log("開始下載圖片..."); // let folder = `Data/img-${Config.currentImgType}-${Config.startPage}-${Config.endPage}`; // fs.mkdirSync(folder); let downloadCount = 0; var concurrencyCount = 0; let q = async.queue(function (image, callback) { // console.log("正在下載 : " + image.title); var delay = parseInt((Math.random() * 30000000) % 1000, 10); //設(shè)置延時并發(fā)爬取 concurrencyCount++; console.log("現(xiàn)在的并發(fā)數(shù)是", concurrencyCount, ",正在抓取的是", image.title, "延遲", delay, "毫秒"); superagent.get(image.url).proxy(proxy).end(function (err, res) { if (err) { console.log(err); callback(null); } else { downloadCount++; fs.writeFile(`./picture/${downloadCount}-${image.title}.${image.format}`, res.body, function (err) { if (err) { console.log(err); } else { console.log("圖片下載成功"); } setTimeout(() => { concurrencyCount--; callback(null); }, delay) }); } }); }, 5); // 當(dāng)所有任務(wù)都執(zhí)行完以后,將調(diào)用該函數(shù) q.drain = function () { console.log("All img download"); } let imgList = await dealPicJson(); q.push(imgList);//將所有任務(wù)加入隊列 } downloadImg()async控制并發(fā)
控制并發(fā)我通常是用async.maplimit,因?yàn)樽钤缃佑|
不過看到一篇文章介紹了async.queue,我就試了下
區(qū)別在于, mapLimit會返回所有并發(fā)任務(wù)結(jié)束后的結(jié)果數(shù)組
而queue是沒有的,因此要自己定個變量來存放每一個并發(fā)任務(wù)返回的結(jié)果
具體api用法見: async常用api
github代碼: bilibili壁紙站爬蟲
里面有一些必要注釋
有4個可以跑的js
./aboutIp/getIp.js (用來抓并存有用的代理ip)
./aboutIp/ipTest.js (測試ip可不可用)
app-thumbnails.js (用來爬壁紙的縮略圖)
app-hd.js (用來爬壁紙的高清圖)
雖然懂得很淺,但能漸漸感受到爬蟲的魅力了?
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/84795.html
摘要:站的彈幕服務(wù)器也有類似的機(jī)制,隨便打開一個未開播的直播間,抓包將看到每隔左右會給服務(wù)端發(fā)送一個心跳包,協(xié)議頭第四部分的值從修改為即可。 原文:B 站直播間數(shù)據(jù)爬蟲, 歡迎轉(zhuǎn)載項(xiàng)目地址:bilibili-live-crawler 前言 起因 去年在 B 站發(fā)現(xiàn)一個后期超強(qiáng)的 UP 主:修仙不倒大小眼,專出 PDD 這樣知名主播的吃雞精彩集錦,漲粉超快。于是想怎么做這樣的 UP,遇到的第一...
摘要:我又回頭看那個爬京東的程序哦我好像被反爬蟲發(fā)現(xiàn)了解決反爬蟲問題這下可以了吧直接點(diǎn)開鏈接看一下沒錯,火狐才是我的默認(rèn)瀏覽器終于不用再說交封不殺了。 昨晚終于提交了該死的31條CPU,今天十節(jié)課翹了八節(jié),躺在宿舍睡覺,不幸遇到幾百年難得一見的點(diǎn)名……然而當(dāng)時我在吃炸雞,沒法(懶)趕過去,達(dá)成第一次翹課就點(diǎn)名。 心情郁結(jié)的我打算看一看漂亮小姐姐開心一下,于是我發(fā)現(xiàn)了這個視頻:showImg(...
摘要:沒有結(jié)果返回百度搜索的可以指定頁碼,最多一頁個,使用后有效減少了連接次數(shù)。但親測下來設(shè)置過以后的結(jié)果與實(shí)際用戶在百度搜索的結(jié)果排序和個數(shù)都有出入。 showImg(https://segmentfault.com/img/bVbnA0I?w=1280&h=787); 一直有一個需求,希望看到自己網(wǎng)站在百度的實(shí)時的排名用過一些工具,要么反應(yīng)遲鈍,要么結(jié)果不準(zhǔn)確或不實(shí)時于是打算用jsoup...
摘要:今天為大家整理了個爬蟲項(xiàng)目。地址新浪微博爬蟲主要爬取新浪微博用戶的個人信息微博信息粉絲和關(guān)注。代碼獲取新浪微博進(jìn)行登錄,可通過多賬號登錄來防止新浪的反扒。涵蓋鏈家爬蟲一文的全部代碼,包括鏈家模擬登錄代碼。支持微博知乎豆瓣。 showImg(https://segmentfault.com/img/remote/1460000018452185?w=1000&h=667); 今天為大家整...
閱讀 2799·2021-11-04 16:15
閱讀 3478·2021-09-29 09:35
閱讀 4071·2021-09-22 15:45
閱讀 1428·2019-08-30 15:55
閱讀 1700·2019-08-30 15:44
閱讀 2741·2019-08-29 12:56
閱讀 2710·2019-08-26 13:30
閱讀 2184·2019-08-23 17:00