2012-05-04 35 views
6

Tôi đang viết một tập lệnh Python sử dụng pycurl để tiêu thụ Twitter's Sreaming API. Dưới đây là một đoạn ngắn mà không chính xác điều đó (chỉ cần đặt Twitter đăng nhập của bạn/mật khẩu để kiểm tra nó):Làm thế nào để xử lý KeyboardInterrupt (Ctrl-c) độc đáo với pycurl?

import pycurl 

user = 'USER' 
password = 'PWD' 

def handleData(data): 
    print(data) 

conn = pycurl.Curl() 
conn.setopt(pycurl.USERPWD, "%s:%s" % (user, password)) 
conn.setopt(pycurl.URL, 'https://stream.twitter.com/1/statuses/sample.json') 
conn.setopt(pycurl.WRITEFUNCTION, handleData) 
conn.perform() 

Vấn đề là vì kịch bản tiêu thụ một dòng suối, conn.perform() không bao giờ trở lại (hoặc rất hiếm khi). Do đó, đôi khi tôi cần phải ngắt đoạn mã và KeyboardInterrupt bị bắt theo phương thức perform().

Tuy nhiên, nó không xử lý tốt, in ra lỗi xấu và tăng ngoại lệ khác.

^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)') 

Các cURL FAQ nói rằng để làm gián đoạn một chuyển đang diễn ra, một trong những chức năng gọi lại (trong trường hợp của tôi handleData) phải trả lại một giá trị đặc biệt. Điều này thật tuyệt, nhưng KeyboardInterrupt không bị bắt bởi bất kỳ chức năng gọi lại nào!

Tôi có thể làm điều này gọn gàng như thế nào?

EDIT: Tôi biết rằng bạn có thể bắt ngoại lệ, nhưng pycurl vẫn hiện một số điều buồn cười:

Nếu tôi làm:

try: 
    conn.perform() 
except BaseException as e: 
    print('We caught the exception') 
    print(type(e)) 

tôi nhận được:

^CTraceback (most recent call last): 
    File "test.py", line 6, in handleData 
    def handleData(data): 
KeyboardInterrupt 
We caught the exception 
<class 'pycurl.error'> 

Điều này có nghĩa rằng nội bộ, pycurl thực hiện một số loại bắt, in một thông báo lỗi xấu xí và sau đó tăng một số pycurl.error.

+0

'KeyboardInterrupt' [không phải là một lớp con của 'Exception', đó là một lớp con của' BaseException'] (http://docs.python.org/library/exceptions.html#exception-hierarchy) - tuy nhiên, điều đó không thay đổi đầu ra. (Mặc dù một ví dụ khác về lý do tại sao bắt 'Ngoại lệ' là một ý tưởng tồi.) –

+0

Cảm ơn bạn đã chỉ ra điều đó, tôi đã sửa lại ví dụ của mình. Nó không thay đổi câu hỏi của tôi mặc dù. – Wookai

+0

Bạn cần conn.close() sau conn.perform(). –

Trả lời

1

Bạn có thể làm điều này bằng cách bắt loại pycurl.error. Ví dụ:

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

Điều này giống với điều thứ hai tôi đã thử, không xóa thao tác in KeyboardInterrupt. – Wookai

2

Bạn cần phải bắt CTRL + C và quá trình đó là dấu hiệu
gốc: Example 1
gốc: Example 2


Ví dụ 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() 

Ví dụ 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 

Và ít nhất một cái gì đó không hoạt động trên trang liên kết twitter, xem here

  • đừng quên đặt conn.close() sau conn.perform()

Và thật hữu ích khi bật chế độ gỡ lỗi khi thử nghiệm.

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

Chỉ cần sao chép/dán thử nghiệm hoạt động Ví dụ

➜ ~ 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! 
+1

Thêm 'close()' sẽ không thay đổi thực tế là một ngoại lệ được nâng lên bên trong 'body()' khi bị gián đoạn. – Wookai

+0

@Wookai, vâng, bạn nói đúng, cần nắm bắt tín hiệu CTRL + C và xử lý nó, thêm ví dụ về cách. Cảm ơn bạn. –

+0

Bạn có thể kết hợp cả hai thành một ví dụ phù hợp với pycurl? – Wookai

Các vấn đề liên quan