天天看點

python time 異常_python 高度魯棒性爬蟲的異常和逾時問題

爬蟲這類型程式典型特征是意外多,無法確定每次請求都是穩定的傳回統一的結果,要提高魯棒性,能對錯誤資料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