├── README.md └── qywx.py /README.md: -------------------------------------------------------------------------------- 1 | # QywxPython 2 | python3操作企业微信,发送文字、图片、语音、视频、文件,支持命令行方式调用,其他类引用。 3 | -------------------------------------------------------------------------------- /qywx.py: -------------------------------------------------------------------------------- 1 | import urllib.request 2 | import json 3 | import requests 4 | import logging 5 | import os 6 | import sys 7 | import getopt 8 | 9 | class Qywx(): 10 | ''' 11 | #-----------发送企业微信的消息格式------------ 12 | #图片(image):1MB,支持JPG,PNG格式 13 | #语音(voice):2MB,播放长度不超过60s,支持AMR格式 14 | #视频(video):10MB,支持MP4格式 15 | #普通文件(file):20MB 16 | #-------------------------------- 17 | ''' 18 | def __init__(self,corpid='yourid',corpsecret='yoursecret',is_log=True,log_path="qywx.log",log_level=0): 19 | """初始化,需要传入企业ID和密钥,在企业微信的页面上有显示""" 20 | url="https://qyapi.weixin.qq.com" 21 | self.corpid=corpid 22 | self.corpsecret=corpsecret 23 | self.is_log=is_log 24 | self.log_path=log_path 25 | self.log_level=log_level 26 | if is_log==True: 27 | LOG_FORMAT = "%(asctime)s - %(levelname)s: %(message)s" 28 | DATE_FORMAT = "%m/%d/%Y %H:%M:%S %p" 29 | if log_level==0: 30 | logging.basicConfig(level=logging.INFO,filename=log_path,format=LOG_FORMAT, datefmt=DATE_FORMAT) 31 | else: 32 | logging.basicConfig(level=logging.ERROR,filename=log_path,format=LOG_FORMAT, datefmt=DATE_FORMAT) 33 | 34 | def send_message(self,msg,msgtype,agid): 35 | upload_token=self.get_upload_token(self.corpid,self.corpsecret) 36 | if msgtype=="text": 37 | data=self.msg_messages(msg,agid,msgtype='text',msgid="content") 38 | elif msgtype=="image": 39 | media_id=self.get_media_ID(msg,upload_token,msgtype="image") 40 | data=self.msg_messages(media_id,agid,msgtype='image',msgid="media_id") 41 | elif msgtype=="voice": 42 | media_id=self.get_media_ID(msg,upload_token,msgtype="voice") 43 | data=self.msg_messages(media_id,agid,msgtype='voice',msgid="media_id") 44 | elif msgtype=="video": 45 | media_id=self.get_media_ID(msg,upload_token,msgtype="video") 46 | data=self.msg_messages(media_id,agid,msgtype='video',msgid="media_id") 47 | elif msgtype=="file": 48 | media_id=self.get_media_ID(msg,upload_token,msgtype="file") 49 | data=self.msg_messages(media_id,agid,msgtype='file',msgid="media_id") 50 | else: 51 | raise Exception("msgtype参数错误,参数只能是image或text或voice或video或file") 52 | url="https://qyapi.weixin.qq.com" 53 | token=self.get_token(url,self.corpid,self.corpsecret) 54 | send_url = '%s/cgi-bin/message/send?access_token=%s' % (url,token) 55 | respone=urllib.request.urlopen(urllib.request.Request(url=send_url, data=data)).read() 56 | x = json.loads(respone.decode())['errcode'] 57 | if x == 0: 58 | print ("{} 发送成功".format(msg)) 59 | if self.is_log==True: 60 | logging.info("{} 发送成功".format(msg)) 61 | else: 62 | print ("{} 发送失败".format(msg)) 63 | if self.is_log==True: 64 | logging.info("{} 发送失败".format(msg)) 65 | 66 | def send_msg_message(self,msg,agid=1000002): 67 | try: 68 | self.send_message(msg,'text',agid) 69 | except Exception as e: 70 | if self.is_log==True: 71 | logging.error(e) 72 | def send_image_message(self,path,agid=1000002): 73 | if path.endswith("jpg")==False and path.endswith("png")==False: 74 | raise Exception("图片只能为jpg或png格式") 75 | if os.path.getsize(path)>1048576: 76 | raise Exception("图片大小不能超过1MB") 77 | try: 78 | self.send_message(path,'image',agid) 79 | except Exception as e: 80 | if self.is_log==True: 81 | logging.error(e) 82 | def send_voice_message(self,path,agid=1000002): 83 | if path.endswith("amr")==False: 84 | raise Exception("语音文件只能为amr格式,并且不能大于2MB,不能超过60s") 85 | if os.path.getsize(path)>2097152: 86 | raise Exception("语音文件大小不能超过2MB,并且不能超过60s,只能为amr格式") 87 | try: 88 | self.send_message(path,'voice',agid) 89 | except Exception as e: 90 | if self.is_log==True: 91 | logging.error(e) 92 | def send_video_message(self,path,agid=1000002): 93 | if path.endswith("mp4")==False: 94 | raise Exception("视频文件只能为mp4格式,并且不能大于10MB") 95 | if os.path.getsize(path)>10485760: 96 | raise Exception("视频文件大小不能超过10MB,只能为mp4格式") 97 | try: 98 | self.send_message(path,'video',agid) 99 | except Exception as e: 100 | if self.is_log==True: 101 | logging.error(e) 102 | def send_file_message(self,path,agid=1000002): 103 | if os.path.getsize(path)>20971520: 104 | raise Exception("文件大小不能超过20MB") 105 | try: 106 | self.send_message(path,'file',agid) 107 | except Exception as e: 108 | if self.is_log==True: 109 | logging.error(e) 110 | 111 | def get_token(self,url, corpid, corpsecret): 112 | token_url = '%s/cgi-bin/gettoken?corpid=%s&corpsecret=%s' % (url, corpid, corpsecret) 113 | token = json.loads(urllib.request.urlopen(token_url).read().decode())['access_token'] 114 | return token 115 | def get_upload_token(self,corid,corsec): 116 | gurl="https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={}&corpsecret={}".format(corid,corsec) 117 | r=requests.get(gurl) 118 | dict_result=(r.json()) 119 | return dict_result['access_token'] 120 | 121 | def get_media_ID(self,path,token,msgtype="image"): 122 | """上传资源到企业微信的存储上,msgtype有image,voice,video,file""" 123 | media_url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload?access_token={}&type={}".format(token,msgtype) 124 | with open(path, 'rb') as f: 125 | files = {msgtype: f} 126 | r = requests.post(media_url, files=files) 127 | re = json.loads(r.text) 128 | return re['media_id'] 129 | 130 | def msg_messages(self,msg,agid,msgtype='text',msgid="content"): 131 | """ 132 | msgtype有text,image,voice,video,file;如果msgytpe为text,msgid为content,如果是其他,msgid为media_id。 133 | msg为消息的实际内容,如果是文本消息,则为字符串,如果是其他类型,则传递media_id的值。 134 | 135 | """ 136 | values = { 137 | "touser": '@all', 138 | "msgtype": msgtype, 139 | "agentid": agid, 140 | msgtype: {msgid: msg}, 141 | "safe": 0 142 | } 143 | msges=(bytes(json.dumps(values), 'utf-8')) 144 | return msges 145 | 146 | def usage(): 147 | str=""" 148 | ********************调用格式如下********************** 149 | 发送文本消息: 150 | python qywx.py -t text -m 你要发送的消息 151 | 发送文本消息,指定要发送的应用的ID: 152 | python qywx.py -t text -m 你要发送的消息 -a 1000005 153 | 发送图片消息: 154 | python qywx.py -t image -m 图片的全路径 155 | 发送图片消息,指定要发送的应用的ID: 156 | python qywx.py -t image -m 图片的全路径 -a 1000005 157 | 发送语音消息: 158 | python qywx.py -t voice -m 语音的路径 159 | 发送视频消息: 160 | python qywx.py -t video -m 视频的路径 161 | 发送文件消息: 162 | python qywx.py -t file -m 文件的路径 163 | *********************注意事项*************************** 164 | 图片只能是png或jpg图片,大小不能超过1MB 165 | 语音只能是amr格式,播放长度不能超过60s,大小不能超过2MB 166 | 视频只能是mp4格式,大小不能超过10MB 167 | 普通文件大小不能超过20MB 168 | ******************************************************** 169 | *********************例子******************************* 170 | python qywx.py -t image -m /root/test.png 171 | python qywx.py -t text -m 测试消息 172 | ******************************************************** 173 | """ 174 | print(str) 175 | if __name__=="__main__": 176 | qywx=Qywx() #Qywx(corpid='yourid',corpsecret='yoursecret',is_log=True,log_path='yourpath') 177 | try: 178 | options,args = getopt.getopt(sys.argv[1:],"ht:m:a:",["help","type=","message=","agentid="]) 179 | except Except as e: 180 | print(e) 181 | a=1000002 182 | t=None 183 | m=None 184 | for name,value in options: 185 | if name in ("-h","--help"): 186 | usage() 187 | elif name in ("-t","--type"): 188 | t=value 189 | elif name in ("-m","--message"): 190 | m=value 191 | elif name in ("-a","--agentid"): 192 | a=value 193 | else: 194 | usage() 195 | if t and m: 196 | if t=="text": 197 | qywx.send_msg_message(m,agid=a) 198 | elif t=="image": 199 | qywx.send_image_message(m,agid=a) 200 | elif t=="voice": 201 | qywx.send_voice_message(m,agid=a) 202 | elif t=="video": 203 | qywx.send_video_message(m,agid=a) 204 | elif t=="file": 205 | qywx.send_file_message(m,agid=a) 206 | else: 207 | usage() 208 | #-----------代码中直接调用--------------------- 209 | # qywx=Qywx() #Qywx(corpid='yourid',corpsecret='yoursecret',is_log=True,log_path='yourpath') 210 | # qywx.send_msg_message("test") 211 | # qywx.send_image_message("/root/test.png") 212 | # qywx.send_voice_message("/root/test.amr") 213 | # qywx.send_video_message("/root/test.mp4") 214 | # qywx.send_file_message("/root/test.mp3") 215 | # qywx.send_msg_message("test",agid=1000003) 216 | #-----------代码中直接调用--------------------- 217 | --------------------------------------------------------------------------------