2004-08-25

解决在 Python 中登录网站的问题

所谓登录进入一个网站,实际上就是在浏览器里留下一些暂时或长期的 cookie 而已。如果我们用 Python 访问一些需要登录才能看到的内容,只要把登录之后传回来的cookies再传回去就行了。

虽然 Python2.3 提供了 Cookie 这个模块,但做为操作客户端 cookie 来说并不实用。我们也可以靠自己维护 http header 来实现这些功能,但这很很麻烦。还好有人提供了不错的模块,比如 CookieClient 就是不错的选择。下面是我用 CookieClient 编写的一个访问 linuxforum 的示例脚本:

#!/usr/bin/env python
# -*- coding: GB2312 -*-
# xyb at linuxforum.net

import sys
import ClientCookie
from urllib import urlencode

# add loader
cookies = ClientCookie.LWPCookieJar()
opener = ClientCookie.build_opener(
ClientCookie.HTTPCookieProcessor(cookies),
ClientCookie.HTTPRefererProcessor,
ClientCookie.HTTPEquivProcessor,
ClientCookie.HTTPRefreshProcessor,
ClientCookie.SeekableProcessor)
opener.addheaders = [
("User-agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Debian/1.5-3"),
("Accept", "text/html, image/jpeg, image/png, text/*, image/*, */*")]
ClientCookie.install_opener(opener)

# check args
if len(sys.argv) <= 2:
print "Usage: %s USERNAME PASSWORD" % (sys.argv[0])
sys.exit(1)
else:
UserName = sys.argv[1]
Password = sys.argv[2]

# login
data = {
'Loginname': UserName,
'Loginpass': Password,
'firstlogin': 1,
'option': '登入论坛'
}
urldata = urlencode(data)
r = ClientCookie.urlopen("http://www.linuxforum.net/forum/start_page.php", urldata)

# show result
results = r.read()
open('start.html', 'w').write(results)

# then, user page
r = ClientCookie.urlopen("http://www.linuxforum.net/forum/login.php?Cat=")
results = r.read()
open('user.html', 'w').write(results)

# read messages
r = ClientCookie.urlopen("http://www.linuxforum.net/forum/viewmessages.php?Cat=&box=received")
results = r.read()
open('inbox.html', 'w').write(results)

# save cookies to file
cookies.save("./cookies")

这个例子里用的是 ClientCookie-0.9.4a。

不过从 Python2.4 开始,将会增加 clientlib 来提供对客户端 cookie 的支持,其中绝大部分代码都是 ClientCookie 里的,只不过调整了一下组织方式和文档,并且和 urllib2 整合在了一起。把上面的代码翻译一下,就可以得到如下的代码:

#!/usr/bin/env python
# -*- coding: GB2312 -*-
# xyb at linuxforum.net

import sys
from urllib import urlencode
import cookielib, urllib2
cj = cookielib.LWPCookieJar()
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
urllib2.install_opener(opener)
opener.addheaders = [
("User-agent", "Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.5) Gecko/20031107 Debian/1.5-3"),
("Accept", "text/html, image/jpeg, image/png, text/*, image/*, */*")]

# check args
if len(sys.argv) <= 2:
print "Usage: %s USERNAME PASSWORD" % (sys.argv[0])
sys.exit(1)
else:
UserName = sys.argv[1]
Password = sys.argv[2]

# login
data = {
'Loginname': UserName,
'Loginpass': Password,
'firstlogin': 1,
'option': '登入论坛'
}
urldata = urlencode(data)
r = opener.open("http://www.linuxforum.net/forum/start_page.php", urldata)

# show result
results = r.read()
open('start.html', 'w').write(results)

# then, user page
r = urllib2.urlopen("http://www.linuxforum.net/forum/login.php?Cat=")
results = r.read()
open('user.html', 'w').write(results)

# read messages
r = urllib2.urlopen("http://www.linuxforum.net/forum/viewmessages.php?Cat=&box=received")
results = r.read()
open('inbox.html', 'w').write(results)

# save cookies to file
cj.save("./cookies")

不过现在 Python2.4a2 的 urllib2 还有点 bug,它导致发出的请求 header 会有两个大小写不同的 Content-Length。这也导致我们的这个例子现在还不能正常运行,不过我想等正式的 Python2.4 出来以后这段代码应该能直接执行。

另外,在上面的代码中我是使用的 cookielib.LWPCookieJar() 或 ClientCookie.LWPCookieJar(),其实还有 MozillaCookieJar、MSIECookieJar、MSIEDBCookieJar 和
BSDDBCookieJar 这些选择。

2004-09-06,注:Python2.4a3 发布,clientlib 没有什么问题了,我的那段倒是有问题,一是需要 install_opener,二是需要使用 urllib2.urlopen。现在改过了。

3 条评论:

匿名 说...

Good design!
[url=http://croxctgk.com/yjtv/zjui.html]My homepage[/url] | [url=http://stcowuxr.com/osmc/unhg.html]Cool site[/url]

匿名 说...

Nice site!
My homepage | Please visit

匿名 说...

为什么要用urllib2.urlopen而不用opener.open? 前者要求install_opener, 后者不用阿.