123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- from __future__ import absolute_import, unicode_literals
- import logging
- import random
- import string
- import time
- import requests
- from library.wechatpy.client import api
- from library.wechatpy.client.base import BaseWeChatClient
- from library.wechatpy.utils import WeChatSigner
- from library.wechatbase.exceptions import WeChatException, WechatNetworkException
- logger = logging.getLogger(__name__)
- class WeChatClient(BaseWeChatClient):
- """
- 微信 API 操作类
- 通过这个类可以操作微信 API,发送主动消息、群发消息和创建自定义菜单等。
- """
- API_BASE_URL = 'https://api.weixin.qq.com/cgi-bin/'
- card = api.WeChatCard()
- customservice = api.WeChatCustomService()
- datacube = api.WeChatDataCube()
- device = api.WeChatDevice()
- group = api.WeChatGroup()
- invoice = api.WeChatInvoice()
- material = api.WeChatMaterial()
- media = api.WeChatMedia()
- menu = api.WeChatMenu()
- merchant = api.WeChatMerchant()
- message = api.WeChatMessage()
- misc = api.WeChatMisc()
- poi = api.WeChatPoi()
- qrcode = api.WeChatQRCode()
- scan = api.WeChatScan()
- semantic = api.WeChatSemantic()
- shakearound = api.WeChatShakeAround()
- tag = api.WeChatTag()
- template = api.WeChatTemplate()
- subscribe = api.WeChatNewtmpl()
- user = api.WeChatUser()
- wifi = api.WeChatWiFi()
- wxa = api.WeChatWxa()
- marketing = api.WeChatMarketing()
- def __init__(self, appid, secret, session, timeout=None, auto_retry=True):
- super(WeChatClient, self).__init__(
- appid, session, timeout, auto_retry
- )
- self.appid = appid
- self.secret = secret
- @property
- def nonce_str(self):
- char = string.ascii_letters + string.digits
- return "".join(random.choice(char) for _ in range(32))
- def jsapi_sign(self, url):
- """
- 生成签名给js使用
- """
- jsapi_ticket = self.jsapi_ticket
- timestamp = str(int(time.time()))
- nonce_str = self.nonce_str
- data = [
- 'noncestr={noncestr}'.format(noncestr=nonce_str),
- 'jsapi_ticket={jsapi_ticket}'.format(jsapi_ticket=jsapi_ticket),
- 'timestamp={timestamp}'.format(timestamp=timestamp),
- 'url={url}'.format(url=url),
- ]
- signer = WeChatSigner(delimiter=b'&')
- signer.add_data(*data)
- return {
- 'sign': signer.signature,
- 'timestamp': timestamp,
- 'noncestr': nonce_str,
- 'appId': self.appid,
- 'jsapi_ticket': jsapi_ticket
- }
- def refresh_jsapi_ticket(self):
- """
- 获取微信 JS-SDK ticket
- :return: 返回的 JSON 数据包
- """
- jsapi_ticket_response = self.get(
- 'ticket/getticket',
- params={'type': 'jsapi'}
- )
- ticket = jsapi_ticket_response['ticket']
- expires_in = int(jsapi_ticket_response['expires_in'])
- if expires_in < 600:
- expires_in = expires_in / 2
- else:
- expires_in = expires_in - 600
- self.session.set(self.jsapi_ticket_key, ticket, expires_in)
- return ticket
- def refresh_access_token(self):
- logger.info('Fetching access token for {}'.format(self.appid))
- with requests.sessions.Session() as _session:
- res = _session.get(
- url='https://api.weixin.qq.com/cgi-bin/token',
- params={
- 'grant_type': 'client_credential',
- 'appid': self.appid,
- 'secret': self.secret
- },
- timeout=self.timeout)
- try:
- res.raise_for_status()
- except requests.RequestException as reqe:
- raise WechatNetworkException(
- errCode='HTTP{}'.format(res.status_code),
- errMsg=reqe.message,
- client=self,
- request=reqe.request,
- response=reqe.response
- )
- result = res.json()
- if 'errcode' in result and result['errcode'] != 0:
- raise WeChatException(
- errCode=result['errcode'],
- errMsg=result['errmsg'],
- client=self,
- request=res.request,
- response=res
- )
- expires_in = 7200 - 600
- if 'expires_in' in result:
- expires_in = result['expires_in']
- if expires_in < 600:
- expires_in = expires_in / 2
- else:
- expires_in = expires_in - 600
- self.session.set(
- self.access_token_key,
- result['access_token'],
- expires_in
- )
- return result['access_token']
- class WeChatComponentClient(WeChatClient):
- """
- 开放平台代公众号调用客户端
- """
- def __init__(self, appid, component, session=None, timeout=None):
- # 未用到secret,所以这里没有
- super(WeChatComponentClient, self).__init__(appid, "", session, timeout)
- self.appid = appid
- self.component = component
- def refresh_access_token(self):
- """
- 获取 access token
- 详情请参考 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list\
- &t=resource/res_list&verify=1&id=open1419318587&token=&lang=zh_CN
- :return: 返回的 JSON 数据包
- """
- result = self.component.refresh_authorizer_token(self.appid)
- expires_in = 7200 - 600
- if 'expires_in' in result:
- expires_in = result['expires_in']
- if expires_in < 600:
- expires_in = expires_in / 2
- else:
- expires_in = expires_in - 600
- self.session.set(
- self.access_token_key,
- result['authorizer_access_token'],
- expires_in
- )
- return result['authorizer_access_token']
|