Python分享消息到Twitter、Youtube、Facebook平台

Python分享消息到Twitter、Youtube、Facebook平台

浏览器

概述

第三方登录平台免不了需要登录验证,比起命令行输入账号密码再填充表单,不如直接用浏览器实在

环境配置

运行库
pip install PyQt5
pip install PyQt5-tools
代码
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebKit import *
from PyQt5.QtWebKitWidgets import *
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow

class webForm():
    def __init__(self):
        self.app = QApplication(sys.argv)
        self.form = QWidget()
        self._debug = False

        self.webview = QWebView()
        self.webview.page().mainFrame().urlChanged.connect(self._urlChanged)

        vbox = QVBoxLayout()
        vbox.addWidget(self.webview)
        main = QGridLayout()
        main.setSpacing(0)
        main.addLayout(vbox, 0, 0)
        self.form.setLayout(main)

        self.callbackFunc = None

    def show(self, url, title, debug=False):
        """ 打开内嵌浏览器(在浏览器窗口关闭前,主线程将被挂起)
        url: 目标链接
        title: 窗口标题
        debug: 是否在控制台打印出每次url跳转及参数
        """
        self._debug = debug
        self.form.setWindowTitle(title)
        self.form.show()
        self.webview.load(QUrl(url))
        self.app.exec_()

    def close(self):
        self.form.close()


    def __del__(self):
        self.close()

    def set_callback(self, callbackFunc):
        """ callbackFunc(QUrl) """
        self.callbackFunc = callbackFunc


    def _loadFinished(self,bool):
        if bool != True:
            return
        url = self.webview.url()
        if self.callbackFunc != None:
            self.callbackFunc(url)

    def _urlChanged(self, url):
        ##debug#############
        if self._debug == True:
            query = QUrlQuery(url.query())
            items = query.queryItems()

            logging.info("--------------------------------------")
            logging.info("[url]: " + url.toString())
            logging.info("[host]: " + url.host())
            #print(" query: " + query.toString())
            for i in items:
                logging.info("    " + i[0] + " : " + i[1])
        #####################

        if self.callbackFunc != None:
            self.callbackFunc(url)
        pass

Twitter

概述

使用tweepy进行登录验证拿到access_token后,可以自由发布文字、图片。

  • 需要登录验证
  • 需要第三方库:tweepy
  • 需要建立开发者应用
  • 可以发布纯文字推、带图推及
  • 视频上传功能在当前版本tweepy(3.6.0)有bug,在github上已经被修复,但还没有发布到新版本

相关链接

  • twitter 开发者后台 https://dev.twitter.com/apps
  • twitter 授权过程 https://blog.csdn.net/yangjian8915/article/details/11816669
  • twitter API索引 https://developer.twitter.com/en/docs/api-reference-index
  • tweepy github https://github.com/tweepy/tweepy

环境配置

开发者后台
  1. 打开https://apps.twitter.com/ 新建应用
  2. 依次输入相关信息。其中:Callback URLs必须是可访问的地址
  3. 进入应用,点开Keys and Access Tokens
  4. 得到Consumer Key和Consumer Secret
运行库

pip install tweepy

代码
import tweepy
import logging

