在R中萍恕,循環(huán)如果出錯逸嘀,程序就會被kill掉。對于計算開銷較大的循環(huán)來說雄坪,這樣的錯誤是難以忍受的厘熟。
- 一種方法是逐步地debug,針對所有的情況都能提供處理方案维哈,但是很費心費力绳姨;
- 一種方法是使用錯誤 異常控制函數(shù)阔挠,把錯誤跳過 或者說飘庄,提升對錯誤的容忍能力,即容錯性购撼。
針對第二種方法跪削,有try tryCatch等函數(shù)。網(wǎng)上雖然教程較少迂求,但是也能學(xué)個大概碾盐。最不濟,看R 幫助文件也是可以的揩局。本文毫玖,主要是記錄我遇到的問題和解決的方法。
問題背景
使用爬蟲爬取表格。該表格結(jié)構(gòu)簡單付枫,不涉及到動態(tài)網(wǎng)頁相關(guān)知識烹玉。問題就在于內(nèi)容較大,每頁有500行阐滩,有7000+頁二打。
- 網(wǎng)頁結(jié)構(gòu):靜態(tài)網(wǎng)頁
- url結(jié)構(gòu):有規(guī)律
- 網(wǎng)絡(luò)狀態(tài):較差,難以次次連接成功
- 出現(xiàn)的問題:連接不上(報錯)掂榔,連接超時(不報錯继效,但是爬蟲卡死了)
由于代碼涉及到項目,所以具體細(xì)節(jié)不能公開衅疙。這里只是說明類似的問題和提供解決的思路莲趣。
代碼撰寫
略,下文使用expr1
代表出現(xiàn)問題的代碼塊饱溢,其他expr\\d
表示用于處理該過程的代碼塊喧伞。
錯誤控制
- 針對
爬蟲連接網(wǎng)頁失敗,報錯并打斷進(jìn)程
的問題 - 使用的R基礎(chǔ)包中的函數(shù)
tryCatch
tryCatch(
expr1,
error=function(e){
expr2
},finnally = {
expr3
}
)
- tryCatch的思路是
- run expr1
- if expr1 is error, doing expr2
- finnally, weather expr1 error or not, doing expr3
- 我的代碼與下面類似:
while(i != m+1){
tryCatch(
{
expr1 # expr1是爬取網(wǎng)絡(luò)的代碼塊 绩郎,所以會遇到連接失敗的error
i = i+1 # 如果expr1有error潘鲫,則該語句不會運行,因而下一次循環(huán)使用的還是本次循環(huán)的i值
}, error = function(e){
cat("Sleeping for net connection agian at i = ", i, "\n")
Sys.sleep(10) # sleep 10s肋杖,而后重復(fù)發(fā)生了錯誤的那個i
}, finnaly = {
expr3 #是啥都行溉仑。我用來輸出循環(huán)信息
}
)
}
異常控制
- 針對
連接超時状植,導(dǎo)致循環(huán)停滯浊竟,爬蟲卡死
的問題 - 使用
R.utils
包的withTimeout
函數(shù) - 我的代碼類似于:
while(i != m+1){
tryCatch(
{
R.utils::withTimeout(
expr1,
timeout = 60
)
i = i+1
}, TimeoutException = function(ex){
message("Times out! Now refresh it") # 輸出提示信息。但是事實上Timeout函數(shù)已經(jīng)終止了expr1津畸,并開始下一次循環(huán)(i值不變)
}, error = function(e){
cat("Sleeping for net connection agian at i = ", i, "\n")
Sys.sleep(10) # sleep 10s振定,而后重復(fù)發(fā)生了錯誤的那個i
}, finnaly = {
expr3 #是啥都行。我用來輸出循環(huán)信息
}
)
}
感悟
爬取數(shù)據(jù)肉拓,雖然是爬后频,但是卻是比手動復(fù)制粘貼優(yōu)雅一千倍的貴族運動。電腦隨便爬去吧暖途,這邊看會兒生信技能樹卑惜、生信星球的推文或者去峽谷里維護(hù)一下正義,難道不香嗎驻售???