Python 如何使用pycurl很好地处理键盘中断(Ctrl-c)?

Python 如何使用pycurl很好地处理键盘中断(Ctrl-c)?,python,curl,pycurl,twitter-streaming-api,Python,Curl,Pycurl,Twitter Streaming Api,我正在编写一个用于消费的Python脚本。下面是一个简短的代码片段,正好可以做到这一点(只需输入您的Twitter登录名/密码即可进行测试): 问题在于,由于脚本使用流,conn.perform()永远不会返回(或者很少返回)。因此,我有时需要中断脚本,KeyboardInterrupt被perform()方法捕获 然而,它不能很好地处理它,打印出一个丑陋的错误,并引发一个不同的异常 ^CTraceback (most recent call last): File "test.py", l

我正在编写一个用于消费的Python脚本。下面是一个简短的代码片段,正好可以做到这一点(只需输入您的Twitter登录名/密码即可进行测试):


问题在于,由于脚本使用流,
conn.perform()
永远不会返回(或者很少返回)。因此,我有时需要中断脚本,
KeyboardInterrupt
perform()
方法捕获

然而,它不能很好地处理它,打印出一个丑陋的错误,并引发一个不同的异常

^CTraceback (most recent call last):
  File "test.py", line 6, in handleData
    def handleData(data):
KeyboardInterrupt
Traceback (most recent call last):
  File "test.py", line 12, in <module>
    conn.perform()
pycurl.error: (23, 'Failed writing body (0 != 2203)')
我得到:

^CTraceback (most recent call last):
  File "test.py", line 6, in handleData
    def handleData(data):
KeyboardInterrupt
We caught the exception
<class 'pycurl.error'>
^CTraceback(最近一次通话最后一次):
handleData中的文件“test.py”,第6行
def handleData(数据):
键盘中断
我们抓住了例外

这意味着在内部,
pycurl
执行某种捕获,打印一条丑陋的错误消息,然后引发一个
pycurl.error

您可以通过捕获pycurl.error类型来实现这一点。例:

try:
    conn.perform()
except pycurl.error, e:
    errorCode, errorText = e.args
    print 'We got an error. Code: %s, Text:%s'%(errorCode, errorText)

您需要捕获CTRL+C并处理该信号
原件:
原件:


示例1

#!/usr/bin/env python
import signal
import sys
def signal_handler(signal, frame):
        print 'You pressed Ctrl+C!'
        sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
print 'Press Ctrl+C'
signal.pause()

示例2

import signal, os

def handler(signum, frame):
    print 'Signal handler called with signal', signum
    raise IOError("Couldn't open device!")

# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)

# This open() may hang indefinitely
fd = os.open('/dev/ttyS0', os.O_RDWR)

signal.alarm(0)          # Disable the alarm

至少在twitter链接上有些东西不起作用,请参见

  • 不要忘记在连接执行()之后加上连接关闭()
在测试时启用调试模式是很有帮助的

import pycurl

username = 'your_user_name'
password = 'your_password'

def body(buf):
    for item in buf.strip().split('\n'):
        if item.strip():
            print item

def test(debug_type, debug_msg):
    if len(debug_msg) < 300:
        print "debug(%d): %s" % (debug_type, debug_msg.strip())

