V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
zvDC
V2EX  ›  Python

求助:利用 requests 模拟登录,中文数据提交 + 两次 302 重定向

  •  
  •   zvDC · 2015-01-17 23:31:07 +08:00 · 14586 次点击
    这是一个创建于 3391 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如题,想利用python的requests来进行网站的模拟登录,苦于技术太差,纠结了许久,也到处搜索还是没有找到答案,烦请大家帮忙。

    问题是:
    1、如何处理form data中提交的数据为中文的编码问题?
    2、如何处理两次302,"object moved"重定向的问题,在requests中如何写代码?

    这是成功登录时的抓包图:
    wireshark
    http://i.imgur.com/Z1qcWH7.png
    Chrome DevTools
    http://i.imgur.com/YkEuq1s.png

    有问题的代码如下:

    import requests

    url_login = 'http://www.example.com/RedeployCourse/login.asp'
    url_default = 'http://www.example.com/RedeployCourse/default.asp'
    url_info = 'http://www.example.com/RedeployCourse/RedeployInfo.asp'

    headers = { 'Content-Type': 'application/x-www-form-urlencoded',}
    form_data={"username": '中文用户名',"password":'abcdef'}

    s = requests.Session()
    s.get(url_login)

    r = s.post(url_login, data=form_data, headers=headers, allow_redirects=False)

    s.get(url_default)
    r = s.get(url_info)

    16 条回复    2015-01-23 05:27:23 +08:00
    14
        1
    14  
       2015-01-17 23:41:59 +08:00   ❤️ 1
    In [1]: import urllib

    In [2]: urllib.quote('中文用户名')
    Out[2]: '%E4%B8%AD%E6%96%87%E7%94%A8%E6%88%B7%E5%90%8D'

    第二个没明白你的意思,这个可能对你有帮助: http://stackoverflow.com/questions/20475552/python-requests-library-redirect-new-url
    aaaa007cn
        2
    aaaa007cn  
       2015-01-18 01:02:07 +08:00   ❤️ 1
    302 有什么问题?
    已经事先知道目标网址的话
    最多就是再带上 cookie 和 referer
    cookie 已经由 session 处理了
    referer 看场合也有不需要的
    s.get(url_default, allow_redirects=False, headers={"referer": url_login})
    r = s.get(url_info, allow_redirects=False, headers={"referer": url_default})
    不知道目标网址的话就从 r.headers["Location"] 来取跳转的网址

    不过 requests 默认 allow_redirects 为 True 的
    也可以让它自动跳转
    ericFork
        3
    ericFork  
       2015-01-18 06:11:59 +08:00   ❤️ 1
    如果不是非要用 Python 的话,可以试试 casperjs
    zvDC
        4
    zvDC  
    OP
       2015-01-18 08:22:36 +08:00
    @14 @aaaa007cn @zvDC 谢谢各位的回复

    我想还是先把第一个问题解决吧

    服务端页面编码为 <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
    提交中文的问题,我还有疑问:
    拿 “登录”二字举例,

    unicode 字符
    In [1]: u"登录"
    Out[1]: u'\u767b\u5f55'

    转换成gb2312格式
    In [2]: u'登录'.encode('gb2312 ')
    Out[2]: '\xb5\xc7\xc2\xbc'

    进行URL编码
    In [3]: urllib.quote(u'登录'.encode('gb2312'))
    Out[3]: '%B5%C7%C2%BC'

    这样转换成gb2312编码之后,与cookie中对应的字符显示是一致的
    可是通过wireshark抓包,却发现,正确的值应该是:\265\307\302\274
    请问这是如何实现的,或者哪个地方我忽略了,谢谢!
    zvDC
        5
    zvDC  
    OP
       2015-01-18 08:31:51 +08:00
    @aaaa007cn 你好
    使用
    s = requests.session()
    这个应该是可以把cookies一直保留,直到会话结束。
    在这种情况下:
    1、是否,只要我post过去的值是正确的,就不需要再添加新的值?
      (因为,我发现用脚本post比真实提交的cookie值少了一些)

    2、如果需要添加,如何向cookies中添加新的值,比如{"name":'value'}?
    zvDC
        6
    zvDC  
    OP
       2015-01-18 10:48:20 +08:00
    在  http://www.v2ex.com/t/97347 中看到修改cookie值的方法

    def update_cookie(cookiejar, cookie):
    _cookies = requests.cookies
    _cookies.remove_cookie_by_name(cookiejar, 'cookie_name')
    cookiejar.set_cookie(_cookies.create_cookie('cookie_name', cookie, **{'domain': '.example.com'}))
    mringg
        7
    mringg  
       2015-01-18 11:14:53 +08:00 via Android   ❤️ 1
    redirect这个属性为true就没多大问题吧
    Sylv
        8
    Sylv  
       2015-01-18 12:45:46 +08:00   ❤️ 1
    '\xb5\xc7\xc2\xbc' 和 '\265\307\302\274' 应该是等价的,只是表示方式不一样,不过是一个写成的是16进制,一个写成的是8进制的。所以应该直接提交 u'登录'.encode('gb2312 ') 就好了。

    根据 requests 文档,向 requests.Session 的 cookies 中添加新值,应该这样就好了:
    s.cookies.update({"name":'value'})

    另外我不理解为什么你在 r = s.post(url_login) 之前还要 s.get(url_login) 一次?同样的还有 s.get(url_default)?看样子你不需要这两个的 response,那为什么要多此一举地 get 一下呢?
    mengskysama
        9
    mengskysama  
       2015-01-18 14:39:34 +08:00   ❤️ 2
    楼主其实昨天我看了下,我没敢给你贴上来,这样真的好吗?

    登陆很简单,因为web后端吃的是gb2312所以中文必须要先编码成2312,然后再让他做urlencode,这个requests能自己帮你做好。你不用urllib.quote

    还有就是requests会自动做decode成unicode,如果返回的头部没有指定ISO-XXX什么的,这样.text获取到的就是错误的unicode r.encoding = 'gb2312'


    url_login = 'http://os.ningboerji.com:82/RedeployCourse/login.asp'
    headers = { 'Content-Type': 'application/x-www-form-urlencoded'}
    form_data={"UserName": '\'or\' = \'or\'',"Pwd":'','B1':u'登录'.encode('gb2312')}
    s = requests.Session()
    r = s.post(url_login, data=form_data, headers=headers)
    r.encoding = 'gb2312'
    print r.text.encode('utf-8')
    exit(1)
    zvDC
        10
    zvDC  
    OP
       2015-01-18 14:40:53 +08:00
    @mringg 谢谢回复,requests 默认 allow_redirects 为 True,没能成功。

    @Sylv 谢谢。如你所说,'\xb5\xc7\xc2\xbc' 和 '\265\307\302\274' 应该是等价的,没有想到。是否有方法指定要生成的进制模式。

    之所以在post之前,先 s.get(url_login) 一下的原因,是想获得一个session cookie的值,后边要用到。

    后边的s.get(url_default),是因为在F12或者抓包里看到的都是在这样一个地址……

    (对于上面的做法,我都不确定是否有用,刚刚开始学习,只是在尝试)
    mengskysama
        11
    mengskysama  
       2015-01-18 14:51:21 +08:00   ❤️ 1
    如果没猜错你的系统和上面的一样有注入漏洞,在登录'or' = 'or'试试?迟早被人捅
    zvDC
        12
    zvDC  
    OP
       2015-01-18 14:51:23 +08:00
    @mengskysama 太感谢了。谢谢你。
    “这样好吗?”,放心,不是做坏事。
    只是地址链接能否修改一下,不公开呀?

    v2不能发私信,也不知道你现在还可以修改吗?
    mengskysama
        13
    mengskysama  
       2015-01-18 15:11:38 +08:00   ❤️ 1
    @zvDC V2不能编辑也不能删除
    我看你的DEST IP 和这个不匹配我就贴了..本想给你做个完成的例子..并不是有意冒犯。
    如果你是管理员,还是赶紧补掉吧。
    zvDC
        14
    zvDC  
    OP
       2015-01-18 15:16:46 +08:00
    @mengskysama 没事,谢谢。
    我不是管理员,只是不想因为我给别人带来不必要的麻烦。
    关注你了,向你学习。
    aaaa007cn
        15
    aaaa007cn  
       2015-01-20 00:16:37 +08:00   ❤️ 1
    >> 是否,只要我post过去的值是正确的,就不需要再添加新的值?
    session 已经自动处理了 cookie
    一般不需要手动更新

    >> 因为,我发现用脚本post比真实提交的cookie值少了一些
    可能是你先前少请求了某些页面
    也可能是真实提交时多了一些
    建议清掉浏览器 cookie 或者新开隐身模式去测试

    >> requests 默认 allow_redirects 为 True,没能成功
    怎么不成功
    贴出相关信息
    比如出错信息
    比如 r.history
    比如 r.text
    zvDC
        16
    zvDC  
    OP
       2015-01-23 05:27:23 +08:00
    @aaaa007cn 谢谢!
    对隐身模式测试,以前不知道,下次可以试试。
    问题出在我对编码这块了解不清,这块问题解决了,后面就没有问题了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   986 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 18:51 · PVG 02:51 · LAX 11:51 · JFK 14:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.