Python3.6获取QQ空间全部好友列表

首先要处理的是gtk算法:从上次分析以来代码并没有变

登录QQ空间后搜索gtk字符串,在三个js中出现了

operation.50303.js
gdtlib.20160810.js
index.js

第一个js

/*  |xGv00|e5808eb94a2bdffe3aae60cd22c5efe2 */
define("app/v8/controls/mood_poster/utils/misc/1.0", ["app/v8/utils/tmpl/1.0"], function(require, exports, module) {
    var tmpl = require('app/v8/utils/tmpl/1.0');
    var misc = {};
	var getUploadUrl = function(callback) {
		misc.getRoute(function(routeDomainMap) {
			var gtk = 5381;
			var url = ['http://', routeDomainMap['u'].replace('photo.qq.com', 'photo.qzone.qq.com'), '/cgi-bin/upload/cgi_upload_image'].join('');
			try {
				gtk = QZONE.FP.getACSRFToken(url);
			} catch (err) {}
			callback(url + '?g_tk=' + gtk);
		}
		);
	}
	;
}



第二个js
HMod.genGTk = function() {
	var skey = comm.cookie.get("skey") || comm.cookie.get("rv2");
	return comm.genHash(skey);
}
;

NMod.xhrgetter = function(url, callback, ecb, opts) {
	var pid, gtk, domain = document.domain, usecors, valuestaturl = 'http://i.gdt.qq.com/view.fcg?xhr2';
	opts = opts || {};
	gtk = NMod._ishostSupportxhr() ? helper.genGTk() : '';
	if (supportlv2 && NMod._ishostSupportxhr()) {
		gtk && (url += '&g_tk=' + gtk);
		comm.xhr(url, function(obj) {
			NMod._decodexhrjson(obj.resp, callback, ecb);
		}
		, function(obj) {
			ecb(obj);
			if (obj && obj.exception && obj.status == 598) {
				helper.sendErrMsg(obj.exception, location.href + '&gxhr', '', {
					extra: "get xhr transport error",
					rate: 100
				});
			}
		}
		, opts);
		helper.valueStat(valuestaturl, 1, 11, 1, 500);
		return;
	}
	opts.forcescript = true;
	NMod._normalgetter(url, callback, ecb, opts);
	helper.valueStat(valuestaturl, 1, 12, 1, 500);
}
;

第三个js
/**
* @fileOverview 首页,入口文件
* @author Viktor Li
*/


define.pack("./index", ["lib/jquery", "mall.v8/lib/mall", "./event", "./tmpl", "./asyncRender"], function(require, exports, module) {
    var $ = require('lib/jquery')
      , 
    M = require('mall.v8/lib/mall');
    var evt = require('./event')
      , 
    TMPL = require('./tmpl')
      , 
    asyncRender = require('./asyncRender');
    
    //发起一个img请求ping后台
    function Ping(url, arg) {
        arg = arg || {};
        if (!('g_tk' in arg)) {
            //补上gtk
            arg.g_tk = M.user.getToken();
        }
        var sender = new Image
          , 
        params = $.param(arg);
        
        url = url + (url.indexOf('?') === -1 ? '?' : '&') + params;
        
        sender.src = url;
    }
}


看第一个js就够了
这个js从定义的名称来看是获取上传路径的
关键还是这一句
QZONE.FP.getACSRFToken(url)
url通过前面传的参数拼接
找函数定义相对准确的做法是用开发者工具watch查看QZONE.FP这个对象,然后找到getACSRFToken(url),右键 show function definition 查看函数定义( 右键的位置很重要)

找到这个js

interface_mini.js

 

QZONE.FrontPage.getACSRFToken = function(url) {
    url = QZFL.util.URI(url);
    var skey;
    if (url) {
      if (url.host && url.host.indexOf("qzone.qq.com") > 0) {
        skey = QZFL.cookie.get("p_skey");
      } else {
        if (url.host && url.host.indexOf("qq.com") > 0) {
          skey = QZFL.cookie.get("skey");
        }
      }
    }
    if (!skey) {
      try {
        skey = parent.QZFL.cookie.get("p_skey") || "";
      } catch (err) {
        skey = QZFL.cookie.get("p_skey") || "";
      }
    }
    if (!skey) {
      skey = QZFL.cookie.get("skey") || QZFL.cookie.get("rv2");
    }
    var hash = 5381;
    for (var i = 0, len = skey.length;i < len;++i) {
      hash += (hash << 5) + skey.charAt(i).charCodeAt();
    }
    return hash & 2147483647;
  };


可能是为了方便调用,定义也出现在下面这个js里

qzfl_v8_2.1.60.js

  

QZFL.pluginsDefine.getACSRFToken = function(url) {
    url = QZFL.util.URI(url);
    var skey;
    if (url) {
      if (url.host && url.host.indexOf("qzone.qq.com") > 0) {
        try {
          skey = parent.QZFL.cookie.get("p_skey");
        } catch (err) {
          skey = QZFL.cookie.get("p_skey");
        }
      } else {
        if (url.host && url.host.indexOf("qq.com") > 0) {
          skey = QZFL.cookie.get("skey");
        }
      }
    }
    if (!skey) {
      skey = QZFL.cookie.get("p_skey") || (QZFL.cookie.get("skey") || (QZFL.cookie.get("rv2") || ""));
    }
    return arguments.callee._DJB(skey);
  };
  QZFL.pluginsDefine.getACSRFToken._DJB = function(str) {
    var hash = 5381;
    for (var i = 0, len = str.length;i < len;++i) {
      hash += (hash << 5) + str.charCodeAt(i);
    }
    return hash & 2147483647;
  };

//两个定义大体上时一样的
先看具体情况生成要计算的skey
1.如果url中含有指定主机名,获取cookie中的p_skey或skey作为要计算的skey
2.如果通过url的方式没有获取到,则获取cookie中的p_skey作为要计算的skey
3.如果通过以上两种方式还没有获取到,则获取cookie中的p_skey||rv2作为要计算的skey
QZFL.pluginsDefine对象中的定义将23进行了合并
如果URL方式没获取到,则获取cookie中的p_skey||skey||rv2||""作为要计算的skey
从命名上和逻辑上推测p_skey和skey的关系应该是:当前域的p_skey=当前域的父域的skey值


后面的计算方式没变,这个计算方式很早就有了

这次获取的js和15年的没什么区别,这次就把获取方法和具体算法说详细一点

Python3版本的gtk算法代码如下,主机名判断懒得搞了,直接用QZFL.pluginsDefine的第二步,反正能用

def LongToInt(value):  # 由于int+int超出范围后自动转为long型,通过这个转回来
    if value > 0x7fffffff or value < 0x80000000:
        return int(value & 0x7fffffff)
    else:
        return int(value)
def LeftShiftInt(number, step):  # 由于左移可能自动转为long型,通过这个转回来
    if (number << step) > 0x7fffffff or (number << step) < 0x80000000:
        return int((number << step) - 0x200000000)
    else:
        return int(number << step)

def getNewGTK(p_skey, skey, rv2):
    b = p_skey or skey or rv2
    a = 5381
    for i in range(0, len(b)):
        a = a + LeftShiftInt(a, 5) + ord(b[i])
        a = LongToInt(a)
    return a & 0x7fffffff

Python3的完整版获取QQ空间好友列表代码

运行之前先安装httplib2

pip install httplib2

# -*- coding: UTF-8 -*-  
import httplib2
import json
import re

def LongToInt(value):  # 由于int+int超出范围后自动转为long型,通过这个转回来
    if value > 0x7fffffff or value < 0x80000000:
        return int(value & 0x7fffffff)
    else:
        return int(value)
def LeftShiftInt(number, step):  # 由于左移可能自动转为long型,通过这个转回来
    if (number << step) > 0x7fffffff or (number << step) < 0x80000000:
        return int((number << step) - 0x200000000)
    else:
        return int(number << step)

def getNewGTK(p_skey, skey, rv2):
    b = p_skey or skey or rv2
    a = 5381
    for i in range(0, len(b)):
        a = a + LeftShiftInt(a, 5) + ord(b[i])
        a = LongToInt(a)
    return a & 0x7fffffff

h = httplib2.Http()
url = 'http://m.qzone.com/friend/mfriend_list?g_tk=[g_tk]&res_uin=[QQ号码]&res_type=normal&format=json&count_per_page=10&page_index=0&page_type=0&mayknowuin=&qqmailstat='
myqq=''
cookieStr = ''
headers = {'Cookie': cookieStr}
if re.search(r'p_skey=(?P<p_skey>[^;]*)', cookieStr):
    p_skey = re.search(r'p_skey=(?P<p_skey>[^;]*)', cookieStr).group('p_skey')
else:
    p_skey = None
if re.search(r'skey=(?P<skey>[^;]*)', cookieStr):
    skey = re.search(r'skey=(?P<skey>[^;]*)', cookieStr).group('skey')
else:
    skey = None
if re.search(r'rv2=(?P<rv2>[^;]*)', cookieStr):
    rv2 = re.search(r'rv2=(?P<rv2>[^;]*)', cookieStr).group('rv2')
else:
    rv2 = None
print('gtk='+str(getNewGTK(p_skey, skey, rv2)))
url = url.replace('[g_tk]', str(getNewGTK(p_skey, skey, rv2)))
url = url.replace('[QQ号码]', myqq)
print(url)
resp, content = h.request(url, 'GET', headers=headers)
print(resp)
print(content)
output = json.loads(content)  # json字符串转字典  
if output['code'] == -3000:
    print(output['message'])
else:
    items_list = output['data']['list']
    qqlist = set()
    for item in items_list:
        qqlist.add(item['uin'])
        # 打印信息并输出到文件
    print('获取QQ号个数' + str(len(qqlist)))
    filename = 'qqlist.txt'
    fileobj = open(filename, 'w')
    result = [str(qq) + '\n' for qq in sorted(qqlist)]
    fileobj.writelines(result)
    fileobj.flush()
    fileobj.close()
    print('写入完成')

使用方法:复制cookie字符串和QQ号粘贴到cookieStr和myqq的引号里面,然后运行即可


Python2版本的代码相比,处理了以下几个小问题

1.python3把int long合并为int型,左移的代码又不能去掉,所以把int和long类型判断改成数值范围判断,没了long,数值后面的L也要去掉

2.print只能是函数形式了,这里全改成函数形式



  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值