Python中与Twitter的OAuth脚本不起作用

4 投票
2 回答
1424 浏览
提问于 2025-04-15 19:09

我正在用Python写一个OAuth的脚本。

为了测试这个脚本,我使用了Twitter的API。但是它运行得不太好。

def test():
    params = {
            "oauth_consumer_key": TWITTER_OAUTH_CONSUMER_KEY,
            "oauth_nonce": "".join(random.choice(string.digits + string.letters) for i in xrange(7)),
            "oauth_signature_method": "HMAC-SHA1",
            "oauth_timestamp": str(int(time.time())),
            "oauth_token": res_dict["oauth_token"],
            "oauth_version": "1.0",
            }
    status = {"status": u"Always_look_on_the_bright_side_of_life".encode("UTF-8")}
    print status
    params.update(status)
    url = "http://twitter.com/statuses/update.xml"
    key = "&".join([TWITTER_OAUTH_CONSUMER_SECRET, res_dict["oauth_token_secret"]])
    msg = "&".join(["POST", urllib.quote(url,""),
                    urllib.quote("&".join([k+"="+params[k] for k in sorted(params)]), "-._~")])
    print msg
    signature = hmac.new(key, msg, hashlib.sha1).digest().encode("base64").strip()
    params["oauth_signature"] = signature
    req = urllib2.Request(url,
          headers={"Authorization":"OAuth", "Content-type":"application/x-www-form-urlencoded"})
    req.add_data("&".join([k+"="+urllib.quote(params[k], "-._~") for k in params]))
    print req.get_data()
    res = urllib2.urlopen(req).read()
    print res

这个脚本(状态="Always_look_on_the_bright_side_of_life")是可以正常工作的。

但是,如果状态是"Always look on the bright side of life"(把下划线换成空格),它就不行了(返回了HTTP错误401:未授权)。

我参考了这个问题,但是没有成功。

请给我一些建议。谢谢。

2 个回答

0

解决这个问题最简单的方法是在 status = {"status": u"Always_look_on_the_bright_side_of_life".encode("UTF-8")} 之后加上 status = urllib.quote(status)。这样可以把空格和其他特殊字符处理成需要的格式。

1

我之前在使用Facebook的OAuth时也遇到过同样的问题。问题出在服务器端的签名验证失败。你可以看看你的签名生成代码:

msg = "&".join(["POST", urllib.quote(url,""),
                urllib.quote("&".join([k+"="+params[k] for k in sorted(params)]), "-._~")])
print msg
signature = hmac.new(key, msg, hashlib.sha1).digest().encode("base64").strip()

这个代码是用原始(未编码)的字符串来生成签名的。然而,服务器端是用经过URL编码的字符串来验证签名的:

req.add_data("&".join([k+"="+urllib.quote(params[k], "-._~") for k in params]))

要解决这个问题,你需要修改这行代码,使用经过URL编码的参数来生成签名:

msg = "&".join(["POST", urllib.quote(url,""),
                urllib.quote("&".join([k+"="+urllib.quote(params[k], "-._~") for k in sorted(params)]), "-._~")])

撰写回答