I have the same piece of coding to deal with Twitter User Stream running on two different machines. Both machines are Ubuntu Lucid using python 2.6.5, but on the machine in my home I receive HTTP Error 401: Unauthorized
while on the university it works perfectly. On both machines it works perfectly when I use curl with the same parameters, i.e., consumer key, consumer secret, acces token, and access key.
See the code bellow, it was created by Josh Sharp
from oauth.oauth import OAuthRequest, OAuthSignatureMethod_HMAC_SHA1
from hashlib import md5
import json, time
import random, math, re, urllib, urllib2
STREAM_URL = "https://userstream.twitter.com/2/user.json"
class Token(object):
def __init__(self,key,secret):
self.key = key
self.secret = secret
def _generate_nonce(self):
random_number = ''.join(str(random.randint(0, 9)) for i in range(40))
m = md5(str(time.time()) + str(random_number))
return m.hexdigest()
CONSUMER_KEY = 'consumer_key'
CONSUMER_SECRET = 'consumer_secret'
ACCESS_TOKEN = 'token'
ACCESS_TOKEN_SECRET = 'token_secret'
access_token = Token(ACCESS_TOKEN,ACCESS_TOKEN_SECRET)
consumer = Token(CONSUMER_KEY,CONSUMER_SECRET)
parameters = {
'oauth_consumer_key': CONSUMER_KEY,
'oauth_token': access_token.key,
'oauth_signature_method': 'HMAC-SHA1',
'oauth_timestamp': str(int(time.time())),
'oauth_nonce': access_token._generate_nonce(),
'oauth_version': '1.0',
}
oauth_request = OAuthRequest.from_token_and_callback(access_token,
http_url=STREAM_URL,
parameters=parameters)
signature_method = OAuthSignatureMethod_HMAC_SHA1()
signature = signature_method.build_signature(oauth_request, consumer, access_token)
parameters['oauth_signature'] = signature
data = urllib.urlencode(parameters)
req = urllib2.urlopen("%s?%s" % (STREAM_URL,data))
buffer = ''
# We're using urllib2 to avoid external dependencies
# even though pyCurl actually handles the callbacks
# much more gracefully than this clumsy method.
# We read a byte at a time until we find a newline
# which indicates the end of a chunk.
while True:
chunk = req.read(1)
if not chunk:
print buffer
break
chunk = unicode(chunk)
buffer += chunk
tweets = buffer.split("\n",1)
if len(tweets) > 1:
print tweets[0]
buffer = tweets[1]
The error when I try to execute in home is:
File "py_stream.py", line 48, in <module>
req = urllib2.urlopen("%s?%s" % (STREAM_URL,data))
File "/usr/lib/python2.6/urllib2.py", line 126, in urlopen
return _opener.open(url, data, timeout)
File "/usr/lib/python2.6/urllib2.py", line 397, in open
response = meth(req, response)
File "/usr/lib/python2.6/urllib2.py", line 510, in http_response
'http', request, response, code, msg, hdrs)
File "/usr/lib/python2.6/urllib2.py", line 435, in error
return self._call_chain(*args)
File "/usr/lib/python2.6/urllib2.py", line 369, in _call_chain
result = func(*args)
File "/usr/lib/python2.6/urllib2.py", line 518, in http_error_default
raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
urllib2.HTTPError: HTTP Error 401: Unauthorized
Since it works using curl on both machines, I suppose nothing is wrong related with the SSL certification. But at the same time it makes me wonder what fails when I use it in home.
After many weeks trying to find what was the problem, I discovered that the clock was not well synced with the one responsible for the Twitter Stream. And therefore, Twitter returns 401: Unauthorized.
If you are using Ubuntu, you can solve this problem using ntpdate as following: