使用python导出公众号关注用户

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

要从公众号导出关注用户,共需要三步:

  1. 获取access_token
  2. 获取关注用户的Open_id
  3. 根据open_id获取用户的信息

获取access_token

公众号文档对access_token的简介:

URL: https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
返回结果:{"access_token":"ACCESS_TOKEN","expires_in":7200}

字段解析:
grant_type	是	获取access_token填写client_credential
appid	是	第三方用户唯一凭证
secret	是	第三方用户唯一凭证密钥,即appsecret

获取access_token的代码:

access_token = None
def get_access_token():
	url = 'https://api.weixin.qq.com/cgi-bin/token'
	global access_token
	params = {
		'grant_type':'client_credential',
		'appid':'xxxxx', #从公众号上找到自己的appid
		'secret':'xxxx', #从公众号上找到自己的secret
	}

	response = get(url, params)

	# print(response.text)

	json_data = json.loads(response.text)
	access_token = json_data['access_token']

access_token的有效期是7200秒,过期需要重新获取。

获取关注用户的Open_id

公众号文档对获取关注用户的open_id列表的文档:

URL: https://api.weixin.qq.com/cgi-bin/user/get?access_token=ACCESS_TOKEN&next_openid=NEXT_OPENID

返回结果:{
"total":2,
"count":2,
"data":{
"openid":["OPENID1","OPENID2"]},
"next_openid":"NEXT_OPENID"
}

字段解析:
total	关注该公众账号的总用户数
count	拉取的OPENID个数,最大值为10000
data	列表数据,OPENID的列表
next_openid	拉取列表的最后一个用户的OPENID

获取open_id列表的python代码:

openids = []
def get_openids(next_openid=''):
	global openids
	url = 'https://api.weixin.qq.com/cgi-bin/user/get'
	params = {
		'access_token':access_token,
		'next_openid':next_openid,
	}

	response = get(url, params)

	# print(response.text)

	json_data = json.loads(response.text)
	count = json_data['count']
	openid_list = json_data['data']['openid']
	openids.extend(openid_list)
	next_openid = json_data['next_openid']

	logger.info('>>> count=%s, next_openid=%s'%(count,next_openid))

	if count == 10000:
		get_openids(next_openid)

每个请求最多返回10000个open_id。 第一次请求,next_open_id是空的。 我这里直接判断上次返回的open_id的数量。如果返回数量是10000个,就尝试再请求下一批Open_id。

根据open_id获取用户的信息

公众号文档对获取用户信息的文档描述:

URL: https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=ACCESS_TOKEN
请求参数:
{
    "user_list": [
        {
            "openid": "otvxTs4dckWG7imySrJd6jSi0CWE", 
            "lang": "zh_CN"
        }, 
        {
            "openid": "otvxTs_JZ6SEiP0imdhpi50fuSZg", 
            "lang": "zh_CN"
        }
    ]
}

返回结果:
{
    "subscribe": 1, 
    "openid": "o6_bmjrPTlm6_2sgVt7hMZOPfL2M", 
    "nickname": "Band", 
    "sex": 1, 
    "language": "zh_CN", 
    "city": "广州", 
    "province": "广东", 
    "country": "中国", 
    "headimgurl":"http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0",
    "subscribe_time": 1382694957,
    "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
    "remark": "",
    "groupid": 0,
    "tagid_list":[128,2],
    "subscribe_scene": "ADD_SCENE_QR_CODE",
    "qr_scene": 98765,
    "qr_scene_str": ""
}

字段解析:
subscribe	用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。
openid	用户的标识,对当前公众号唯一
nickname	用户的昵称
sex	用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
city	用户所在城市
country	用户所在国家
province	用户所在省份
language	用户的语言,简体中文为zh_CN
headimgurl	用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
subscribe_time	用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间
unionid	只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
remark	公众号运营者对粉丝的备注,公众号运营者可在微信公众平台用户管理界面对粉丝添加备注
groupid	用户所在的分组ID(兼容旧的用户分组接口)
tagid_list	用户被打上的标签ID列表
subscribe_scene	返回用户关注的渠道来源,ADD_SCENE_SEARCH 公众号搜索,ADD_SCENE_ACCOUNT_MIGRATION 公众号迁移,ADD_SCENE_PROFILE_CARD 名片分享,ADD_SCENE_QR_CODE 扫描二维码,ADD_SCENEPROFILE LINK 图文页内名称点击,ADD_SCENE_PROFILE_ITEM 图文页右上角菜单,ADD_SCENE_PAID 支付后关注,ADD_SCENE_OTHERS 其他
qr_scene	二维码扫码场景(开发者自定义)
qr_scene_str	二维码扫码场景描述(开发者自定义)

获取用户信息的代码:

user_info_list=[]
def get_unionids():
	url = 'https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=%s'%access_token
	
	total=len(openids)
	step=100
	repeat=int(total/step+(1 if total%step>0 else 0))

	global user_info_list

	for i in range(repeat):

		low_idx=step*i
		high_idx=len(openids) if len(openids) <= step*(i+1) else step*(i+1)

		if len(openids) <= low_idx:
			break

		openid_params = []
		for openid in openids[low_idx:high_idx]:
			openid_params.append({'openid':openid,'lang':'zh_CN'})

		payload = {'user_list':openid_params}

		logger.info('step=%s,low index=%s,high index=%s' % (i,low_idx,high_idx))
		#json_data = json.dumps(payload)
		#logger.info(json_data)
		
		response = post_json(url, payload)

		json_data = json.loads(response.text)

		try:
			user_infos = json_data['user_info_list']
			user_info_list.extend(user_infos)
			#store_user_infos()
			#exit()
		except KeyError:
			logger.error(response.status_code)
			logger.error(response.text)

这个请求需要用post发送。 每次只能发送100个open_id。

这里遇到两个问题:

  1. 在windows系统,打印请求回来的内容时,遇到gbk编码问题,
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='gb18030')

用上面的代码片段,将打印输出流的编码指定为gb18030,可以支持中文输出

  1. 昵称里有表情符号,无法入库 首先需要让请求返回的数据编码是utf-8 mysql数据库,数据表,文本字段的编码是utf8mb4, 修改完数据配置后,一定要重启数据库,这些编码才能生效。

修改数据库编码的脚本如下:

ALTER DATABASE hello_moto CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci;

ALTER TABLE t_yown_user CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

ALTER TABLE tb_user CHANGE name name VARCHAR(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

数据库的配置(/etc/my.cnf):

[mysql]
default-character-set=utf8mb4

[mysqld]
character_set_server=utf8mb4
init_connect='SET NAMES utf8mb4'

为了简化和重用发送http请求的代码,做了一个小工具类 http.py:

import requests


requests.packages.urllib3.disable_warnings()

s=requests.session()  #获取会话对象

def get(url, data=None):
    response = s.get(url, params=data) if data else s.get(url)

    return response

def post_json(url, payload):
    myheader = {
        "Content-Encoding":"application/json; encoding=utf-8",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:44.0) Gecko/20100101 Firefox/44.0",
        "Accept": "application/json, text/javascript, */*; q=0.01",
        "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
        "Accept-Encoding": "gzip, deflate, br",
        "Content-Type": "application/json; charset=utf-8",
        "Connection": "keep-alive"
    }

    response = s.post(url, headers=myheader, json=payload, verify=False)

    response.encoding = 'utf-8'

    return response

这里面的get, post_json函数的使用,在上面的代码里有。

转载于:https://my.oschina.net/ez8life/blog/1931238

你可能感兴趣的:(使用python导出公众号关注用户)