使用urllib2进行Python表单POST(包含关于保存/使用cookie的问题)
我正在尝试写一个函数,用来提交表单数据,并把返回的cookie信息保存到一个文件里,这样下次访问页面时,就能把cookie信息发送给服务器(也就是正常的浏览器行为)。
我在C++中用curlib写这个功能时相对简单,但我花了将近一天的时间尝试在Python中用urllib2来实现,结果还是没成功。
这是我目前的代码:
import urllib, urllib2
import logging
# the path and filename to save your cookies in
COOKIEFILE = 'cookies.lwp'
cj = None
ClientCookie = None
cookielib = None
logger = logging.getLogger(__name__)
# Let's see if cookielib is available
try:
import cookielib
except ImportError:
logger.debug('importing cookielib failed. Trying ClientCookie')
try:
import ClientCookie
except ImportError:
logger.debug('ClientCookie isn\'t available either')
urlopen = urllib2.urlopen
Request = urllib2.Request
else:
logger.debug('imported ClientCookie succesfully')
urlopen = ClientCookie.urlopen
Request = ClientCookie.Request
cj = ClientCookie.LWPCookieJar()
else:
logger.debug('Successfully imported cookielib')
urlopen = urllib2.urlopen
Request = urllib2.Request
# This is a subclass of FileCookieJar
# that has useful load and save methods
cj = cookielib.LWPCookieJar()
login_params = {'name': 'anon', 'password': 'pass' }
def login(theurl, login_params):
init_cookies();
data = urllib.urlencode(login_params)
txheaders = {'User-agent' : 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'}
try:
# create a request object
req = Request(theurl, data, txheaders)
# and open it to return a handle on the url
handle = urlopen(req)
except IOError, e:
log.debug('Failed to open "%s".' % theurl)
if hasattr(e, 'code'):
log.debug('Failed with error code - %s.' % e.code)
elif hasattr(e, 'reason'):
log.debug("The error object has the following 'reason' attribute :"+e.reason)
sys.exit()
else:
if cj is None:
log.debug('We don\'t have a cookie library available - sorry.')
else:
print 'These are the cookies we have received so far :'
for index, cookie in enumerate(cj):
print index, ' : ', cookie
# save the cookies again
cj.save(COOKIEFILE)
#return the data
return handle.read()
# FIXME: I need to fix this so that it takes into account any cookie data we may have stored
def get_page(*args, **query):
if len(args) != 1:
raise ValueError(
"post_page() takes exactly 1 argument (%d given)" % len(args)
)
url = args[0]
query = urllib.urlencode(list(query.iteritems()))
if not url.endswith('/') and query:
url += '/'
if query:
url += "?" + query
resource = urllib.urlopen(url)
logger.debug('GET url "%s" => "%s", code %d' % (url,
resource.url,
resource.code))
return resource.read()
当我尝试登录时,我传入了正确的用户名和密码,但登录失败了,而且没有保存任何cookie数据。
我有两个问题:
- 有没有人能看出login()函数哪里出错了,我该怎么修复它?
- 我该如何修改get_page()函数,以便使用我保存的cookie信息?
3 个回答
请在保存cookie的时候使用 ignore_discard
和 ignore_expires
,在我的情况下,这样保存是没问题的。
self.cj.save(cookie_file, ignore_discard=True, ignore_expires=True)
如果你在使用POST请求时遇到困难(就像我在处理登录表单时一样),那么快速安装Firefox的Live HTTP headers扩展会很有帮助(http://livehttpheaders.mozdev.org/index.html)。这个小扩展可以做很多事情,其中之一就是显示你手动登录时发送的确切POST数据。
在我的情况下,我花了好几个小时都没搞定,因为网站要求额外添加一个字段,内容是'action=login'(真是太傻了!)。
你发的代码有不少问题。一般来说,你需要创建一个自定义的打开器,这样才能处理重定向、https等情况,否则会遇到麻烦。至于 cookies,你需要在你的 cookiejar
上调用加载和保存的方法,并使用一些子类,比如 MozillaCookieJar
或 LWPCookieJar
。
这里有一个我写的类,用来登录 Facebook,那时候我在玩一些无聊的网页游戏。我只是把它改成了使用基于文件的 cookiejar,而不是内存中的。
import cookielib
import os
import urllib
import urllib2
# set these to whatever your fb account is
fb_username = "your@facebook.login"
fb_password = "secretpassword"
cookie_filename = "facebook.cookies"
class WebGamePlayer(object):
def __init__(self, login, password):
""" Start up... """
self.login = login
self.password = password
self.cj = cookielib.MozillaCookieJar(cookie_filename)
if os.access(cookie_filename, os.F_OK):
self.cj.load()
self.opener = urllib2.build_opener(
urllib2.HTTPRedirectHandler(),
urllib2.HTTPHandler(debuglevel=0),
urllib2.HTTPSHandler(debuglevel=0),
urllib2.HTTPCookieProcessor(self.cj)
)
self.opener.addheaders = [
('User-agent', ('Mozilla/4.0 (compatible; MSIE 6.0; '
'Windows NT 5.2; .NET CLR 1.1.4322)'))
]
# need this twice - once to set cookies, once to log in...
self.loginToFacebook()
self.loginToFacebook()
self.cj.save()
def loginToFacebook(self):
"""
Handle login. This should populate our cookie jar.
"""
login_data = urllib.urlencode({
'email' : self.login,
'pass' : self.password,
})
response = self.opener.open("https://login.facebook.com/login.php", login_data)
return ''.join(response.readlines())
test = WebGamePlayer(fb_username, fb_password)
在你设置好用户名和密码后,你应该能看到一个文件,叫 facebook.cookies
,里面存着你的 cookies。实际上,你可能想修改一下代码,先检查一下是否有有效的 cookie,如果有就用这个,然后如果访问被拒绝再重新登录。