class Twitter():
    def __init__(self, consumer_key, consumer_secret, redirect_uri):
        """ 需要提供应用密钥和回调地址
        参数获取链接:https://dev.twitter.com/apps
        redirect_uri必须填写一个可以访问的网址
        """
        self._consumer_key = consumer_key
        self._consumer_secret = consumer_secret
        self._redirect_uri = redirect_uri
        self._access_token = ""
        self._access_token_secret = ""
        self.is_access = False

    def access(self):
        """ 获取授权
        return True is success
        """

        flag = False
        self.is_access = False
        self.auth = tweepy.OAuthHandler(self._consumer_key, self._consumer_secret)

        logging.info("请求授权URL")
        try:
            url = self.auth.get_authorization_url(False,'HMAC-SHA1')
            logging.info("请求授权URL-成功")
        except Exception as e:
            logging.error("请求授权URL-失败")
            return flag

        logging.info("进行授权验证")
        self._form = webForm()
        self._form.set_callback(self.webview_callback)
        self._form.show(url, "分享到Twitter", True)

        if self.is_access == True:
            flag = True

        return flag

    def webview_callback(self, url):
        if QUrl(self._redirect_uri).host() == url.host():
            query = QUrlQuery(url.query())
            items = query.queryItems()
            if self._get_access_token(items) == True:
                self._form.close()


    def is_access(self):
        return self.is_access

    def _get_access_token(self, list):
        """ 获取授权token
        return True is success
        """
        for i in list:
            if i[0] == 'oauth_verifier':
                try:
                    self._access_token, self._access_token_secret = self.auth.get_access_token(i[1])
                    self.api = tweepy.API(self.auth)
                    self._client_id = self.api.me().id
                    self.is_access = True

                    logging.info("请求授权 成功")
                    logging.info("用户名: " + self.api.me().name)
                    #logging.info("access_token: " + self._access_token)
                    #logging.info("access_token_secret: " + self._access_token_secret)
                    return True

                except Exception as e:
                    self.is_access = False
                    logging.error("请求授 权失败 code:%d\n msg:%s",e.args)
                    #raise e
        return False

    def post_tweet(self, text):
        """ 发布tweet
        不要连续发两条一样的推,不然会遇到错误
        {'code': 187, 'message': 'Status is a duplicate.'}

        return True is success
        """
        if self.is_access == False:
            logging.info("没有获取授权!")
            return False

        if text == "":
            logging.info("tweet文不能为空!")
            return False

        try:
            self.api.update_status(text)
            logging.info("发布tweet 成功")
        except Exception as e:
            logging.error("发布tweet 失败: ",e.args)
            return False

        return True

    def post_tweet_with_media(self,text,filenames):
        """ 发布带媒体的tweet
        text = "hello world"
        filenames = ['C:\\1.png', 'C:\\2.png', ...]

        return True is success
        """


        if self.is_access == False:
            logging.info("没有获取授权!")
            return False

        try:
            # upload images and get media_ids
            media_ids = []
            for filename in filenames:
                 res = self.api.media_upload(filename)
                 media_ids.append(res.media_id)

            # tweet with multiple images
            self.api.update_status(status=text, media_ids=media_ids)
            logging.info("发布带图tweet 成功")
        except Exception as e:
            logging.error("发布带图tweet 失败: ",e.args)
            return False

    def get_last_tweet(self):
        """ 获取最新一条tweet
        return NOT "" is success
        """

        text = ""
        if self.is_access == False:
            logging.info("没有获取授权!")
        else:
            try:
                tweet = self.api.user_timeline(id = self._client_id, count = 1)[0]
                logging.info("获取tweet 成功")
                text = tweet.text
            except Exception as e:
                logging.error("获取tweet 失败: ",e.args)
        return text
测试代码

if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO)

    tw = Twitter("Consumer Key","Consumer Secret","https://www.baidu.com")
    if tw.access() == True:
        print("验证成功")
        import random
        text = "Hello World " + str(random.random())
        tw.post_tweet(text)

        #filenames = ['C:\\1.png', 'C:\\2.png']
        filenames = ['output.mp4']
        if tw.post_tweet_with_media(text,filenames) == True:
            print("分享成功")
    else:
        print("分享失败")

Youtube

概述

Youtube 上只能分享视频。Youtube API 使用Google开发者后台,所以需要先与Google对接。

  • 需要登录验证
  • 只能分享视频
  • 需要建立开发者应用
  • Youtube使用Google体系,需要通过google验证
  • 需要真实有效,并且通过google所有权验证的回调地址
  • 需要多个第三方库
  • 需要凭据文件

相关链接

  • Google API Console https://console.developers.google.com/apis
  • Search Console https://www.google.com/webmasters/tools/home?hl=zh-CN
  • YoutubeScope https://developers.google.com/youtube/v3/guides/auth/client-side-web-apps
  • API索引 https://developers.google.com/youtube/v3/docs/
  • python samples https://developers.google.com/youtube/v3/code_samples/python

环境配置

开发者后台
  1. 打开Google API Console https://console.developers.google.com/apis
  2. 新建项目
  3. 点开菜单,依次点击API和服务→信息中心→启用API和服务
  4. 搜索YouTube Data API v3并启用
  5. 点开菜单,依次点击凭据→OAuth同意屏幕,填写相关资料并保存
  6. 打开Search Console https://www.google.com/webmasters/tools/home?hl=zh-CN
  7. 输入回调网址,点击添加属性。按照要求验证所填网址
  8. 回到Google API Console,点击网域验证→添加网域,填入刚才验证通过的网址
  9. 点击凭据→创建凭据→OAuth客户端ID,选择网页客户端,填写相关资料并保存
  10. 下载client_secret.json凭据文件
运行库
pip install --upgrade google-api-python-client
pip install --upgrade google-auth google-auth-oauthlib google-auth-httplib2
pip install oauth2client
pip install apiclient
pip install httplib2
代码
import logging
import time

