Publication de Python sur la chronologie Facebook

Publiez de python à vous-même ou à la chronologie sur votre page Facebook.

Malheureusement, Facebook n'a pas de mécanisme de webhook entrant, vous devez donc créer une application Facebook pour publier.

De plus, des jetons d'accès sont nécessaires pour faire fonctionner Facebook, mais il est difficile d'obtenir des jetons d'accès de CLI car Facebook nécessite une authentification OAuth (bien que ce ne soit pas impossible si vous analysez la réponse à l'aide d'un navigateur sans tête).

Donc, cette fois, je vais démarrer le serveur CGI avec python sur localhost et traiter le rappel OAuth avec CGI pour obtenir le jeton d'accès.

Je voulais pouvoir poster sur le groupe facebook, mais malheureusement j'ai abandonné cette fois car il semble que l'opérateur facebook doive approuver l'application facebook.

Environnement vérifié

version
OS Ubuntu 15.04 (3.19.0-26-generic)
Python 2.7.10
pip 7.1.2
requests 2.8.1
jinja2 2.8
facebook-sdk 0.4.0
facebook graph API 2.5

Code source

https://github.com/nmatsui/post_facebook_using_python

Créer une application facebook

Tout d'abord, créez une application Facebook.

1 Affichez «Ajouter une nouvelle application» depuis le portail des développeurs Facebook https://developers.facebook.com/ et sélectionnez «Site Web».

fb_python_01.png

2 Entrez le nom de l'application Facebook que vous souhaitez créer (cette fois ** python_publisher **) et appuyez sur "Créer un nouvel ID d'application Facebook"

fb_python_02.png

3 Sélectionnez une catégorie (cette fois ** Utility **) et appuyez sur "Create App ID"

fb_python_03.png

4 Entrez l'URL pour le rappel d'authentification avec OAuth (cette fois ** http: // localhost: 8000 / cgi-bin / get_token **) et appuyez sur "Suivant".

fb_python_04.png

5 Fin de la création de l'application facebook

fb_python_05.png

6 Affichez à nouveau la Première page du portail des développeurs et sélectionnez l'application créée dans "Mes applications".

Si vous ne voyez pas l'application que vous avez créée, rechargez le portail des développeurs

fb_python_06.png

7 Vérifier l'ID de l'application et le secret de l'application

Vous pouvez être invité à entrer un mot de passe lors de la vérification du secret de l'application

fb_python_07.png

Créer un fichier de configuration

Créez un fichier de paramètres qui décrit les informations de l'application Facebook créée et les informations de la page Facebook à publier. Pour la commodité du programme CGI, le nom du fichier de paramètres est défini comme ** conf.json **.

conf.json


{
  "app": {
    "app_id": "ID d'application de l'application facebook",
    "app_secret": "l'application facebook App Secret",
    "redirect_uri": "URL de rappel définie dans l'application Facebook"
  },
  "page": {
    "name": "Le nom de la page facebook à publier"
  }
}

Préparation environnementale

Maintenant que nous avons une application facebook, nous devons préparer un environnement python.

Installation de la bibliothèque

Créez requirements.txt au même emplacement que conf.json et installez les trois bibliothèques suivantes à l'aide de pip.

requirements.txt


requests
jinja2
facebook-sdk

Installer avec pip


$ pip install -r requirements.txt

Création d'un répertoire pour CGI

Placez le programme CGI dans le répertoire où se trouve conf.json ** Créez le répertoire cgi-bin ** et le répertoire jinja2 template ** templates **

Créer un répertoire


$ mkdir cgi-bin
$ mkdir templates

Créer un programme CGI

Cette fois, nous allons créer les deux CGI suivants

Privilèges accordés aux jetons d'accès

Cette fois, spécifiez les trois plages d'autorités suivantes. Voir Référence des autorisations - Connexion à Facebook pour plus de détails sur les autorisations qui peuvent être spécifiées.

Par défaut, le jeton d'accès reçoit les privilèges ** public_profile ** (autorisation d'acquérir un profil public), de sorte que le jeton d'accès acquis cette fois est autorisé à fonctionner dans ces quatre plages de privilèges.

index Générez une URL d'authentification OAuth pour l'application Facebook et affichez le lien dans votre navigateur.

CGI de génération d'URL d'authentification OAuth

** cgi-bin / index ** lit conf.json et génère une URL d'authentification OAuth au format suivant.

https://www.facebook.com/dialog/oauth?redirect_uri= <URL de rappel définie pour l'application Facebook & client_id = <ID d'application de l'application Facebook> & scope = <Autorité d'accorder l'approbation>

cgi-bin/index


#!/usr/bin/env python
# -*- coding: utf-8 -*-

import json
import urllib
from jinja2 import Environment, FileSystemLoader

