专栏首页Urlteampython 高度鲁棒性爬虫的超时控制问题

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

官网原文: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。主要设置语句是

<span style="color: #ff0000;">page.settings.resourceTimeout = 5000; // 等待5秒</span>
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", "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...'
#  answer = raw_input("Do you want to restart this program ? ")
#  if answer.strip() in "y Y yes Yes YES".split():
#    restart_program()
  print u"3秒后,程序将结束...".encode("utf8")
  time.sleep(3)
  restart_program()

原创文章,转载请注明: 转载自URl-team

本文链接地址: python 高度鲁棒性爬虫的超时控制问题

  1. selenium自动登录挂stackoverflow的金牌
  2. python 爬虫资源包汇总
  3. python 进程超时控制 防止phantomjs假死
  4. 数据采集技术指南 第一篇 技术栈总览-附总图和演讲ppt
  5. 淘宝商品信息采集器二,开放源码可自定义关键词进行采集
  6. Python模拟登录的几种方法(转)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • python语音智能对话聊天机器人,linux&&树莓派双平台兼容

    项目简介:运用百度语音进行声音转中文的识别与合成,智能对话使用图灵机器人,录音则,linux端用pythonaudio 模块.树莓派端因为pythonaudio...

    十四君
  • 树莓派 python 百度语音控制 gpio 控制开关灯

    最初拿到树莓派的时候测试过,没成功,后来发现一张华丽丽的说明图,顿时醒悟了..记录下来,

    十四君
  • 创新实验室python&linux零下五度小组技能树规划

    规则一:每天晚上七点,固定学习时间,一律到讨论组里报道。一周允许有两次缺席,我自己记录在案,一周内有四次以上未到,则剔除出组。

    十四君
  • from __future__ import print_function 用法

    在开头加上from __future__ import print_function这句之后,即使在python2.X,使用print就得像python3.X那...

    KEVINGUO_CN
  • 一个oracle查询引起的bug (r4笔记第59天)

    任何软件都不是完美的,oracle也是如此,隔一段时间就会收到oracle的邮件说建议打哪些安全补丁什么的。新发布的产品都是release 1,比如10gR1...

    jeanron100
  • iOS 系统中的视图动画

    动画为用户界面的状态转换提供了流畅的可视化效果, 在 iOS 中大量使用了动画效果, 包括改变视图位置、 大小、 从可视化树中删除视图, 隐藏视图等。 你可以考...

    beginor
  • Geant4-怎样设置你的粒子源--精简注释+收藏版

    一个通用的粒子发生函数源文件,即MYPrimaryGeneratorAction.cc大致就是本文的全部了。同现实场景相符,你需要知道每个发射的模拟粒子的特点,...

    梁佐佐
  • 你不应该忽略的五个机器学习项目一览

    随着人工智能和深度学习的兴起,网络上存在的学习资源以及开源项目也越来越多。本文精选了的五个项目,都含有潜在新的机器学习想法,且全都是用Pytho...

    用户3578099
  • 第十二章:其他特性

    Quartz提供了一个用于插入附加功能的接口org.quartz.spi.SchedulerPlugin。

    Throwable
  • 什么是队列?

    与前面提到的数据结构相同,队列中的数据也呈线性排列。虽然与栈有些相似,但队列中添加和删除数据的操作分别是在两端进行的,就和队列这个名字一样,把它想象成排成一队的...

    武培轩

扫码关注云+社区

领取腾讯云代金券