def _parse(self, dct): if 'deleted' in dct and dct['deleted']: logger.debug("This is a deleted message %s of SinaWeiboStatusMessage", dct["id"]) self.parsed.time = "unknown" self.parsed.username = "******" self.parsed.userid = "unknown" self.parsed.text = "unknown" self.deleted = True return self.ID.id = dct["id"] self.parsed.time = utils.str2utc(dct["created_at"]) self.parsed.username = dct['user']['name'] self.parsed.userid = dct['user']['id'] self.parsed.reposts_count = dct['reposts_count'] self.parsed.comments_count = dct['comments_count'] if 'retweeted_status' in dct: self.parsed.username_orig = "unknown" try: self.parsed.username_orig = dct['retweeted_status']['user']['name'] except KeyError: logger.warning('KeyError when parsing SinaWeiboStatus. May be deleted original message') self.parsed.text_orig = dct['retweeted_status']['text'] self.parsed.text_trace = dct['text'] self.parsed.text = self.parsed.text_trace \ + " || " + "@" + self.parsed.username_orig \ + " : " + self.parsed.text_orig else: self.parsed.text_orig = dct['text'] self.parsed.text_trace = None self.parsed.text = self.parsed.text_orig
def unlike(self, message, channel=None): """ unlike a message """ if isinstance(message, snstype.Message): mID = message.ID elif isinstance(message, snstype.MessageID): mID = message else: logger.warning("unknown type: %s", type(message)) return {} if channel: if channel in self: # If the platforms are not identical, unlike method will surly fail if self[channel].platform != mID.platform: logger.warning("Inter-platform unlike method is not supported.") elif self[channel].is_expired(): logger.warning("channel '%s' is expired. Do nothing.", channel) else: re = self[channel].unlike(message) else: logger.warning("channel '%s' is not in pocket. Do nothing.", channel) else: for c in self.itervalues(): if self.__check_method(c, 'unlike') and not c.is_expired(): re = c.unlike(message) break logger.info("UnLike status '%s'. Result: %s",\ message.digest(), re) return re
def home_timeline(self, count=20): '''Get home timeline * function : get statuses of yours and your friends' * parameter count: number of statuses ''' url = "https://api.weibo.com/2/statuses/home_timeline.json" params = {} params['count'] = count params['access_token'] = self.token.access_token jsonobj = self._http_get(url, params) statuslist = snstype.MessageList() try: if("error" in jsonobj): logger.warning("error json object returned: %s", jsonobj) return [] for j in jsonobj['statuses']: statuslist.append(self.Message(j,\ platform = self.jsonconf['platform'],\ channel = self.jsonconf['channel_name']\ )) except Exception, e: logger.warning("Catch exception: %s", e)
def unlike(self, message): ''' Unlike method * Weibo doesn't provide an API for "unlike" * So "unfavourite" function supersedes "unlike" * Here "unlike" means "remove from my favourites" * Receive a message ''' mID = message.ID try: ret = self.weibo_request('favorites/destroy', 'POST', {'id': mID.id}) # error_code 20705 means this status had never been collected. # For the purpose of backward compatibility, we also view # it as a successful unlike if 'favorited_time' in ret or ret["error_code"] == 20705: return True else: logger.warning("'%s' unlikes status '%s' fail. ret: %s", self.jsonconf.channel_name, mID, ret) return False except Exception, e: logger.warning("'%s' unlike status '%s' fail. ret: %s", self.jsonconf.channel_name, mID, ret) return False
def update(self, text): try: self.client.miniblog.new(text) return True except Exception, e: logger.warning("DoubanAPIError: %s", e) return False
def save_config(self, fn_channel = DIR_DEFAULT_CONF_CHANNEL, fn_pocket = DIR_DEFAULT_CONF_POCKET): """ Save configs: reverse of load_config Configs can be modified during execution. snsapi components communicate with upper layer using Python objects. Pocket will be the unified place to handle file transactions. """ conf_channel = [] for c in self.itervalues(): conf_channel.append(c.jsonconf) conf_pocket = self.jsonconf try: json.dump(conf_channel, open(fn_channel, "w"), indent = 2) json.dump(conf_pocket, open(fn_pocket, "w"), indent = 2) except: raise snserror.config.save logger.info("save configs done")
def _fetch_code_local_username_password(self): try: login_username = self.auth_info.login_username login_password = self.auth_info.login_password app_key = self.jsonconf.app_key app_secret = self.jsonconf.app_secret callback_url = self.auth_info.callback_url referer_url = self._last_requested_url postdata = {"client_id": app_key, "redirect_uri": callback_url, "userId": login_username, "passwd": login_password, "isLoginSina": "0", "action": "submit", "response_type": "code", } headers = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; rv:11.0) Gecko/20100101 Firefox/11.0", "Host": "api.weibo.com", "Referer": referer_url } auth_url = "https://api.weibo.com/oauth2/authorize" # auth_url = self.auth_info.auth_url resp_url = self._http_post(auth_url, data=postdata, headers=headers, json_parse=False).url logger.debug("response URL from local post: %s", resp_url) return resp_url except Exception, e: logger.warning("Catch exception: %s", e)
def _parse(self, dct): if "deleted" in dct and dct["deleted"]: logger.debug("This is a deleted message %s of SinaWeiboStatusMessage", dct["id"]) self.parsed.time = "unknown" self.parsed.username = "******" self.parsed.userid = "unknown" self.parsed.text = "unknown" self.deleted = True return self.ID.id = dct["id"] self.parsed.time = utils.str2utc(dct["created_at"]) self.parsed.username = dct["user"]["name"] self.parsed.userid = dct["user"]["id"] self.parsed.reposts_count = dct["reposts_count"] self.parsed.comments_count = dct["comments_count"] if "retweeted_status" in dct: self.parsed.username_orig = "unknown" try: self.parsed.username_orig = dct["retweeted_status"]["user"]["name"] except KeyError: logger.warning("KeyError when parsing SinaWeiboStatus. May be deleted original message") self.parsed.text_orig = dct["retweeted_status"]["text"] self.parsed.text_trace = dct["text"] self.parsed.text = ( self.parsed.text_trace + " || " + "@" + self.parsed.username_orig + " : " + self.parsed.text_orig ) else: self.parsed.text_orig = dct["text"] self.parsed.text_trace = None self.parsed.text = self.parsed.text_orig
def reply(self, statusId, text): res = None flag = False try: # The order in the bracket is important since there # exists "SHARE_XXXX" type. In order to figure out # the actual type, SHARE must be put in the first position. for msg_type in [ "SHARE", "BLOG", "PHOTO", "ALBUM", "STATUS", "VIDEO" ]: if msg_type in statusId.feed_type: flag = True break if flag: res = self.renren_request(method="comment/put", content=text, commentType=msg_type, entryOwnerId=statusId.source_user_id, entryId=statusId.resource_id) else: return BooleanWrappedData(False, { 'errors': ['SNSAPI_NOT_SUPPORTED'], }) except Exception, e: logger.warning('Catch exception: %s', e) return BooleanWrappedData(False, { 'errors': ['PLATFORM_'], })
def unlike(self, message): try: self.client.miniblog.unlike(message.ID.id) return True except Exception, e: logger.warning("DoubanAPIError, %s", e) return False
def forward(self, message, text): try: self.client.miniblog.reshare(message.ID.id) return True except Exception, e: logger.warning("DoubanAPIError: %s", e) return False
def reply(self, statusID, text): try: self.client.miniblog.comment.new(statusID.id, text) return True except Exception, e: logger.warning('DoubanAPIError: %s', str(e)) return False
def report_time_wrapper(*al, **ad): start = time.time() ret = func(*al, **ad) end = time.time() logger.info("Function '%s' execution time: %.2f", func.__name__, end - start) return ret
def save_config(self, fn_channel=DIR_DEFAULT_CONF_CHANNEL, fn_pocket=DIR_DEFAULT_CONF_POCKET): """ Save configs: reverse of load_config Configs can be modified during execution. snsapi components communicate with upper layer using Python objects. Pocket will be the unified place to handle file transactions. """ conf_channel = [] for c in self.itervalues(): conf_channel.append(c.jsonconf) conf_pocket = self.jsonconf try: json.dump(conf_channel, open(fn_channel, "w"), indent=2) json.dump(conf_pocket, open(fn_pocket, "w"), indent=2) except: raise snserror.config.save logger.info("save configs done")
def reply(self, statusId, text): res = None flag = False try: # The order in the bracket is important since there # exists "SHARE_XXXX" type. In order to figure out # the actual type, SHARE must be put in the first position. for msg_type in ["SHARE", "BLOG", "PHOTO", "ALBUM", "STATUS", "VIDEO"]: if msg_type in statusId.feed_type: flag = True break if flag: res = self.renren_request( method="comment/put", content=text, commentType=msg_type, entryOwnerId=statusId.source_user_id, entryId=statusId.resource_id ) else: return BooleanWrappedData(False, { 'errors': ['SNSAPI_NOT_SUPPORTED'], }) except Exception, e: logger.warning('Catch exception: %s', e) return BooleanWrappedData(False, { 'errors': ['PLATFORM_'], })
def update_func(self): logger.debug("acquiring lock") self.dblock.acquire() try: conn = sqlite3.connect(self.sqlitefile) conn.row_factory = sqlite3.Row cursor = conn.cursor() cursor.execute("SELECT * FROM pending_update") i = cursor.fetchone() if i: cursor.execute("DELETE FROM pending_update WHERE id = ?", (i['id'], )) j = { 'id': str(i['id']), 'args': str2obj(str(i['args'])), 'kwargs': str2obj(str(i['kwargs'])), 'type': str(i['type']), 'callback': str2obj(str(i['callback'])) } res = getattr(self.sp, j['type'])(*j['args'], **j['kwargs']) if j['callback']: j['callback'](self, res) conn.commit() cursor.close() except Exception, e: logger.warning("Error while updating: %s" % (str(e)))
def _forward(self, mID, text): """ Raw forward method * Only support Sina message * Use 'text' as exact comment sequence """ try: ret = self.weibo_request("statuses/repost", "POST", {"id": mID.id, "status": text}) if "id" in ret: return True else: logger.warning( "'%s' forward status '%s' with comment '%s' fail. ret: %s", self.jsonconf.channel_name, mID, text, ret, ) return False except Exception as e: logger.warning( "'%s' forward status '%s' with comment '%s' fail: %s", self.jsonconf.channel_name, mID, text, e ) return False
def request_url(self, url): if self.auth_info.cmd_request_url == "(webbrowser)": self.open_brower(url) elif self.auth_info.cmd_request_url == "(console_output)": utils.console_output(url) elif self.auth_info.cmd_request_url == "(local_webserver)+(webbrowser)": host = self.auth_info.host port = self.auth_info.port from third.server import ClientRedirectServer from third.server import ClientRedirectHandler import socket try: self.httpd = ClientRedirectServer((host, port), ClientRedirectHandler) self.open_brower(url) except socket.error: raise snserror.auth else: self.__last_request_time = self.time() cmd = "%s '%s'" % (self.auth_info.cmd_request_url, url) logger.debug("request_url command is: %s", cmd) res = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True).stdout.read().rstrip() logger.debug("request_url result is: %s", res) return
def unlike(self, message): res = None flag = False try: # The order in the bracket is important since there # exists "SHARE_XXXX" type. In order to figure out # the actual type, SHARE must be put in the first position. for msg_type in [ "SHARE", "BLOG", "PHOTO", "ALBUM", "STATUS", "VIDEO" ]: if msg_type in message.ID.feed_type: flag = True break if flag: res = self.renren_request(method="like/ugc/remove", ugcOwnerId=message.ID.source_user_id, likeUGCType="TYPE_" + msg_type, ugcId=message.ID.resource_id) else: return False except Exception as e: logger.warning('Catch exception: %s', type(e)) return False if res: return True else: return False
def forward(self, message, text): res = None try: if message.ID.feed_type == 'STATUS': res = self.renren_request( method='status.forward', status=text, forward_id=message.ID.status_id, forward_owner=message.ID.source_user_id, ) elif message.ID.feed_type != 'OTHER': res = self.renren_request(method='share.share', type=str({ 'BLOG': 1, 'PHOTO': 2, 'SHARE': 20 }[message.parsed.feed_type]), ugc_id=message.ID.status_id, user_id=message.ID.source_user_id, comment=text) else: return BooleanWrappedData(False, { 'errors': ['SNSAPI_NOT_SUPPORTED'], }) except Exception as e: logger.warning('Catch exception: %s', e) return BooleanWrappedData(False, { 'errors': ['PLATFORM_'], }) if res: return BooleanWrappedData(True) else: return BooleanWrappedData(False, { 'errors': ['PLATFORM_'], })
def like(self, message): ''' Like method * Weibo doesn't provide an API for "like" * So "favourite" function supersedes "like" * Here "like" means "add to my favourites" * Receive a message ''' mID = message.ID try: ret = self.weibo_request('favorites/create', 'POST', {'id': mID.id}) # error_code 20704 means this status had been collected. # For the purpose of backward compatibility, we also view # it as a successful like if 'favorited_time' in ret or ret["error_code"] == 20704: message.parsed.liked = True return True else: logger.warning("'%s' likes status '%s' fail. ret: %s", self.jsonconf.channel_name, mID, ret) return False except Exception, e: logger.warning("Exception: %s. '%s' like status '%s' fail. ret: %s", e, self.jsonconf.channel_name, mID, ret) return False
def _forward(self, mID, text): ''' Raw forward method * Only support Renren message * Use 'text' as exact comment sequence ''' try: api_params = { 'method': 'status.forward', 'status': text, 'forward_owner': mID.source_user_id, 'place_id': 'RRAF04D95FA37892FFA88', 'forward_id': mID.status_id } ret = self.renren_request(api_params) if 'id' in ret: # ret['id'] is the ID of new status # X, their doc says the field name is 'result'... return True else: logger.warning( "'%s' forward status '%s' with comment '%s' fail. ret: %s", self.jsonconf.channel_name, mID, text, ret) return False except Exception as e: logger.warning( "'%s' forward status '%s' with comment '%s' fail: %s", self.jsonconf.channel_name, mID, text, e) return False
def update(self, text, pic=None): '''update a status * parameter text: the update message * return: success or not ''' text = self._cat(self.jsonconf['text_length_limit'], [(text, 1)]) if not pic: method = "t/add" else: method = "t/add_pic" try: if pic: ret = self.tencent_request(method, "POST", content=text, files={'pic': ('pic.jpg', pic)}) else: ret = self.tencent_request(method, "POST", content=text) if (ret['msg'] == "ok"): logger.info("Update status '%s' on '%s' succeed", text, self.jsonconf.channel_name) return True else: return ret except Exception, e: logger.warning("Catch Exception: %s", e) return False
def get(self, attr, default_value = "(null)"): ''' dict entry reading with fault tolerance. :attr: A str or a list of str. If attr is a list, we will try all the candidates until one 'get' is successful. If none of the candidates succeed, we will return a "(null)" e.g. RSS format is very diverse. To my current knowledge, some formats have 'author' fields, but others do not: * rss : no * rss2 : yes * atom : yes * rdf : yes This function will return a string "(null)" by default if the field does not exist. The purpose is to expose unified interface to upper layers. seeing "(null)" is better than catching an error. ''' if isinstance(attr, str): return dict.get(self, attr, default_value) elif isinstance(attr, list): for a in attr: val = dict.get(self, a, None) if val: return val return default_value else: logger.warning("Unkown type: %s", type(attr)) return default_value
def update(self, text, pic=None): '''update a status * parameter text: the update message * return: success or not ''' text = self._cat(self.jsonconf['text_length_limit'], [(text, 1)]) if not pic: method = "t/add" else: method = "t/add_pic" try: if pic: ret = self.tencent_request(method, "POST", content=text, files={'pic': ('pic.jpg', pic)}) else: ret = self.tencent_request(method, "POST", content=text) if(ret['msg'] == "ok"): logger.info("Update status '%s' on '%s' succeed", text, self.jsonconf.channel_name) return True else: return ret except Exception, e: logger.warning("Catch Exception: %s", e) return False
def unlike(self, message): res = None flag = False try: # The order in the bracket is important since there # exists "SHARE_XXXX" type. In order to figure out # the actual type, SHARE must be put in the first position. for msg_type in ["SHARE", "BLOG", "PHOTO", "ALBUM", "STATUS", "VIDEO"]: if msg_type in message.ID.feed_type: flag = True break if flag: res = self.renren_request( method="like/ugc/remove", ugcOwnerId=message.ID.source_user_id, likeUGCType="TYPE_" + msg_type, ugcId=message.ID.resource_id ) else: return False except Exception as e: logger.warning('Catch exception: %s', type(e)) return False if res: return True else: return False
def _forward(self, mID, text): ''' Raw forward method * Only support Renren message * Use 'text' as exact comment sequence ''' try: api_params = {'method': 'status.forward', 'status': text, 'forward_owner': mID.source_user_id, 'place_id': 'RRAF04D95FA37892FFA88', 'forward_id': mID.status_id } ret = self.renren_request(api_params) if 'id' in ret: # ret['id'] is the ID of new status # X, their doc says the field name is 'result'... return True else: logger.warning("'%s' forward status '%s' with comment '%s' fail. ret: %s", self.jsonconf.channel_name, mID, text, ret) return False except Exception as e: logger.warning("'%s' forward status '%s' with comment '%s' fail: %s", self.jsonconf.channel_name, mID, text, e) return False
def update(self, text, pic=None): '''update a status * parameter text: the update message * return: success or not ''' # NOTE: # * With this pre-shortening, we can post potentially longer messages. # * It consumes one more API quota. text = self._replace_with_short_url(text) text = self._cat(self.jsonconf['text_length_limit'], [(text, 1)], delim='//') try: if not pic: ret = self.weibo_request('statuses/update', 'POST', {'status': text}) else: ret = self.weibo_request( 'statuses/upload', 'POST', {'status': text}, files={'pic': ('pic.jpg', pic)} ) self.Message(ret) logger.info("Update status '%s' on '%s' succeed", text, self.jsonconf.channel_name) return True except Exception as e: logger.warning("Update status fail. Message: %s", e) return False
def update(self, text, pic=None): '''update a status * parameter text: the update message * return: success or not ''' # NOTE: # * With this pre-shortening, we can post potentially longer messages. # * It consumes one more API quota. text = self._replace_with_short_url(text) text = self._cat(self.jsonconf['text_length_limit'], [(text, 1)], delim='//') try: if not pic: ret = self.weibo_request('statuses/update', 'POST', {'status': text}) else: ret = self.weibo_request('statuses/upload', 'POST', {'status': text}, files={'pic': ('pic.jpg', pic)}) self.Message(ret) logger.info("Update status '%s' on '%s' succeed", text, self.jsonconf.channel_name) return True except Exception as e: logger.warning("Update status fail. Message: %s", e) return False
def append(self, e): if isinstance(e, Message): if hasattr(e, 'deleted') and e.deleted: logger.debug("Trying to append Deleted Message type element. Ignored") else: super(MessageList, self).append(e) else: logger.debug("Trying to append non- Message type element. Ignored")
def _parse(self, dct): if 'deleted' in dct and dct['deleted']: logger.debug( "This is a deleted message %s of SinaWeiboStatusMessage", dct["id"]) self.parsed.time = "unknown" self.parsed.username = "******" self.parsed.userid = "unknown" self.parsed.text = "unknown" self.deleted = True return self.ID.id = dct["id"] self.parsed.time = utils.str2utc(dct["created_at"]) self.parsed.username = dct['user']['name'] self.parsed.userid = dct['user']['id'] self.parsed.reposts_count = dct['reposts_count'] self.parsed.comments_count = dct['comments_count'] if 'pic_urls' in dct: for pic in dct['pic_urls']: self.parsed.attachments.append({ 'type': 'picture', 'format': ['link'], 'data': pic['thumbnail_pic'].replace('/thumbnail/', '/woriginal/') }) if 'retweeted_status' in dct: self.parsed.username_orig = "unknown" if 'pic_urls' in dct['retweeted_status']: for pic in dct['retweeted_status']['pic_urls']: self.parsed.attachments.append({ 'type': 'picture', 'format': ['link'], 'data': pic['thumbnail_pic'].replace('/thumbnail/', '/woriginal/') }) try: self.parsed.username_orig = dct['retweeted_status']['user'][ 'name'] except KeyError: logger.warning( 'KeyError when parsing SinaWeiboStatus. May be deleted original message' ) self.parsed.text_orig = dct['retweeted_status']['text'] self.parsed.text_trace = dct['text'] self.parsed.text = self.parsed.text_trace \ + "//@" + self.parsed.username_orig \ + ": " + self.parsed.text_orig else: self.parsed.text_orig = dct['text'] self.parsed.text_trace = None self.parsed.text = self.parsed.text_orig
def _parse(self, dct): if 'deleted' in dct and dct['deleted']: logger.debug( "This is a deleted message %s of SinaWeiboStatusMessage", dct["id"]) self.parsed.time = "unknown" self.parsed.username = "******" self.parsed.userid = "unknown" self.parsed.text = "unknown" self.deleted = True return self.ID.id = dct["id"] self.parsed.time = utils.str2utc(dct["created_at"]) self.parsed.username = dct['user']['name'] self.parsed.userid = dct['user']['id'] self.parsed.reposts_count = dct['reposts_count'] self.parsed.comments_count = dct['comments_count'] if 'pic_urls' in dct: for pic in dct['pic_urls']: self.parsed.attachments.append({ 'type': 'picture', 'format': ['link'], 'data': pic['thumbnail_pic'].replace('/thumbnail/', '/woriginal/') }) if 'retweeted_status' in dct: self.parsed.username_orig = "unknown" if 'pic_urls' in dct['retweeted_status']: for pic in dct['retweeted_status']['pic_urls']: self.parsed.attachments.append({ 'type': 'picture', 'format': ['link'], 'data': pic['thumbnail_pic'].replace('/thumbnail/', '/woriginal/') }) try: self.parsed.username_orig = dct['retweeted_status']['user'][ 'name'] except KeyError: logger.warning( 'KeyError when parsing SinaWeiboStatus. May be deleted original message' ) self.parsed.text_orig = dct['retweeted_status']['text'] self.parsed.text_trace = dct['text'] self.parsed.text = self.parsed.text_trace \ + " || " + "@" + self.parsed.username_orig \ + " : " + self.parsed.text_orig else: self.parsed.text_orig = dct['text'] self.parsed.text_trace = None self.parsed.text = self.parsed.text_orig
def new_channel(self, pl=None, **kwarg): if pl: try: return getattr(platform, pl).new_channel(**kwarg) except AttributeError: logger.warning("can not find platform '%s'", pl) return utils.JsonDict() else: return utils.JsonDict(json.load(open(abspath("conf/init-channel.json.example"), "r")))
def home_timeline(self, count=20): try: jsonlist = self.instagram_request(resource="users/self/feed", method="get", count=count) except Exception, e: logger.warning("InstagramAPIError, %s", e) return snstype.MessageList()
def __init_oauth2_client(self): if self.auth_client == None: try: self.auth_client = oauth.APIClient(self.jsonconf.app_key, \ self.jsonconf.app_secret, self.auth_info.callback_url, \ auth_url = self.auth_info.auth_url) except: logger.critical("auth_client init error") raise snserror.auth
def unlike(self, message): try: jsonlist = self.instagram_request(resource="media/" + message.ID.id + "/likes", method="delete") return True except Exception, e: logger.warning("InstagramAPIError, %s", e) return False
def auth(self): if self.get_saved_token(): return self.is_authed() if self.jsonconf['auth_by'] == 'gsid': self.token['gsid'] = self.jsonconf['gsid'] elif self.jsonconf['auth_by'] == 'userpass': show_verification = False verification_code = '' req = urllib2.Request('http://login.weibo.cn/login/?vt=4&revalid=2&ns=1&pt=1') req = self._process_req(req) response = urllib2.urlopen(req, timeout = 10) p = response.read() while True: req = urllib2.Request('http://login.weibo.cn/login/?rand=' + (re.search("rand=([0-9]*)", p).group(1) )+ '&backURL=http%3A%2F%2Fweibo.cn&backTitle=%E6%89%8B%E6%9C%BA%E6%96%B0%E6%B5%AA%E7%BD%91&vt=4&revalid=2&ns=1') data = {'mobile': self.auth_info['login_username'], 'password_%s' % (re.search('name="password_([0-9]*)"', p).group(1)): self.auth_info['login_password'], 'backURL': 'http%3A%2F%2Fweibo.cn', 'backTitle': '手机新浪网', 'tryCount': '', 'vk': re.search('name="vk" value="([^"]*)"', p).group(1), 'submit' : '登录'} if show_verification: data['code'] = verification_code data['capId'] = re.search('name="capId" value="([^"]*)"', p).group(1) show_verification = False req = self._process_req(req) data = urllib.urlencode(data) response = urllib2.urlopen(req, data, timeout = 10) p = response.read() final_url = response.geturl() if 'newlogin' in final_url: final_gsid = re.search('g=([^&]*)', final_url).group(1) self.token = {'gsid' : final_gsid} break elif '验证码' in p: err_msg = re.search('class="me">([^>]*)<', p).group(1) if '请输入图片中的字符' in p: captcha_url = re.search(r'"([^"]*captcha[^"]*)', p).group(1) show_verification = True import Image import StringIO ss = urllib2.urlopen(captcha_url, timeout=10).read() sss = StringIO.StringIO(ss) img = Image.open(sss) img.show() verification_code = raw_input(err_msg) else: err_msg = re.search('class="me">([^>]*)<', p).group(1) logger.warning(err_msg) break else: return False res = self.is_authed() if res: self.save_token() return res
def _get_weibo(self, page = 1): #FIXME: 获取转发和评论数应该修改为分析DOM而不是正则表达式(以免与内容重复) #FIXME: 对于转发的微博,原微博信息不足 req = urllib2.Request('http://weibo.cn/?gsid=' + self.token['gsid'] + '&page=%d' % (page)) req = self._process_req(req) m = urllib2.urlopen(req, timeout = 10).read() h = lxml.html.fromstring(m) weibos = [] for i in h.find_class('c'): try: if i.get('id') and i.get('id')[0:2] == 'M_': weibo = None if i.find_class('cmt'): # 转发微博 weibo = { 'uid' : self._get_uid_by_pageurl(i.find_class('nk')[0].attrib['href'], self.jsonconf['uidtype']), 'author' : i.find_class('nk')[0].text, 'id': i.get('id')[2:], 'time': i.find_class('ct')[0].text.encode('utf-8').strip(' ').split(' ')[0].decode('utf-8'), 'text' : None, 'orig' : { 'text': unicode(i.find_class('ctt')[0].text_content()), 'author': re.search(u'转发了\xa0(.*)\xa0的微博', i.find_class('cmt')[0].text_content()).group(1), 'comments_count' : 0, 'reposts_count' : 0 }, 'comments_count' : 0, 'reposts_count' : 0 } parent = i.find_class('cmt')[-1].getparent() retweet_reason = re.sub(r'转发理由:(.*)赞\[[0-9]*\] 转发\[[0-9]*\] 评论\[[0-9]*\] 收藏.*$', r'\1', parent.text_content().encode('utf-8')) weibo['text'] = retweet_reason.decode('utf-8') zf = re.search(r'赞\[([0-9]*)\] 转发\[([0-9]*)\] 评论\[([0-9]*)\]', parent.text_content().encode('utf-8')) if zf: weibo['comments_count'] = int(zf.group(3)) weibo['reposts_count'] = int(zf.group(2)) zf = re.search(r'赞\[([0-9]*)\] 原文转发\[([0-9]*)\] 原文评论\[([0-9]*)\]', i.text_content().encode('utf-8')) if zf: weibo['orig']['comments_count'] = int(zf.group(3)) weibo['orig']['reposts_count'] = int(zf.group(2)) else: weibo = {'author' : i.find_class('nk')[0].text, 'uid' : self._get_uid_by_pageurl(i.find_class('nk')[0].attrib['href'], self.jsonconf['uidtype']), 'text': i.find_class('ctt')[0].text_content()[1:], 'id': i.get('id')[2:], 'time': i.find_class('ct')[0].text.encode('utf-8').strip(' ').split(' ')[0].decode('utf-8') } zf = re.search(r'赞\[([0-9]*)\] 转发\[([0-9]*)\] 评论\[([0-9]*)\]', i.text_content().encode('utf-8')) if zf: weibo['comments_count'] = int(zf.group(3)) weibo['reposts_count'] = int(zf.group(2)) if i.find_class('ib'): #FIXME: Still not able to process a collections of pictures weibo['attachment_img'] = i.find_class('ib')[0].get('src').replace('wap128', 'woriginal') weibos.append(weibo) except Exception, e: logger.warning("Catch exception: %s" % (str(e)))
def new_channel(self, pl = None, **kwarg): if pl: try: return getattr(platform, pl).new_channel(**kwarg) except AttributeError: logger.warning("can not find platform '%s'", pl) return utils.JsonDict() else: _fn_conf = path.join(SNSConf._SNSAPI_DIR_STATIC_DATA, 'init-channel.json.example') return utils.JsonDict(json.load(open(_fn_conf)))
def unlike(self, message): try: jsonlist = self.instagram_request( resource="media/" + message.ID.id + "/likes", method="delete" ) return True except Exception, e: logger.warning("InstagramAPIError, %s", e) return False
def _parse(self, dct): if 'deleted' in dct and dct['deleted']: logger.debug("This is a deleted message %s of SinaWeiboStatusMessage", dct["id"]) self.parsed.time = "unknown" self.parsed.username = "******" self.parsed.userid = "unknown" self.parsed.text = "unknown" self.deleted = True return self.ID.id = dct["id"] self.parsed.time = utils.str2utc(dct["created_at"]) self.parsed.username = dct['user']['name'] self.parsed.userid = dct['user']['id'] self.parsed.reposts_count = dct['reposts_count'] self.parsed.comments_count = dct['comments_count'] # accordian to http://open.weibo.com/qa/index.php?qa=448&qa_1=v2-%E5%B7%B2%E6%94%B6%E8%97%8F%E5%BE%AE%E5%8D%9A-%E6%8E%A5%E5%8F%A3statuses-friends-timeline%E8%BF%94%E5%9B%9E%E5%AD%97%E6%AE%B5-favorited-%E4%B8%BAfalse # Currently we have no way to tell whether # a weibo message is favorited Although there's a # specious property self.parsed.liked = False if 'pic_urls' in dct: for pic in dct['pic_urls']: self.parsed.attachments.append( { 'type': 'picture', 'format': ['link'], 'data': pic['thumbnail_pic'].replace('/thumbnail/', '/woriginal/') }) if 'retweeted_status' in dct: self.parsed.username_orig = "unknown" if 'pic_urls' in dct['retweeted_status']: for pic in dct['retweeted_status']['pic_urls']: self.parsed.attachments.append( { 'type': 'picture', 'format': ['link'], 'data': pic['thumbnail_pic'].replace('/thumbnail/', '/woriginal/') }) try: self.parsed.username_orig = dct['retweeted_status']['user']['name'] except KeyError: logger.warning('KeyError when parsing SinaWeiboStatus. May be deleted original message') self.parsed.text_orig = dct['retweeted_status']['text'] self.parsed.text_trace = dct['text'] self.parsed.text = self.parsed.text_trace \ + "//@" + self.parsed.username_orig \ + ": " + self.parsed.text_orig else: self.parsed.text_orig = dct['text'] self.parsed.text_trace = None self.parsed.text = self.parsed.text_orig
def new_channel(self, pl=None, **kwarg): if pl: try: return getattr(platform, pl).new_channel(**kwarg) except AttributeError: logger.warning("can not find platform '%s'", pl) return utils.JsonDict() else: _fn_conf = path.join(SNSConf._SNSAPI_DIR_STATIC_DATA, 'init-channel.json.example') return utils.JsonDict(json.load(open(_fn_conf)))
def _http_post(self, baseurl, params): try: for p in params: params[p] = self._unicode_encode(params[p]) data = urllib.urlencode(params) resp = urllib.urlopen(baseurl,data) json_objs = json.loads(resp.read()) return json_objs except Exception, e: logger.warning("_http_post fail: %s", e) return {}
def home_timeline(self, count=20): try: jsonlist = self.instagram_request( resource="users/self/feed", method="get", count=count ) except Exception, e: logger.warning("InstagramAPIError, %s", e) return snstype.MessageList()
def _get_user_status_list(self, count, userid, username): try: jsonlist = self.renren_request( method="status.gets", page=1, count=count, uid = userid, ) except RenrenAPIError, e: logger.warning("RenrenAPIError, %s", e) return snstype.MessageList()
def new_channel(self, pl=None, **argd): if pl: try: return getattr(platform, pl).new_channel(**argd) except AttributeError: logger.warning("can not find platform '%s'", pl) return utils.JsonDict() else: return utils.JsonDict( json.load(open(abspath('conf/init-channel.json.example'), 'r')))
def _get_user_status_list(self, count, userid, username): try: jsonlist = self.renren_request( method="status/list", pageNumberint=1, pageSize=count, ownerId=userid, ) except RenrenAPIError, e: logger.warning("RenrenAPIError, %s", e) return snstype.MessageList()
def extend(self, l): if isinstance(l, MessageList): super(MessageList, self).extend(l) elif isinstance(l, list): # We still extend the list if the user asks to. # However, a warning will be placed. Doing this # may violate some properties of MessageList, e.g. # there is no Deleted Message in the list. super(MessageList, self).extend(l) logger.warning("Extend MessageList with non MessageList list.") else: logger.warning("Extend MessageList with unknown type.")
def reply(self, statusID, text): try: result = self.instagram_request(resource="media/" + statusID.id + "/comments", method="post", text=text) # TODO: # Find better indicator for status update success return True except Exception, e: logger.warning('update Instagram failed: %s', str(e)) return False
def oauth2(self): ''' Authorizing using synchronized invocation of OAuth2. Users need to collect the code in the browser's address bar to this client. callback_url MUST be the same one you set when you apply for an app in openSNS platform. ''' logger.info("Try to authenticate '%s' using OAuth2", self.jsonconf.channel_name) self._oauth2_first() self._oauth2_second()
def callback_and_sleep(self, value): if self.callback: try: self.callback(value) except Exception as e: logger.warning("Error while executing callback %s" % (str(e))) if self.started: for i in range(self.sleepsec): time.sleep(1) if not self.started: break if self.started: self._start()