爬蟲這類型程式典型特征是意外多,無法確定每次請求都是穩定的傳回統一的結果,要提高魯棒性,能對錯誤資料or逾時or程式死鎖等都能進行處理,才能確定程式幾個月不停止。本項目乃長期維護github:反反爬蟲開源庫中積累下來,更多幹貨歡迎star。
目錄:一:基礎try&except異常處理
二:普通請求函數的逾時處理
三:selenium+chrome | phantomjs 的逾時處理
四:自定義函數的死鎖or逾時處理
五:自定義線程的死鎖or逾時處理
六:自重新開機的程式設計
一:基礎try&except異常處理
try&except的語句作用不僅僅是要讓其捕獲異常更重要的是讓其忽略異常,因為爬蟲中的絕大多數異常可能重新請求就不存在,是以,發現異常的時候将其任務隊列進行修複其實是個最省力的好辦法。
其次被try包住的語句即使出錯也不會導緻整個程式的退出,相信我,你絕對不希望計劃跑一個周末的程式在半夜停止了。
try:
pass
#可能出錯的語句
except Exception,e:
pass
#保留錯誤的url,留待下次重跑
print e
finally:
#無論是否處理了異常都繼續運作
print time.ctime()
二:請求函數的逾時處理
2.1:普通請求:
2.1.1單請求類型:
import requests
requests.get(url,timeout=60)
2.1.2會話保持類型:
import requesocks
session = requesocks.session()
response = session.get(URL,headers=headers,timeout=10)
三:selenium+chrome | phantomjs 的逾時處理
2.2.1:selenium+chrome的逾時設定
顯式等待:、等待某個條件發生,然後再繼續進行代碼。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delays_loading")
try:
element = WebDriverWait(driver, 10).until( #這裡修改時間
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
finally:
driver.quit()
隐式等待:是告訴WebDriver在嘗試查找一個或多個元素(如果它們不是立即可用的)時輪詢DOM一定時間。預設設定為0,一旦設定,将為WebDriver對象執行個體的生命期設定隐式等待。
from selenium import webdriver
driver = webdriver.Firefox()
driver.implicitly_wait(10) # seconds
driver.get("http://somedomain/url_that_delays_loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")
2.2.2:phantomjs的逾時設定
這裡使用不帶selenium的phantomjs,需要使用js。主要設定語句
page.settings.resourceTimeout = 5000; // 等待5秒
var system = require('system');
var args = system.args;
var url = args[1];
var page = require('webpage').create();
page.settings.resourceTimeout = 5000; // 等待5秒
page.onResourceTimeout = function(e) {
console.log(e.errorCode); //列印錯誤碼
console.log(e.errorString); // 列印錯誤語句
console.log(e.url); //列印錯誤url
phantom.exit(1);
};
page.open(url, function(status) {
if (status === 'success') {
var html = page.evaluate(function() {
return document.documentElement.outerHTML;
});
console.log(html);
}
phantom.exit();
});
//$phantomjs xx.js http://bbs.pcbaby.com.cn/topic-2149414.html
四:自定義函數的死鎖or逾時處理
這個非常重要!!
python是順序執行的,但是如果下一句話可能導緻死鎖(比如一個while(1))那麼如何強制讓他逾時呢?他本身如果沒有帶有逾時設定的話,就要自己運作信号(import signal)來處理
#coding:utf-8
import time
import signal
def test(i):
time.sleep(0.999)#模拟逾時的情況
print "%d within time"%(i)
return i
def fuc_time(time_out):
# 此為函數逾時控制,替換下面的test函數為可能出現未知錯誤死鎖的函數
def handler(signum, frame):
raise AssertionError
try:
signal.signal(signal.SIGALRM, handler)
signal.alarm(time_out)#time_out為逾時時間
temp = test(1) #函數設定部分,如果未逾時則正常傳回資料
return temp
except AssertionError:
print "%d timeout"%(i)# 逾時則報錯
if __name__ == '__main__':
for i in range(1,10):
fuc_time(1)
五:自定義線程的死鎖or逾時處理
在某個程式中一方面不适合使用selenium+phantomjs的方式(要實作的功能比較難不适合)因為隻能用原生的phantomjs,但是這個問題他本身在極端情況下也有可能停止(在逾時設定之前因為某些錯誤)
那麼最佳方案就是用python單獨開一個線程(程序)調用原生phantomjs,然後對這個線程程序進行逾時控制。
這裡用ping這個指令先做測試,
import subprocess
from threading import Timer
import time
kill = lambda process: process.kill()
cmd = ["ping", "http://www.google.com"]
ping = subprocess.Popen(
cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
my_timer = Timer(5, kill, [ping])#這裡設定時間,和指令
try:
my_timer.start()#啟用
stdout, stderr = ping.communicate()#獲得輸出
#print stderr
print time.ctime()
finally:
print time.ctime()
my_timer.cancel()
六:自重新開機的程式設計
比如程式在某種情況下報錯多次,,那麼滿足條件後,讓其重新開機即可解決大多數問題,當然這隻不過是治标不治本而已,如果這個程式重新開機沒有大問題(例如讀隊列類型)那麼自重新開機這是最省力的方式之一。
import time,sys,os
def restart_program():
python = sys.executable
os.execl(python, python, * sys.argv)
if __name__ == "__main__":
print 'start...'
print u"3秒後,程式将結束...".encode("utf8")
time.sleep(3)
restart_program()
原創文章,轉載請注明: 轉載自URl-team