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