搜文章
推荐 原创 视频 Java开发 iOS开发 前端开发 JavaScript开发 Android开发 PHP开发 数据库 开发工具 Python开发 Kotlin开发 Ruby开发 .NET开发 服务器运维 开放平台 架构师 大数据 云计算 人工智能 开发语言 其它开发
Lambda在线 > Python开发者 > python 高度健壮性爬虫的异常和超时问题

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

Python开发者 2017-11-19


来源:伯乐在线专栏作者 - 路易十四

如需转载,发送「转载」二字查看说明


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


目录:


  • 一:基础try&except异常处理

  • 二:普通请求函数的超时处理

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

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

  • 五:自定义线程的死锁or超时处理

  • 六:自重启的程序设计


一:基础try&except异常处理


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


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


try:

    passhttp://top.jobbole.com/deliver-article/#

    #可能出错的语句

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的超时设置


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


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


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(){

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)来处理


#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 processprocess.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()


六:自重启的程序设计


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


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()


看完本文有帮助?请转发分享给更多人

关注「Python开发者」,提升Python技能

专栏作者简介 )


路易十四:少年程序猿,从事数据采集挖掘方面:个人博客,www.urlteam.org,邮箱:a83533774@gmail.com主要技能树:python,爬虫,linux,web前端,ACM,骑行。

打赏支持作者写出更多好文章,谢谢

版权声明:本站内容全部来自于腾讯微信公众号,属第三方自助推荐收录。《python 高度健壮性爬虫的异常和超时问题》的版权归原作者「Python开发者」所有,文章言论观点不代表Lambda在线的观点, Lambda在线不承担任何法律责任。如需删除可联系QQ:516101458

文章来源: 阅读原文

相关阅读

关注Python开发者微信公众号

Python开发者微信公众号:PythonCoder

Python开发者

手机扫描上方二维码即可关注Python开发者微信公众号

Python开发者最新文章

精品公众号随机推荐