CONF_FILE = 'conf.json'
BASE_URL = 'https://www.facebook.com/dialog/oauth'
SCOPE = 'manage_pages,publish_actions,publish_pages'
TPL_DIR = './templates'
TEMPLATE = 'index.tpl.html'


def create_url():
    with open(CONF_FILE, 'r') as f:
        conf = json.load(f)
    redirect_uri = urllib.quote_plus(conf['app']['redirect_uri'])
    url = BASE_URL + '?'
    url += 'redirect_uri=' + redirect_uri + '&'
    url += 'client_id=' + conf['app']['app_id'] + '&'
    url += 'scope=' + SCOPE
    return url


def main():
    params = {}
    try:
        url = create_url()
        params['isOK'] = True
        params['url'] = url
    except Exception as e:
        params['isOK'] = False
        params['error_type'] = type(e).__name__
        params['error_title'] = str(e)

    env = Environment(loader=FileSystemLoader(TPL_DIR, encoding='utf-8'))
    tpl = env.get_template(TEMPLATE)
    html = tpl.render(params)

    print('Content-type: text/html')
    print('\n')
    print(html.encode('utf-8'))

main()

Puisque l'URL de rappel ne peut pas être passée en tant que paramètre d'URL telle quelle, elle est échappée avec ʻurllib.quote_plus () `.

Modèle d'affichage d'URL d'authentification OAuth

** templates / index.tpl.html ** affiche l'URL générée sous forme de lien.

html+jinja:templates/index.tpl.html


<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>index</title>
  </head>
  <body>
  {% if isOK %}
    <a href="{{ url }}">get token</a>
  {% else %}
    <b>J'ai eu l'erreur suivante</b><br/>
    [{{ error_type }}] {{ error_title }}
  {% endif %}
  </body>
</html>

get_token Rappelé depuis la fonction d'authentification OAuth de Facebook et obtenir le code d'authentification. Obtenez le jeton d'accès suivant de l'API facebook à l'aide du code d'authentification et enregistrez-le en tant que fichier json.

Acquisition de jetons d'accès CGI

** cgi-bin / get_token ** obtient le jeton d'accès à la page de la page Facebook spécifiée comme jeton d'accès utilisateur en utilisant le code d'autorisation rappelé. Le jeton d'accès acquis est enregistré dans token.json.

cgi-bin/get_token


#!/usr/bin/env python
# -*- coding: utf-8 -*-

import cgi
import json
import re
import requests
from jinja2 import Environment, FileSystemLoader

CONF_FILE = 'conf.json'
TOKEN_FILE = 'token.json'
TOKEN_URL = 'https://graph.facebook.com/oauth/access_token'
ACCOUNT_URL = 'https://graph.facebook.com/me/accounts'
USER_ACCESS_TOKEN_PATTERN = r'access_token=([^&=]+)(&expires=\d+)?'
TPL_DIR = './templates'
TEMPLATE = 'get_token.tpl.html'


class TokenRetriever(object):

    def __init__(self, code):
        self.code = code
        with open(CONF_FILE, 'r') as f:
            self.conf = json.load(f)

    def get_token(self):
        user_access_token = self.__get_user_access_token()
        page_access_token = self.__get_page_access_token(user_access_token)
        token = {}
        token['user_access'] = user_access_token
        token['page_access'] = page_access_token
        token_json = json.dumps({'token': token}, indent=2, sort_keys=True)
        return token_json

    def __get_user_access_token(self):
        payload = {}
        payload['client_id'] = self.conf['app']['app_id']
        payload['client_secret'] = self.conf['app']['app_secret']
        payload['redirect_uri'] = self.conf['app']['redirect_uri']
        payload['code'] = self.code
        response = requests.get(TOKEN_URL, params=payload)
        m = re.match(USER_ACCESS_TOKEN_PATTERN, response.text)
        if m:
            return self.__exchange_token(m.group(1))
        else:
            raise LookupError('access_token does not exist')

    def __get_page_access_token(self, user_access_token):
        payload = {}
        payload['access_token'] = user_access_token
        response = requests.get(ACCOUNT_URL, params=payload)
        pages = filter(lambda p: p['name'] == self.conf['page']['name'],
                       json.loads(response.text)['data'])
        page_access_token = pages[0]['access_token']
        return self.__exchange_token(page_access_token)

    def __exchange_token(self, token):
        payload = {}
        payload['client_id'] = self.conf['app']['app_id']
        payload['client_secret'] = self.conf['app']['app_secret']
        payload['grant_type'] = 'fb_exchange_token'
        payload['fb_exchange_token'] = token
        response = requests.get(TOKEN_URL, params=payload)
        m = re.match(USER_ACCESS_TOKEN_PATTERN, response.text)
        if m:
            return m.group(1)
        else:
            raise LookupError('access_token does not exist')


def main():
    params = {}

    try:
        form = cgi.FieldStorage()
        if not form.has_key('code'):
            raise LookupError('QueryString "code" does not exist')

        token_retriever = TokenRetriever(form['code'].value)
        token_json = token_retriever.get_token()
        with open(TOKEN_FILE, 'w') as f:
            f.write(token_json)

        params['isOK'] = True
        params['token_file'] = TOKEN_FILE
        params['token_json'] = token_json
    except Exception as e:
        params['isOK'] = False
        params['error_type'] = type(e).__name__
        params['error_title'] = str(e)

    env = Environment(loader=FileSystemLoader(TPL_DIR, encoding='utf-8'))
    tpl = env.get_template(TEMPLATE)
    html = tpl.render(params)

    print('Content-type: text/html; charset=utf-8')
    print('\n')
    print(html.encode('utf-8'))

main()

La bibliothèque requests est utilisée pour utiliser l'API REST de facebook. Le jeton d'accès utilisateur facebook expire généralement 1 à 2 heures après son acquisition. Ce fut un problème à tester, j'ai donc utilisé l'API REST Access Token Extension pour échanger des jetons valides pendant 60 jours.

Modèle d'affichage du jeton d'accès

** templates / get_token.tpl.html ** affiche le jeton d'accès acquis.

html+jinja:templates/get_token.tpl.html


<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>get_token</title>
  </head>
  <body>
  {% if isOK %}
    <b>User Access Token</b>Quand<b>Page Access Token</b>J'ai eu.</br>
Les jetons sont au format JSON suivant{{ token_file }}Je l'ai écrit.
    <pre>{{ token_json }}</pre>
  {% else %}
    <b>L'erreur suivante s'est produite:</b><br/>
    [{{ error_type }}] {{ error_title }}
  {% endif %}
  </body>
</html>

Fonctionnement du programme CGI et acquisition de jetons d'accès

Maintenant, exécutons CGI et obtenons un jeton d'accès. Puisqu'il s'agit d'une vérification, httpd tel que nginx et apache ne sera pas utilisé, et python2.7 CGIHTTPServer sera utilisé à la place.

Démarrer le serveur HTTP CGI

Démarrez le serveur HTTP CGI avec la commande suivante à partir du répertoire contenant le répertoire conf.json, le répertoire cgi-bin et le répertoire templates.

Démarrer le serveur HTTP CGI


$ python -m CGIHTTPServer

Index d'accès

Accédez à l'URL suivante à partir du navigateur du PC sur lequel CGIHTTPServer est démarré.

http://localhost:8000/cgi-bin/index

fb_python_08.png

Authentifié avec OAuth

Cliquez sur get_token pour authentifier l'application Facebook et vous demander d'approuver les autorisations.

1 Vérification de l'autorité donnée à l'utilisateur Vérifiez l'autorité d'approuver. Étant donné que cette application Facebook n'est pas approuvée, un avertissement s'affiche indiquant que certaines des autorisations telles que l'écriture dans le groupe ont été invalidées.

fb_python_09.png

2 Vérifiez la plage d'affichage Spécifiez la plage de publications que l'application Facebook publie en votre nom.

fb_python_10.png

3 Vérification des autorisations pour la page Facebook Vérifiez l'autorité de gestion et l'autorité de publication de la page Facebook. Il n'y a aucun avertissement concernant la publication sur la page Facebook, même pour les applications non approuvées.

fb_python_11.png

Obtention et affichage des jetons d'accès

CGI obtient le jeton d'accès, l'enregistre dans token.json et l'affiche à l'écran.

fb_python_12.png

token.json


{
  "token": {
    "page_access": "Jeton d'accès à la page obtenu", 
    "user_access": "Jeton d'accès utilisateur obtenu"
  }
}

Publier sur Facebook

Maintenant que j'ai le jeton d'accès, je le posterai de python sur facebook. Vous pouvez utiliser directement l'API REST de Facebook, mais cette fois, nous utiliserons le SDK Facebook pour Python.

script python

Obtenez-vous et le point de terminaison de la page Facebook en utilisant le SDK et le jeton d'accès et rédigez un message. Notez que la méthode d'écriture est différente entre votre chronologie et la chronologie de la page Facebook.

post.py


#!/usr/bin/env python
# -*- encode: utf-8 -*-

import sys
import json
import facebook


class Timeline:

    def __init__(self, token_file):
        with open(token_file, 'r') as f:
            token = json.load(f)['token']
            self.user_endpoint = facebook.GraphAPI(token['user_access'])
            self.page_endpoint = facebook.GraphAPI(token['page_access'])

    def post_me(self, msg):
        self.user_endpoint.put_object('me', 'feed', message=msg)
        print('posted to my timeline: %s' % msg)

    def post_page(self, msg):
        self.page_endpoint.put_wall_post(message=msg)
        print('posted to page timeline: %s' % msg)

if __name__ == '__main__':
    if len(sys.argv) != 4:
        print('usage: %s token_file [me|page] message' % sys.argv[0])
        exit(1)
    try:
        timeline = Timeline(sys.argv[1])
        if sys.argv[2] == 'me':
            timeline.post_me(sys.argv[3])
        elif sys.argv[2] == 'page':
            timeline.post_page(sys.argv[3])
        else:
            print '%s is invalid' % sys.argv[2]
    except (IOError, facebook.GraphAPIError) as e:
        print e
        exit(9)

Publiez sur votre chronologie

Essayez de publier sur votre chronologie.

Publiez sur votre chronologie


$ ./post.py token.json me "Poste de test. Ceci est un test d'un article à partir d'un script python."
posted to my timeline:Poste de test. Ceci est un test d'un article à partir d'un script python.

facebook_python_12.png

Publication sur la chronologie sur la page Facebook

Je le posterai sur la chronologie de la page facebook créée pour cette expérience.

$ ./post.py token.json page "Poste de test. Ceci est un test d'un article à partir d'un script python."
posted to page timeline:Poste de test. Ceci est un test d'un article à partir d'un script python.

fb_python_13.png

finalement

Je voulais juste publier de python sur facebook, mais c'était un très long chemin, mais j'ai pu publier en toute sécurité sur ma chronologie et la chronologie de la page facebook. Facebook préparera-t-il également un webhook entrant?

Recommended Posts

Publication de Python sur la chronologie Facebook
Publier de Python vers Slack
[Lambda] [Python] Publier sur Twitter depuis Lambda!
Publier une image de Python sur Tumblr
Changements de Python 3.0 à Python 3.5
Changements de Python 2 à Python 3.0
publier sur vim → Python → Slack
Flirter de PHP à Python
Publiez sur Slack avec Python 3
Anaconda mis à jour de 4.2.0 à 4.3.0 (python3.5 mis à jour vers python3.6)
Publier sur Twitter en utilisant Python
Passer de python2.7 à python3.6 (centos7)
Connectez-vous à sqlite depuis python
Publier sur Slack en Python
POSTER des messages de python vers Slack via un webhook entrant
Essayez d'exploiter Facebook avec Python
Connectez-vous à la base de données utf8mb4 à partir de python
Python (de la première fois à l'exécution)
Comment accéder à wikipedia depuis python
Python pour passer d'une autre langue
Publiez facilement sur Twitter avec Python 3
[Nanonets] Comment publier un mémo [Python]
N'a pas changé de Python 2 à 3
Mettre à jour Mac Python de 2 à 3
Publier un message d'IBM Cloud Functions sur Slack en Python
[Python] Simulation de fluide: de linéaire à non linéaire
De Python à l'utilisation de MeCab (et CaboCha)
Comment mettre à jour Google Sheets à partir de Python
Manuel Python privé (mis à jour de temps en temps)
Je veux utiliser jar de python
Conversion de katakana en voyelle kana [python]
Notification push du serveur Python vers Android
Connexion de python à MySQL sur CentOS 6.4
Portage et modification du solveur de doublets de python2 vers python3.
Comment accéder à RDS depuis Lambda (python)
Python> Numéros de sortie de 1 à 100, 501 à 600> Pour csv
Convertir de Markdown en HTML en Python
[Amazon Linux] Passage de la série Python 2 à la série Python 3
Explication API pour toucher mastodonte de python
Connectez-vous à l'API Websocket de Coincheck depuis Python
Mis à jour vers Python 2.7.9
Somme de 1 à 10
sql à sql
MeCab de Python
"Backport" vers python 2
Envoyer un message de Slack à un serveur Python
Modifier Excel à partir de Python pour créer un tableau croisé dynamique
Comment ouvrir un navigateur Web à partir de python
Étude de Python Hour7: Comment utiliser les classes
[Python] Conversion de DICOM en PNG ou CSV
Importer un fichier Excel depuis Python (enregistré dans DB)
Je souhaite envoyer un e-mail depuis Gmail en utilisant Python.
[Python] Je veux gérer 7DaysToDie depuis Discord! 1/3
Du dessin de fichier au graphique en Python. Élémentaire élémentaire
[Premier message] Question ・ Comment balayer python
[Python] Comment lire les données de CIFAR-10 et CIFAR-100
[python] Créer une table de pandas DataFrame vers postgres
[Bash] Obtenez la puissance de python de bash en utilisant la documentation ici
Comment générer un objet Python à partir de JSON