import httplib2
import oauth2client.client
import oauth2client.file
import oauth2client.tools
import googleapiclient.discovery
import googleapiclient.errors
import googleapiclient.http

class Youtube():
    def __init__(self, client_secret_path, redirect_uri):
        """  需要提供凭据文件和回调地址
        1.在Google API Console新建应用 (https://console.developers.google.com/apis)
        2.生成Oauth凭据
        3.新建网页客户端
        4.填写登录回调地址redirect_uri,地址必须在 Search Console中认证通过 (https://www.google.com/webmasters/tools)
        5.到凭据页面下载网页客户端的凭据client_secret.json (可以考虑把凭据文件放到服务器上)
        """
        self._client_secret_file = client_secret_path
        self._callback_url = "https://raw.githubusercontent.com/aa13058219642/facebook-callback/master"

        #请求权限 (其他权限详见
        #https://developers.google.com/youtube/v3/guides/auth/client-side-web-apps)
        self._scopes = ['https://www.googleapis.com/auth/youtube','https://www.googleapis.com/auth/youtube.upload']

        self._access_token = ""
        self.is_access = False

    def access(self):
        """ 获取授权 
        return True is success
        """

        state = False
        self.is_access = False

        self.flow = oauth2client.client.flow_from_clientsecrets(self._client_secret_file,
                self._scopes,redirect_uri=self._callback_url,
                prompt='consent')

        url = self._get_authorize_url()
        if url != None:
            logging.info("进行Google授权验证")
            self._form = webForm()
            self._form.set_callback(self.webview_callback)
            self._form.show(url,"分享到Youtube")

        if self.is_access == True:
            state = True

        return state

    def _get_authorize_url(self):
        """ 请求授权URL
        return NOT None success
        """
        url = None
        try:
            logging.info("请求授权URL")
            url = self.flow.step1_get_authorize_url()
        except Exception as e:
            logging.error("请求授权URL-失败")
            url = None
        return url

    def _get_access_token(self, list):
        """ 获取授权token
        return True is success
        """

        state = False
        for i in list:
            if i[0] == 'code':
                try:
                    credentials = self.flow.step2_exchange(i[1])

                    #保存授权文件
                    #storage = oauth2client.file.Storage('credentials.json')
                    #storage.put(credentials)

                    http = httplib2.Http()
                    http = credentials.authorize(http)
                    self._youtube = googleapiclient.discovery.build("youtube","v3",http = http,cache_discovery=False)
                    self.is_access = True

                    logging.info("请求授权 成功")
                    #logging.info("用户名: " + self.api.me().name)
                    #logging.info("access_token: " + self._access_token)
                    #logging.info("access_token_secret: " + self._access_token_secret)
                    state = True
                except Exception as e:
                    self.is_access = False
                    logging.error("请求授 权失败 code:%d\n msg:%s",e.args)
            elif i[0] == "error":
                logging.info("请求授权 失败")
                for j in list:
                    logging.info(j[0] + ": " + j[1])
            break
        return state

    def webview_callback(self, url):
        if QUrl(self._callback_url).host() == url.host():
            query = QUrlQuery(url.query())
            items = query.queryItems()
            if self._get_access_token(items) == True:
                self.is_access = True
            else:
                self.is_access = False
            self._form.close()
        pass

    def post(self,text):
        print("post")

    def upload(self, filename, title, description='', category='22', keywords='', privacyStatus='public'):
        """ 上传视频
        filename: 文件名及路径
        title: 视频标题
        description: 视频描述
        category: 视频类别ID(id列表: https://gist.github.com/dgp/1b24bf2961521bd75d6c)
        keywords: 关键字 (以英文逗号分隔)
        privacyStatus: 隐私权限 ('public', 'private', 'unlisted')
        """
        if self.is_access == False:
            logging.info("没有获取授权!")
            return False

        tags = None
        if keywords:
            tags = keywords.split(',')

        body = dict(snippet=dict(title=title,
                description=description,
                tags=tags,
                categoryId=category),
            status=dict(privacyStatus=privacyStatus))

        # Call the API's videos.insert method to create and upload the video.
        insert_request = self._youtube.videos().insert(part=','.join(body.keys()),
            body=body,
            # The chunksize parameter specifies the size of each chunk of data,
            # in bytes, that will be uploaded at a time.  Set a higher value for
            # reliable connections as fewer chunks lead to faster uploads.  
            # Set a lower value for better recovery on less reliable connections.
            #
            # Setting 'chunksize' equal to -1 in the code below means that the entire
            # file will be uploaded in a single HTTP request.  (If the upload fails,
            # it will still be retried where it left off.) This is usually a best
            # practice, but if you're using Python older than 2.6 or if you're
            # running on App Engine, you should set the chunksize to something
            # like 1024 * 1024 (1 megabyte).
            media_body=googleapiclient.http.MediaFileUpload(filename, chunksize=-1, resumable=True))

        # This method implements an exponential backoff strategy to resume a
        # failed upload.
        response = None
        error = None
        retry = 0
        while response is None:
            try:
                logging.info('Uploading file...')
                status, response = insert_request.next_chunk()
                if response is not None:
                    if 'id' in response:
                        logging.info('Video id "%s" was successfully uploaded.' % response['id'])
                    else:
                        logging.info('The upload failed with an unexpected response: %s' % response)
            except Exception as e:
                error = 'A retriable error occurred: %s' % e

            if error is not None:
                logging.info(error)
                retry += 1
                if retry > MAX_RETRIES:
                    logging.info('No longer attempting to retry.')

                max_sleep = 2 ** retry
                sleep_seconds = random.random() * max_sleep
                logging.info('Sleeping %f seconds and then retrying...' % sleep_seconds)
                time.sleep(sleep_seconds)
        return True
