1

这次想试一试模拟登陆,以为应该会很顺利,但是遇到了各种问题,所以记录总结一下。
参考文章:请点击这里

模拟登陆segmentfault

参考文章使用的node.js,感觉没有python用起来方便。

工具

  • python2.7
  • Chrome浏览器
  • requests
  • PyV8
  • lxml

思路

首先进入segmentfault的登陆页面
可以随便输入错误密码点击登陆,使用Chrome查看请求发到了哪个url
另外看post的参数,这里有三个:remember, usernamepassword
然后可以顺便按照Requests Headers把请求头设置好(照抄到代码里)。

requests库的session对象能够帮我们跨请求保持某些参数,也会在同一个session实例发出的所有请求之间保持cookies

使用:

    # 创建一个session对象 
    session = requests.session()
    # 用session对象发出get请求
    response = session.get('https://segmentfault.com/user/login')
    # 获取cookie
    cookies = response.cookies

设置了请求头,cookie也拿到了,看看post的url
clipboard.png

发现这段url后面是带了查询字符串的,每次发请求都会变化。
只有明白它是如何生成的才能取得我们要post的url,这里我卡了好久,去寻找答案,才找到了参考文章,这里面提供了思路获取js中生成的token。

  1. login.min.js中查询字符串 "_=" (Chrome f12下使用快捷键Crtl+F可以打开查询窗口),因为注意到url是https://segmentfault.com/api/user/login?_=[querystring]

clipboard.png

发现要post的url是根url加上"?_="再加上a._.
可以想到a是一个对象,_a这个对象的一个属性。
可以找到:

clipboard.png

于是发现了a._window.SF.token

取得token

分析:回到login文件发现tokenhtml中的script标签中一个函数生成的,而html可以使用requests.get取得,然后可以通过pythonre模块用正则表达式提取出所需要的函数,这时还需要python中的PyV8模块来执行js函数。
执行:分析html的DOM节点,发现函数的位置,使用xpath取得那个script标签

    response = requests.get('https://segmentfault.com/user/login')
    sel = html.fromstring(response.text)
    s = sel.xpath('/html/body/script[8]/text()')[0]
    st = str(s.encode('utf-8'))

写一个get_token函数取得token(这里要用到PyV8模块实现pythonJavaScript的交互)
这个DOM目前是这样的:

<script>
    (function (w) {
        w.SF = {
            staticUrl: "https://static.segmentfault.com/v-5aa63d11"
        };
        w.SF.token = (function () {
    var _PRmciaY = //'Uns'
'f44'+//'71w'
'b1e'+//'C'
'9a'+//'cM'
'e4'+'b75'//'x'
+//'PoE'
'163'+//'jxT'
'2'+'61'//'uuJ'
+'1'//'4jI'
+'5'//'bC'
+'e60'//'1XN'
+//'C'
'C'+'m'//'m'
+'8'//'q5g'
+//'I'
'b1'+//'R'
'b64'+//'1'
'2c', _44R = [[24,25],[24,25]];

    for (var i = 0; i < _44R.length; i ++) {
        _PRmciaY = _PRmciaY.substring(0, _44R[i][0]) + _PRmciaY.substring(_44R[i][1]);
    }

    return _PRmciaY;
})();;
    })(window);

                var lock = {
        type: "",
        text: '',
        table: {"ban_post":[1,"\u4f60\u5df2\u7ecf\u88ab\u7981\u8a00, \u65e0\u6cd5\u8fdb\u884c\u6b64\u64cd\u4f5c, \u5982\u6709\u7591\u4e49\u8bf7\u63d0\u4ea4\u7533\u8bc9, \u6216\u8005\u53d1\u90ae\u4ef6\u5230pr@segmentfault.com"]}
    };

        var ddosMode = false;
    
    (function (currentUrl) {
        if (typeof URL != 'undefined') {
            // 测试环境
            if ('https://segmentfault.com' === '//localhost:3000') return

            var baseUrl = new URL('https://segmentfault.com');

            if (baseUrl.protocol != currentUrl.protocol
                || baseUrl.host != currentUrl.host) {
                window.location.href = baseUrl.protocol + '//' + baseUrl.host
                    + currentUrl.pathname + currentUrl.search + currentUrl.hash;
            }
        }
    })(window.location);
</script>

我们需要的是第一个函数,在get_token()中用正则表达式提取出来。

def get_token(st):
    h = re.match('[\s\S]*\(function \(w\) \{[\s\S]+? \}\)\(window\);', st).group()
    with PyV8.JSContext() as ctxt:
        ctxt.eval("""window={};\n""" + h)
        vars = ctxt.locals
        token_var = vars.window.SF.token
        print token_var
    return token_var

到此,所需要的都取得了,接下来就用sesssion.post把参数,cookie,请求头带上,post的url加上查询字符串,就可以成功模拟登陆了。

如有错误请指正~谢谢~


Garrick
35 声望2 粉丝

KEEP LEARNING, KEEP CODING