conn = pycurl.Curl()  
conn.setopt(pycurl.USERNAME, username)
conn.setopt(pycurl.PASSWORD, password)
#conn.setopt(pycurl.SSL_VERIFYPEER, False)
conn.setopt(pycurl.FOLLOWLOCATION, True)
conn.setopt(pycurl.VERBOSE, True)
conn.setopt(pycurl.URL, 'https://stream.twitter.com/1.1/statuses/sample.json')  
conn.setopt(pycurl.DEBUGFUNCTION, test)
conn.setopt(pycurl.WRITEFUNCTION, body)
conn.perform()
conn.close()
导入pycurl
用户名='your_user_name'
密码='您的密码'
def主体(buf):
对于buf.strip().split('\n')中的项:
if item.strip():
打印项目
def测试(调试类型、调试消息):
如果len(debug_msg)<300:
打印“调试(%d):%s”%(调试类型,调试消息条()
conn=pycurl.Curl()
conn.setopt(pycurl.USERNAME,USERNAME)
conn.setopt(pycurl.PASSWORD,PASSWORD)
#conn.setopt(pycurl.SSL_VERIFYPEER,False)
conn.setopt(pycurl.FOLLOWLOCATION,True)
conn.setopt(pycurl.VERBOSE,True)
conn.setopt(pycurl.URL,'https://stream.twitter.com/1.1/statuses/sample.json')  
conn.setopt(pycurl.DEBUGFUNCTION,test)
conn.setopt(pycurl.WRITEFUNCTION,body)
康涅狄格州执行
康涅狄格州关闭

只需复制/粘贴工作测试示例

➜  ~  hcat twitter.py 
import pycurl
import signal
import sys
from time import sleep

username = 'bubudee'
password = 'deebubu'

def body(buf):
    for item in buf.strip().split('\n'):
        if item.strip():
            print item

def test(debug_type, debug_msg):
    if len(debug_msg) < 300:
        print "debug(%d): %s" % (debug_type, debug_msg.strip())

def handle_ctrl_c(signal, frame):
    print "Got ctrl+c, going down!"
    sys.exit(0)
signal.signal(signal.SIGINT, handle_ctrl_c)

conn = pycurl.Curl()  
conn.setopt(pycurl.USERNAME, username)
conn.setopt(pycurl.PASSWORD, password)
#conn.setopt(pycurl.SSL_VERIFYPEER, False)
conn.setopt(pycurl.FOLLOWLOCATION, True)
conn.setopt(pycurl.VERBOSE, True)
conn.setopt(pycurl.URL, 'https://stream.twitter.com/1.1/statuses/sample.json')  
conn.setopt(pycurl.DEBUGFUNCTION, test)
conn.setopt(pycurl.WRITEFUNCTION, body)

conn.perform()

print "Who let the dogs out?:p"
sleep(10)

conn.close()

➜  ~  python twitter.py 
debug(0): About to connect() to stream.twitter.com port 443 (#0)
debug(0): Trying 199.16.156.110...
debug(0): Connected to stream.twitter.com (199.16.156.110) port 443 (#0)
debug(0): Initializing NSS with certpath: sql:/etc/pki/nssdb
debug(0): CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
debug(0): SSL connection using SSL_RSA_WITH_RC4_128_SHA
debug(0): Server certificate:
debug(0): subject: CN=stream.twitter.com,OU=Twitter Security,O="Twitter, Inc.",L=San Francisco,ST=California,C=US
debug(0): start date: Oct 09 00:00:00 2013 GMT
debug(0): expire date: Dec 30 23:59:59 2016 GMT
debug(0): common name: stream.twitter.com
debug(0): issuer: CN=VeriSign Class 3 Secure Server CA - G3,OU=Terms of use at https://www.verisign.com/rpa (c)10,OU=VeriSign Trust Network,O="VeriSign, Inc.",C=US
debug(0): Server auth using Basic with user 'bubudee'
debug(2): GET /1.1/statuses/sample.json HTTP/1.1
Authorization: Basic YnVidWRlZTpkZWVidWJ1
User-Agent: PycURL/7.29.0
Host: stream.twitter.com
Accept: */*
debug(1): HTTP/1.1 401 Unauthorized
debug(0): Authentication problem. Ignoring this.
debug(1): WWW-Authenticate: Basic realm="Firehose"
debug(1): Content-Type: text/html
debug(1): Cache-Control: must-revalidate,no-cache,no-store
debug(1): Content-Length: 1243
debug(1): Connection: close
debug(1): 
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Error 401 Unauthorized</title>
</head>
<body>
<h2>HTTP ERROR: 401</h2>
<p>Problem accessing '/1.1/statuses/sample.json'. Reason:
<pre>    Unauthorized</pre>
</body>
</html>
debug(0): Closing connection 0
Who let the dogs out?:p
^CGot ctrl+c, going down!
➜  ~  hcat twitter.py
导入pycurl
输入信号
导入系统
从时间上导入睡眠
用户名='bubudee'
密码='deebubu'
def主体(buf):
对于buf.strip().split('\n')中的项:
if item.strip():
打印项目
def测试(调试类型、调试消息):
如果len(debug_msg)<300:
打印“调试(%d):%s”%(调试类型,调试消息条()
def句柄控制c(信号,帧):
打印“得到ctrl+c,正在下降!”
系统出口(0)
signal.signal(signal.SIGINT,handle\u ctrl\u c)
conn=pycurl.Curl()
conn.setopt(pycurl.USERNAME,USERNAME)
conn.setopt(pycurl.PASSWORD,PASSWORD)
#conn.setopt(pycurl.SSL_VERIFYPEER,False)
conn.setopt(pycurl.FOLLOWLOCATION,True)
conn.setopt(pycurl.VERBOSE,True)
conn.setopt(pycurl.URL,'https://stream.twitter.com/1.1/statuses/sample.json')  
conn.setopt(pycurl.DEBUGFUNCTION,test)
conn.setopt(pycurl.WRITEFUNCTION,body)
康涅狄格州执行
打印“谁放狗出去的?:p”
睡眠(10)
康涅狄格州关闭
➜  ~  python twitter.py
调试(0):即将连接()到stream.twitter.com端口443(#0)
调试(0):正在尝试199.16.156.110。。。
调试(0):连接到stream.twitter.com(199.16.156.110)端口443(#0)
调试(0):使用certpath:sql:/etc/pki/nssdb初始化NSS
调试(0):CAfile:/etc/pki/tls/certs/ca-bundle.crt
卡帕斯:没有
调试(0):使用SSL\u RSA\u和\u RC4\u 128\u SHA的SSL连接
调试(0):服务器证书:
调试(0):主题:CN=stream.twitter.com,OU=twitter安全,O=“twitter,Inc.”,L=旧金山,ST=California,C=US
调试(0):开始日期:2013年10月9日00:00:00 GMT
调试(0):过期日期:12月30日23:59:59 2016 GMT
调试(0):通用名称:stream.twitter.com
调试(0):颁发者:CN=VeriSign Class 3安全服务器CA-G3,OU=at的使用条款https://www.verisign.com/rpa (c) 10,OU=VeriSign Trust Network,O=“VeriSign,Inc.”,c=US
调试(0):使用Basic与用户“bubudee”进行服务器身份验证
调试(2):GET/1.1/statuses/sample.json HTTP/1.1
授权:基本YnVidWRlZTpkZWVidWJ1
用户代理:PycURL/7.29.0
主持人:stream.twitter.com
接受:*/*
调试(1):HTTP/1.1 401未经授权
调试(0):身份验证问题。忽略这一点。
调试(1):WWW-Authenticate:Basic-realm=“Firehose”
调试(1):内容类型:text/html
调试(1):缓存控制:必须重新验证,无缓存,无存储
调试(1):内容长度:1243
调试(1):连接:关闭
调试(1):
错误401未经授权
HTTP错误:401
访问“/1.1/statuses/sample.json”时出现问题。原因:
未经授权
调试(0):正在关闭连接0
谁把狗放出去了
^CGot ctrl+c,正在下降!

键盘中断
-但是,这不会改变输出。(尽管还有一个例子说明了为什么捕获
异常
是个坏主意。)感谢您指出这一点,我更正了我的示例。但这并没有改变我的问题。在conn.perform()之后需要conn.close()。您是否尝试过在没有任何
BaseException
的情况下放置
除外:
?你试过输入
try。。除了
handleData
函数中的
之外?这与我尝试的第二件事相同,它不会删除键盘中断打印。添加
close()
不会改变在
body()中引发异常的事实。@Wookai,是的,你是对的,需要捕获CTRL+C信号并处理它,添加了一些示例,说明如何使用。谢谢。你能把这两种方法混合到一个使用pycurl的例子中吗?@Wookai,也许我没有挂起的conn.perform(),但我读过“一个特定信号的处理程序,一旦设置,在显式重置之前保持安装状态”,需要一个执行长时间返回内容测试的链接。@Wookai,别提了,我已附上你所要求的。
import pycurl

username = 'your_user_name'
password = 'your_password'

def body(buf):
    for item in buf.strip().split('\n'):
        if item.strip():
            print item

def test(debug_type, debug_msg):
    if len(debug_msg) < 300:
        print "debug(%d): %s" % (debug_type, debug_msg.strip())

conn = pycurl.Curl()  
conn.setopt(pycurl.USERNAME, username)
conn.setopt(pycurl.PASSWORD, password)
#conn.setopt(pycurl.SSL_VERIFYPEER, False)
conn.setopt(pycurl.FOLLOWLOCATION, True)
conn.setopt(pycurl.VERBOSE, True)
conn.setopt(pycurl.URL, 'https://stream.twitter.com/1.1/statuses/sample.json')  
conn.setopt(pycurl.DEBUGFUNCTION, test)
conn.setopt(pycurl.WRITEFUNCTION, body)
conn.perform()
conn.close()
➜  ~  hcat twitter.py 
import pycurl
import signal
import sys
from time import sleep

username = 'bubudee'
password = 'deebubu'

def body(buf):
    for item in buf.strip().split('\n'):
        if item.strip():
            print item

def test(debug_type, debug_msg):
    if len(debug_msg) < 300:
        print "debug(%d): %s" % (debug_type, debug_msg.strip())

def handle_ctrl_c(signal, frame):
    print "Got ctrl+c, going down!"
    sys.exit(0)
signal.signal(signal.SIGINT, handle_ctrl_c)

conn = pycurl.Curl()  
conn.setopt(pycurl.USERNAME, username)
conn.setopt(pycurl.PASSWORD, password)
#conn.setopt(pycurl.SSL_VERIFYPEER, False)
conn.setopt(pycurl.FOLLOWLOCATION, True)
conn.setopt(pycurl.VERBOSE, True)
conn.setopt(pycurl.URL, 'https://stream.twitter.com/1.1/statuses/sample.json')  
conn.setopt(pycurl.DEBUGFUNCTION, test)
conn.setopt(pycurl.WRITEFUNCTION, body)

conn.perform()

print "Who let the dogs out?:p"
sleep(10)

conn.close()

➜  ~  python twitter.py 
debug(0): About to connect() to stream.twitter.com port 443 (#0)
debug(0): Trying 199.16.156.110...
debug(0): Connected to stream.twitter.com (199.16.156.110) port 443 (#0)
debug(0): Initializing NSS with certpath: sql:/etc/pki/nssdb
debug(0): CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
debug(0): SSL connection using SSL_RSA_WITH_RC4_128_SHA
debug(0): Server certificate:
debug(0): subject: CN=stream.twitter.com,OU=Twitter Security,O="Twitter, Inc.",L=San Francisco,ST=California,C=US
debug(0): start date: Oct 09 00:00:00 2013 GMT
debug(0): expire date: Dec 30 23:59:59 2016 GMT
debug(0): common name: stream.twitter.com
debug(0): issuer: CN=VeriSign Class 3 Secure Server CA - G3,OU=Terms of use at https://www.verisign.com/rpa (c)10,OU=VeriSign Trust Network,O="VeriSign, Inc.",C=US
debug(0): Server auth using Basic with user 'bubudee'
debug(2): GET /1.1/statuses/sample.json HTTP/1.1
Authorization: Basic YnVidWRlZTpkZWVidWJ1
User-Agent: PycURL/7.29.0
Host: stream.twitter.com
Accept: */*
debug(1): HTTP/1.1 401 Unauthorized
debug(0): Authentication problem. Ignoring this.
debug(1): WWW-Authenticate: Basic realm="Firehose"
debug(1): Content-Type: text/html
debug(1): Cache-Control: must-revalidate,no-cache,no-store
debug(1): Content-Length: 1243
debug(1): Connection: close
debug(1): 
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Error 401 Unauthorized</title>
</head>
<body>
<h2>HTTP ERROR: 401</h2>
<p>Problem accessing '/1.1/statuses/sample.json'. Reason:
<pre>    Unauthorized</pre>
</body>
</html>
debug(0): Closing connection 0
Who let the dogs out?:p
^CGot ctrl+c, going down!