测试代码
if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO)

    youtu = Youtube('client_secret.json',"https://www.example.com")
    if youtu.access() == True:
        print("验证成功\n开始上传视频")

        video = "output.mp4"
        title = "Hello World"
        if youtu.upload(video,title)==True:
            print("分享成功")
    else:
        print("分享失败")

Facebook

概述

Facebook停用了public_actions权限以后,就不再支持登录后接管账户的操作了,要通过facebook分享内容只能通过额外提供的分享页面,该页面只能分享网址。不过可以通过在目标网址中添加mate标签来实现部分自定义内容。

  • 需要登录验证
  • 只能用户手动发布分享,不能自动执行
  • 只能分享链接,但可以部分自定义
  • 需要填写回调网址
  • 需要应用ID

相关链接

  • 开发者后台 https://developers.facebook.com/apps
  • Facebook 分享文档 https://developers.facebook.com/docs/sharing/web
  • 目标网站构建指南 https://developers.facebook.com/docs/sharing/webmasters#markup

环境配置

开发者后台
  1. 打开 https://developers.facebook.com/apps
  2. 新建APP,填写相关资料
  3. 在左边菜单点击添加产品→facebook登录
  4. 在左边菜单点击→facebook登录→设置,输入有效 OAuth 跳转 URI和取消授权的回调地址
  5. 在左边菜单点击设置→基本,填写应用域名及其他相关资料并保存
  6. 记下应用编号app_id
运行库

Facebook分享不需要第三方库

代码
import logging

class Facebook():
    def __init__(self, app_id, redirect_uri):
        """ 需要提供应用ID和回调地址
        app_id: 获取步骤详见 https://developers.facebook.com/
        redirect_uri: 必须是开发者应用中的“应用域名”属性里的子域名 (https://developers.facebook.com/apps/{{{{app_id}}}}/settings/basic/)
        """
        self._app_id = app_id
        #self._app_secret = ""
        self._redirect_uri = redirect_uri
        self.is_access = False

    def webview_callback(self, url):
        if QUrl(self._redirect_uri).host() == url.host():
            self.is_access = True
            return

    def post(self, link, hashtag=None, display=None):
        """打开发布动态窗口
        link: 要分享的目标网址(目标网站配置指南: https://developers.facebook.com/docs/sharing/webmasters#markup)
        hashtag: 话题标签(不需要带“#”号)
        display: 展示方式(详见 https://developers.facebook.com/docs/sharing/reference/share-dialog)
        """
        logging.info("登录验证")

        if display == None:
            display = "popup"

        tag = "" if hashtag == None else "&hashtag=%23" + hashtag

        url = ("https://www.facebook.com/dialog/feed?" + "app_id=" + self._app_id +  "&display=" + display + "&link=" + link + "&redirect_uri=" + self._redirect_uri + tag)

        self.is_access = False
        self._form = webForm()
        self._form.set_callback(self.webview_callback)
        self._form.show(url,"分享到facebook")

        return self.is_access

测试代码
if __name__ == '__main__':
    logging.basicConfig(level=logging.INFO)

    link = "https://www.google.com/"
    fb = Facebook("app_id","https://www.baidu.com/")
    if fb.post("https://www.google.com/","hellooo") == True:
        print("分享成功")
    else:
        print("分享失败")

你可能感兴趣的:(QT,python,python,twitter,youtube,facebook,pyqt5)