def send_email(to_whom_list, title, content): msg = email.mime.multipart.MIMEMultipart() msg['from'] = EMAIL_HOST msg['to'] = ";".join(to_whom_list) msg['subject'] = title txt = email.mime.text.MIMEText(content) msg.attach(txt) have_exception = False try: smtp = smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) smtp.login(EMAIL_HOST, EMAIL_PASS) result = smtp.sendmail(EMAIL_HOST, to_whom_list, str(msg)) except Exception as e: ERROR('exception when send_email...') ERROR(str(e)) have_exception = True finally: smtp.quit() if have_exception: ERROR('finally raise e: {0}'.format(str(e))) raise e else: INFO('finally no exception raise') return result
def ErrorCode(self, code): if code == 1: ERROR('错误的verify key') self.verifyKey = input('verifyKey:') elif code == 2: ERROR('指定的Bot不存在') self.qq = int(input('qq:')) elif code == 3: WARNING('Session失效或不存在') self.Verify() return 1 elif code == 4: WARNING('Session未认证(未激活)') self.Bind() return 1 elif code == 5: WARNING('发送消息目标不存在(指定对象不存在)') elif code == 6: WARNING('指定文件不存在,出现于发送本地图片') elif code == 10: WARNING('无操作权限,指Bot没有对应操作的限权') elif code == 20: WARNING('Bot被禁言,指Bot当前无法向指定群发送消息') elif code == 30: WARNING('消息过长') elif code == 400: WARNING('错误的访问,如参数错误等') return 0
def send(self, to_whom_list, title, content): """发送邮件的主体逻辑: 1)待发送邮件=以前发送失败的+现在要发送的 2)逐封邮件发送(可能需要调整一个发送间隔,因为太快连续发送,会导致邮件服务器拒绝服务; 3)收集这一次发送失败的邮件; 4)清空原来的“发送失败”数据库,把新的数据保存进去。 """ emails_to_send = self.db.get_all() # 以前发送失败的邮件 if len(emails_to_send) > 0: INFO('有{0}封发送失败的邮件'.format(len(emails_to_send))) # 由于收件人是一个列表,对于数据库的一个字段,所以需要存入时先序列化为字符串,读取则反过来 for i in range(0, len(emails_to_send)): emails_to_send[i][0] = emails_to_send[i][0].splite(self.delimiter) emails_to_send.append([to_whom_list, title, content]) now_fail_emails = [] # 当前发送失败的邮件列表 for email in emails_to_send: try: result = send_email(email[0], email[1], email[2]) except Exception as e: result = str(e) ERROR('smtplib error happend.......................') ERROR('send_result:{0}'.format(result)) INFO('send_result:{0}'.format(result)) if len(result) > 0: now_fail_emails.append(email) self.db.delete_all() INFO("fail:{0} ".format(len(now_fail_emails))) for email in now_fail_emails: email[0] = self.delimiter.join(email[0]) self.db.insert(email) return len(now_fail_emails) == 0
def getTargetContent(self): """获取指定页面的目标内容: 1)指定页面由SinglePageSpider获取; 2)目标内容由正则表达式匹配得到。 Returns: a list of update chapters' relative path and its title such as [('http://dazhuzai.net.cn/dazhuzai-1309.html', 'title 1'), ] """ try: page = SinglePageSpider().getPage(self.url, self.coding) result = re.findall(self.pattern, page) if result: if self.url_prefix: for i in range(len(result)): chapter_url = self.url_prefix + result[i][0] if len(result[i]) >= 3: data = result[i][1:len(result[i])] chapter_title = ' '.join(reversed(data)) else: chapter_title = result[i][1] result[i] = (chapter_url, chapter_title) INFO('正则匹配成功:{0}{1}'.format(len(result), self.tips)) return result else: INFO('!!!!!!!!!!正则匹配size = 0!!!!!!!!!!!') return None except Exception as e: ERROR('-------获取网页失败:-------') ERROR(e) return None
def Plug(self, moduleName): self.unplug(moduleName) try: module = Import(moduleName) except Exception as e: result = '错误:无法加载插件 %s ,%s: %s' % (moduleName, type(e), e) ERROR('', exc_info=True) ERROR(result) self.unplug(moduleName) else: self.unplug(moduleName, removeJob=False) names = [] for slotName in self.slotsTable.keys(): if hasattr(module, slotName): self.slotsTable[slotName].append(getattr(module, slotName)) names.append(slotName) if not names and moduleName not in self.schedTable: result = '警告:插件 %s 中没有定义回调函数或定时任务' % moduleName WARNING(result) else: self.plugins[moduleName] = module jobs = self.schedTable.get(moduleName, []) jobNames = [f.func.__name__ for f in jobs] result = '成功:加载插件 %s(回调函数%s、定时任务%s)' % \ (moduleName, names, jobNames) INFO(result) if self.Mirai.started and hasattr(module, 'onPlug'): _call(module.onPlug, self) return result
def Get(*args, **kwargs): while True: try: return requests.get(*args, **kwargs) except requests.exceptions.ConnectionError: ERROR('无法连接倒Mirai,请检查服务、地址、端口。') except: raise RequestError
def Run(self): self.onStartupComplete() self.onPlug() StartDaemonThread(self.pollForever) StartDaemonThread(self.intervalForever) self.scheduler.start() Put(self.Update) try: MainLoop() except SystemExit as e: raise except Exception as e: ERROR('', exc_info=True) ERROR('Mainloop 发生未知错误:%r', e) self.onExit(1, 'unknown-error', e) raise SystemExit(1)
def pollForever(self): while self.Mirai.started: try: result = self.Mirai.GetMessage() except RequestError: Put(sys.exit) break except: ERROR('qsession.Poll 方法出错', exc_info=True) else: if not result: continue for r in result: Put(self.MessageAnalyst, r)
def LoadQQ(self): time.sleep(0.5) fn = self.absPath('qq(pid%s)' % os.getpid()) if not os.path.exists(fn): return self.qq try: with open(fn, 'r') as f: qq = f.read() except Exception as e: ERROR('无法读取上次运行的 QQ 号码, %s', e) qq = self.qq else: self.qq = qq try: os.remove(fn) except OSError: pass return qq
def urlGet(self, url, data=None, **kw): self.session.headers.update(kw) try: if data is None: return self.session.get(url) else: return self.session.post(url, data=data) except (requests.exceptions.SSLError, AttributeError): # by @staugur, @pandolia if self.session.verify: self.session.verify = False ERROR('无法和腾讯服务器建立私密连接,' ' 10 秒后将尝试使用非私密连接和腾讯服务器通讯。' '若您不希望使用非私密连接,请按 Ctrl+C 退出本程序。') time.sleep(10) WARN('已开始尝试使用非私密连接和腾讯服务器通讯。') requests.packages.urllib3.disable_warnings( requests.packages.urllib3.exceptions.InsecureRequestWarning ) return self.urlGet(url, data, **kw) else: raise
def fetchGroups(self, contacts, silence=True): if not silence: INFO('登录 Step7 - 获取群列表') INFO('=' * 60) for i in range(5): result = self.smartRequest( url='http://s.web2.qq.com/api/get_group_name_list_mask2', data={ 'r': JsonDumps({ 'vfwebqq': self.vfwebqq, 'hash': self.hash }) }, Referer=('http://d1.web2.qq.com/proxy.html?v=20151105001&' 'callback=1&id=2')) if 'gmarklist' in result: break else: ERROR('获取群列表出错,等待 3 秒后再次尝试一次') time.sleep(3) else: CRITICAL('无法获取到群列表') raise QSession.Error markDict = dict((d['uin'], d['markname']) for d in result['gmarklist']) qqResult = self.smartRequest( url='http://qun.qq.com/cgi-bin/qun_mgr/get_group_list', data={'bkn': self.bkn}, Referer='http://qun.qq.com/member.html') qqDict = defaultdict(list) for k in ('create', 'manage', 'join'): for d in qqResult.get(k, []): name = d['gn'].replace(' ', ' ').replace('&', '&') qqDict[name].append(d['gc']) for info in result['gnamelist']: uin = info['gid'] name = info['name'] mark = markDict.get(uin, '') qqlist = qqDict.get(name, []) if len(qqlist) == 1: qq = qqlist.pop() else: qq = self.fetchGroupQQ(uin) for x in qqlist: if (qq - x) % 1000000 == 0: qq = x break try: qqlist.remove(qq) except ValueError: pass members = self.fetchGroupMember(info['code']) c = contacts.Add('group', str(uin), name, str(qq), '', mark, members) if not silence: INFO(repr(c)) for uin, name in members.items(): INFO(' 成员: %s, uin%s', name, uin) INFO('=' * 60) if not silence: INFO('获取群列表成功,共 %d 个群' % len(result))
def _call(func, *args, **kwargs): try: StartDaemonThread(func, *args, **kwargs) except Exception as e: ERROR('', exc_info=True) ERROR('执行 %s.%s 时出错,%s', func.__module__, func.__name__, e)