python 高度健壮性爬虫的异常和超时问题



爬虫这类型程序典型特征是意外多,无法确保每次请求都是稳定的返回统一的结果,要提高健壮性,能对错误数据or超时or程序死锁等都能进行处理,才能确保程序几个月不停止。本项目乃长期维护github:反反爬虫开源库中积累下来,更多干货欢迎star。

目录:

  • 一:基础try&except异常处理
  • 二:普通请求函数的超时处理
  • 三:selenium+chrome  | phantomjs 的超时处理
  • 四:自定义函数的死锁or超时处理
  • 五:自定义线程的死锁or超时处理
  • 六:自重启的程序设计

一:基础try&except异常处理

try&except的语句作用不仅仅是要让其捕获异常更重要的是让其忽略异常,因为爬虫中的绝大多数异常可能重新请求就不存在,因此,发现异常的时候将其任务队列进行修复其实是个最省力的好办法。

其次被try包住的语句即使出错也不会导致整个程序的退出,相信我,你绝对不希望计划跑一个周末的程序在半夜停止了。

 
 
 
 
 
Python
 
1
2
3
4
5
6
7
8
9
10
  try :
     passhttp : / / top . jobbole . com / deliver - article / #
     #可能出错的语句
except Exception , e :
     pass
     #保留错误的url,留待下次重跑
     print e
finally :
     #无论是否处理了异常都继续运行
     print time . ctime ( )

 

二:请求函数的超时处理

2.1:普通请求:

2.1.1单请求类型:

 
 
 
 
 
Python
 
1
2
import requests
requests . get ( url , timeout = 60 )

 

2.1.2会话保持类型:

 

 
 
 
 
 
Python
 
1
2
3
import requesocks
session = requesocks . session ( )
response = session . get ( URL , headers = headers , timeout = 10 )

 

三:selenium+chrome  | phantomjs 的超时处理

2.2.1:selenium+chrome的超时设置

官网原文:http://selenium-python.readthedocs.io/waits.html

显式等待:、等待某个条件发生,然后再继续进行代码。

 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
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对象实例的生命期设置隐式等待。

 
 
 
 
 
 
1
2
3
4
5
6
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。主要设置语句是

 
 
 
 
 
JavaScript
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 ) ; & nbsp ; & nbsp ; //打印错误码
console . log ( e . errorString ) ; //打印错误语句
console . log ( e . url ) ; & nbsp ; & nbsp ; & nbsp ; & nbsp ; //打印错误url
phantom . exit ( 1 ) ;
} ;
page . open ( url , function ( status ) {
if ( status === 'success' ) {
var html = page . evaluate ( function ( ) {
returndocument . documentElement . outerHTML ;
} ) ;
console . log ( html ) ;
}
phantom . exit ( ) ;
} ) ;
//$phantomjs xx.js http://bbs.pcbaby.com.cn/topic-2149414.html

 

四:自定义函数的死锁or超时处理

这个非常重要!!

python是顺序执行的,但是如果下一句话可能导致死锁(比如一个while(1))那么如何强制让他超时呢?他本身如果没有带有超时设置的话,就要自己运行信号(import signal)来处理

 
 
 
 
 
Python
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#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这个命令先做测试,

 
 
 
 
 
Python
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import subprocess
from threading import Timer
import time
 
kill = lambda process : process . kill ( )
 
cmd = [ "ping" , "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 ( )

 

六:自重启的程序设计

比如程序在某种情况下报错多次,,那么满足条件后,让其重启即可解决大多数问题,当然这只不过是治标不治本而已,如果这个程序重启没有大问题(例如读队列类型)那么自重启这是最省力的方式之一。

 
 
 
 
 
Python
 
1
2
3
4
5
6
7
8
9
10
11
12
import time
import sys
import 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 ( )
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

熊野君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值