2019独角兽企业重金招聘Python工程师标准>>>
要从公众号导出关注用户,共需要三步:
- 获取access_token
- 获取关注用户的Open_id
- 根据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。
这里遇到两个问题:
- 在windows系统,打印请求回来的内容时,遇到gbk编码问题,
import sys
import io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='gb18030')
用上面的代码片段,将打印输出流的编码指定为gb18030,可以支持中文输出
- 昵称里有表情符号,无法入库 首先需要让请求返回的数据编码是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函数的使用,在上面的代码里有。