爬虫技术(05)神箭手爬虫回调函数
回調(diào)函數(shù)是在神箭手應(yīng)用爬取并處理網(wǎng)頁的過程中設(shè)置的一些系統(tǒng)鉤子, 通過這些鉤子可以完成一些特殊的處理邏輯.
回調(diào)函數(shù)需要設(shè)置到configs對象中才起作用
下圖是采集爬蟲爬取并處理網(wǎng)頁的流程圖, 矩形方框中標(biāo)識了采集爬蟲運(yùn)行過程中所使用的重要回調(diào)函數(shù):
(1)beforeCrawl(site)
神箭手應(yīng)用初始化時(shí)調(diào)用, 用來進(jìn)行一些爬取前的操作, 栗如, 給所有HTTP請求添加Headers等
@param site site對象. site表示當(dāng)前正在爬取的目標(biāo)網(wǎng)站對象在beforeCrawl回調(diào)函數(shù)中可調(diào)用addHeader等site對象的方法.
在神箭手應(yīng)用的代碼中均可使用.
通用栗子:
在采集爬蟲初始化時(shí)給其所有的HTTP請求添加一個(gè)Header
configs.beforeCrawl = function(site) {site.addHeader("Referer", "http://www.demo.cn/"); };(2)beforeDownloadPage(page, site)
在一個(gè)網(wǎng)頁下載或JS渲染開始之前調(diào)用, 主要用來處理網(wǎng)頁url
@param page 網(wǎng)頁對象. page.raw值為空, page表示當(dāng)前正在爬取的網(wǎng)頁對象 @param site site對象. @return 處理后的網(wǎng)頁對象在神箭手應(yīng)用的代碼中均可使用
通用栗子:
下載某個(gè)網(wǎng)頁之前, 如果網(wǎng)頁url中未包含&page=, 則給網(wǎng)頁url添加該字符串, 處理過程如下:
configs.beforeDownloadPage = function(page, site) {if (page.url.indexOf("&page=") == -1) {page.url = page.url + "&page=1";}return page; };(3)onChangeProxy(site, page)
在神箭手應(yīng)用切換代理IP后調(diào)用, 主要用來給HTTP請求添加Header和Cookie等數(shù)據(jù)
@param site site對象. @param page 網(wǎng)頁對象.必備條件: 開啟代理IP切換
切換代理IP后, 先前HTTP請求添加的Cookie會被清除, 若打算繼續(xù)使用Cookie, 強(qiáng)烈建議在onChangeProxy回調(diào)函數(shù)中添加Cookie
在神箭手應(yīng)用的代碼中均可使用
通用栗子:
默認(rèn)已經(jīng)開啟代理IP切換, 在神箭手應(yīng)用切換代理IP后, 調(diào)用site.requestUrl后請求網(wǎng)頁返回的Cookie會添加到網(wǎng)頁域名中, 供后續(xù)符合該網(wǎng)頁域名的HTTP請求使用.
var configs = {// configs的成員... };configs.onChangeProxy = function(site, page) {site.requestUrl("http://www.demo.cn/"); };(4)isAntiSpider(url, content, page)
判斷訪問網(wǎng)頁時(shí)是否被目標(biāo)網(wǎng)站屏蔽, 如果判斷被屏蔽了, 神箭手會切換一次代理IP后自動(dòng)重新爬取(前提: 開啟代理IP切換)
@param url 網(wǎng)頁url, String類型 @param content 返回的網(wǎng)頁內(nèi)容, String類型 @param page 網(wǎng)頁對象. 點(diǎn)此查看page對象詳解 @return 判斷是否被目標(biāo)網(wǎng)站屏蔽的標(biāo)識, 布爾類型. 如果判斷被目標(biāo)網(wǎng)站屏蔽, 返回true; 如果判斷未被目標(biāo)網(wǎng)站屏蔽, 返回false在神箭手應(yīng)用的代碼中均可使用
通用栗子:
var configs = {// configs的成員... };configs.isAntiSpider = function(url, content, page) {// 判斷返回的網(wǎng)頁內(nèi)容是否包含"404頁面不存在"if (content.indexOf("404頁面不存在") !== -1) {// 返回"true",// 表示判斷此時(shí)被目標(biāo)網(wǎng)站屏蔽了,// 神箭手會切換一次代理IP后自動(dòng)重新爬取return true;}// 默認(rèn)返回"false",// 判斷未被目標(biāo)網(wǎng)站屏蔽return false; };注意:
(5)afterDownloadPage(page, site)
在一個(gè)網(wǎng)頁下載或JS渲染完成之后調(diào)用, 主要用來處理網(wǎng)頁
@param page 網(wǎng)頁對象. @param site site對象. @return 處理后的網(wǎng)頁對象在神箭手應(yīng)用的代碼中均可使用
通用栗子:
下載了某個(gè)網(wǎng)頁, 希望向網(wǎng)頁的body中添加HTML代碼, 處理過程如下:
configs.afterDownloadPage = function(page, site) {var pageHtml = '<div id="num"><span>5</span></div>';var index = page.raw.indexOf("</body>");page.raw = page.raw.substring(0, index) + pageHtml + page.raw.substring(index);return page; };(6)onProcessScanPage(page, content, site)
在下載入口頁內(nèi)容之后, 發(fā)現(xiàn)并添加新url到待爬隊(duì)列之前調(diào)用. 主要用來手動(dòng)添加需要爬取的新url到待爬隊(duì)列中
@param page 入口頁對象. @param content 入口頁的內(nèi)容, String類型 @param site site對象. @return 是否需要在入口頁內(nèi)容中自動(dòng)發(fā)現(xiàn)新url, 布爾類型. 默認(rèn)返回true, 表示需要, 返回false, 表示不需要在onProcessScanPage回調(diào)函數(shù)中可調(diào)用site對象的addScanUrl函數(shù)將新入口頁url添加到待爬隊(duì)列中
在采集爬蟲代碼中可使用
采集爬蟲栗子1:
實(shí)現(xiàn)這個(gè)回調(diào)函數(shù)并返回false, 表示采集爬蟲在處理這個(gè)入口頁url的時(shí)候, 不會從網(wǎng)頁中自動(dòng)發(fā)現(xiàn)新url
configs.onProcessScanPage = function(page, content, site) {return false; };采集爬蟲栗子2:
根據(jù)入口頁的內(nèi)容生成需爬取的列表頁url, 添加到待爬隊(duì)列中, 并通知采集爬蟲不再從當(dāng)前網(wǎng)頁中自動(dòng)發(fā)現(xiàn)新url
configs.onProcessScanPage = function(page, content, site) {var jsonObj = JSON.parse(page.raw);for (var i = 0, n = jsonObj.data.length; i < n; i++) {var item = jsonObj.data[i];var lastid = item._id;// 生成待爬取的第一個(gè)列表頁urlvar url = page.url + lastid;// 將新url添加到待爬隊(duì)列中site.addUrl(url);}// 不再從當(dāng)前網(wǎng)頁中自動(dòng)發(fā)現(xiàn)新urlreturn false; };(7)onProcessHelperPage(page, content, site)
在下載列表頁內(nèi)容之后, 發(fā)現(xiàn)并添加新url到待爬隊(duì)列之前調(diào)用. 主要用來手動(dòng)添加需要爬取的新url到待爬隊(duì)列中
@param page 列表頁對象. 點(diǎn)此查看page對象詳解 @param content 列表頁的內(nèi)容, String類型 @param site site對象. 點(diǎn)此查看site對象詳解 @return 是否需要在列表頁內(nèi)容中自動(dòng)發(fā)現(xiàn)新url, 布爾類型. 默認(rèn)返回true, 表示需要, 返回false, 表示不需要在onProcessHelperPage回調(diào)函數(shù)中可調(diào)用site對象的addUrl函數(shù)將新列表頁和內(nèi)容頁url添加到待爬隊(duì)列中
在采集爬蟲代碼中可使用
采集爬蟲栗子1:
實(shí)現(xiàn)這個(gè)回調(diào)函數(shù)并返回false, 表示采集爬蟲在處理這個(gè)列表頁url的時(shí)候, 不會從網(wǎng)頁中自動(dòng)發(fā)現(xiàn)新url
configs.onProcessHelperPage = function(page, content, site) {return false; };采集爬蟲栗子2:
根據(jù)列表頁的內(nèi)容生成需爬取的內(nèi)容頁url, 添加到待爬隊(duì)列中, 并通知采集爬蟲不再從當(dāng)前網(wǎng)頁中自動(dòng)發(fā)現(xiàn)新url
configs.onProcessHelperPage = function(page, content, site) {for (var i = 1; i <= 100; i++) {// 將拼出的新url添加到待爬隊(duì)列中site.addUrl("http://www.demo.com/pageNum=" + i);}// 不再從當(dāng)前網(wǎng)頁中自動(dòng)發(fā)現(xiàn)新urlreturn false; };(8)onProcessContentPage(page, content, site)
在下載內(nèi)容頁內(nèi)容之后, 發(fā)現(xiàn)并添加新url到待爬隊(duì)列之前調(diào)用. 主要用來手動(dòng)添加需要爬取的新url到待爬隊(duì)列中
@param page 內(nèi)容頁對象. 點(diǎn)此查看page對象詳解 @param content 內(nèi)容頁的內(nèi)容, String類型 @param site site對象. 點(diǎn)此查看site對象詳解 @return 是否需要在內(nèi)容頁內(nèi)容中自動(dòng)發(fā)現(xiàn)新url, 布爾類型. 默認(rèn)返回true, 表示需要, 返回false, 表示不需要在onProcessContentPage回調(diào)函數(shù)中可調(diào)用site對象的addUrl函數(shù)將新列表頁和內(nèi)容頁url添加到待爬隊(duì)列中
在采集爬蟲代碼中可使用
采集爬蟲栗子1:
實(shí)現(xiàn)這個(gè)回調(diào)函數(shù)并返回false, 表示采集爬蟲在處理這個(gè)內(nèi)容頁url的時(shí)候, 不會從網(wǎng)頁中自動(dòng)發(fā)現(xiàn)新url
configs.onProcessContentPage = function(page, content, site) {return false; };采集爬蟲栗子2:
在onProcessContentPage回調(diào)函數(shù)中, 如果發(fā)現(xiàn)內(nèi)容頁中包含404 ERROR!, 則跳過當(dāng)前內(nèi)容頁url, 并通知采集爬蟲不再從當(dāng)前網(wǎng)頁中自動(dòng)發(fā)現(xiàn)新url
configs.onProcessContentPage = function(page, content, site) {// 判斷page.raw中是否包含"404 ERROR!"if (page.raw.indexOf("404 ERROR!") !== -1) {// 跳過當(dāng)前爬取的內(nèi)容頁page.skip();}// 不再從當(dāng)前網(wǎng)頁中自動(dòng)發(fā)現(xiàn)新urlreturn false; };(9)afterDownloadAttachedPage(page, site)
在一個(gè)attachedUrl對應(yīng)的網(wǎng)頁下載或JS渲染完之后調(diào)用, 主要用來處理網(wǎng)頁
@param page 網(wǎng)頁對象. 點(diǎn)此查看page對象詳解 @param site site對象. 點(diǎn)此查看site對象詳解 @return 處理后的網(wǎng)頁對象在神箭手應(yīng)用的代碼中均可使用
通用栗子:
下載的網(wǎng)頁需去掉前后兩邊的中括號, 并將處理后的網(wǎng)頁對象返回, 處理過程如下:
configs.afterDownloadAttachedPage = function(page, site) {var data = page.raw;var start = data.indexOf("[") + 1;var end = data.lastIndexOf("]");page.raw = data.substring(start, end);return page; };(10)beforeHandleImg(fieldName, img)
從內(nèi)容頁中抽取到一個(gè)抽取項(xiàng)的值之后調(diào)用, 對其中包含的img標(biāo)簽進(jìn)行處理
@param fieldName 抽取項(xiàng)的名字, String類型. 子抽取項(xiàng)的名字會帶著父抽取項(xiàng)的名字, 通過.連接, 如, images.image_url @param img img標(biāo)簽, String類型 @return 處理后的img標(biāo)簽, String類型很多網(wǎng)站對圖片設(shè)置了延遲加載, 這時(shí)就需要在beforeHandleImg回調(diào)函數(shù)中處理
在神箭手應(yīng)用的代碼中均可使用
通用栗子:
汽車之家論壇帖子的圖片大部分是延遲加載的, 默認(rèn)會使用http://x.autoimg.cn/club/lazyload.png圖片url, 需要獲取真實(shí)的圖片url并替換, 具體實(shí)現(xiàn)如下:
configs.beforeHandleImg = function(fieldName, img) {if (fieldName == "detail") {// 通過正則匹配"img"中的"src9"屬性獲取真實(shí)圖片urlvar m = /src9=\"(https?[:\/]+.*?)\"/.exec(img);if (m) {// 默認(rèn)圖片urlvar url = "http://x.autoimg.cn/club/lazyload.png";// 真實(shí)圖片urlvar newUrl = m[1];// 將默認(rèn)圖片url替換成真實(shí)圖片urlimg = img.replace(url, newUrl);}}return img; };(11)beforeCacheImg(fieldName, url)
在對爬取到的圖片url進(jìn)行托管處理之前調(diào)用, 主要對托管的圖片url進(jìn)行處理
@param fieldName 抽取項(xiàng)的名字, String類型. 子抽取項(xiàng)的名字會帶著父抽取項(xiàng)的名字, 通過.連接, 如, images.image_url @param url 圖片url, String類型 @return 處理后的圖片url, String類型在神箭手應(yīng)用的代碼中均可使用
通用栗子:
知乎問答頁面, 用戶的頭像url是這樣的: https://pic3.zhimg.com/xxxxxx_s.jpg
研究一下可以發(fā)現(xiàn), 大一點(diǎn)的頭像url是這樣的: https://pic3.zhimg.com/xxxxxx_l.jpg
configs = {// configs的其他成員...fields: [// 其他"field"...{name: "answers",selector: "//div[contains(@class,'answers')]",repeated: true,children: [{name: "avatar",selector: "//div[contains(@class,'answer-avatar')]"}]}] };configs.beforeCacheImage = function(fieldName, url) {if (fieldName == "answers.avatar") {// 對url進(jìn)行字符串替換, 得到較大圖片的url, 并返回return url.replace("_s.jpg", "_l.jpg");}// 返回未處理的圖片urlreturn url; };(12)afterExtractField(fieldName, data, page, site)
從內(nèi)容頁中抽取到一個(gè)抽取項(xiàng)的值后進(jìn)行的回調(diào), 在此回調(diào)中可以對該抽取項(xiàng)的值進(jìn)行處理并返回
@param fieldName 抽取項(xiàng)的名字, String類型. 子抽取項(xiàng)的名字會帶著父抽取項(xiàng)的名字, 通過.連接, 如, images.image_url @param data 抽取結(jié)果, 即抽取項(xiàng)的值 @param page 內(nèi)容頁對象. 點(diǎn)此查看page對象詳解 @param site site對象. 點(diǎn)此查看site對象詳解 @return 處理后的抽取結(jié)果, 數(shù)據(jù)類型請和處理前”data”的數(shù)據(jù)類型保持一致; 否則, 神箭手會自動(dòng)強(qiáng)制轉(zhuǎn)換成”data”的數(shù)據(jù)類型, 如果轉(zhuǎn)換失敗, 會返回空值在神箭手應(yīng)用的代碼中均可使用
通用栗子:
configs = {// configs的其他成員...fields: [{name: "interests",repeated: true},{name: "gender",selector: "XXX"},{name: "time"}] };configs.afterExtractField = function(fieldName, data, page, site) {if (fieldName == "interests") {data = ["足球", "看書", "健身"];// 由于"interests"抽取項(xiàng)是數(shù)組類型, 返回值是數(shù)組類型return data;}if (fieldName == "gender") {// 由于"gender"抽取項(xiàng)是String類型, 返回值是String類型if (data == "male") return "男";else if (data == "female") return "女";else return "未知";}if (fieldName == "time") {// 獲取到當(dāng)前時(shí)間的秒級時(shí)間戳并賦值給"data",// "data"是"float"類型,data = new Date().getTime()/1000;// 返回整型時(shí)間戳return parseInt(data);}return data; };(13)afterExtractPage(page, data, site)
在內(nèi)容頁的所有抽取項(xiàng)抽取完成之后, 在此回調(diào)函數(shù)中對抽取項(xiàng)再進(jìn)行一次處理或進(jìn)行其他操作
@param page 內(nèi)容頁對象. 點(diǎn)此查看page對象詳解 @param data 內(nèi)容頁的抽取結(jié)果, JS對象 @param site site對象. 點(diǎn)此查看site對象詳解 @return 處理后的data對象在神箭手應(yīng)用的代碼中均可使用
通用栗子:
var configs = {// configs的其他成員...fields: [{name: "title",selector: "XXX"},{name: "time",selector: "XXX"},{name: "tags",repeated: true},{name: "time"}] };configs.afterExtractPage = function(page, data, site) {// 得到字符串"t"var t = "[" + data.time + "] " + data.title;// 將"t"賦值給"title"抽取項(xiàng)// 由于"title"抽取項(xiàng)是String類型, "data.title"也必須是String類型data.title = t;// 由于"tags"抽取項(xiàng)是數(shù)組類型, "data.tags"也必須是數(shù)組類型data.tags = ["新聞", "人物"];// 將當(dāng)前時(shí)間轉(zhuǎn)換成秒級時(shí)間戳賦值給"time"抽取項(xiàng)data.time = parseInt(new Date().getTime()/1000);// 返回處理后的"data"對象return data; };總結(jié)
以上是生活随笔為你收集整理的爬虫技术(05)神箭手爬虫回调函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [Pytorch系列-35]:卷积神经网
- 下一篇: 对一个整形数组进行顺序排列