J’ai créé un robot AWS qui publie automatiquement ma poésie sur Instagram chaque jour
16 mins read

J’ai créé un robot AWS qui publie automatiquement ma poésie sur Instagram chaque jour

Un projet de week-end utilisant AWS CDK, Lambda et l’API Instagram Graph — et tous les pièges dans lesquels je suis tombé en cours de route.

Photo sur Jarmoluk

J’écris de la poésie. Au fil des années, j’ai accumulé une pile de poèmes dans une feuille de calcul, sans rien faire. Pendant ce temps, je prends aussi beaucoup de photos sur mon iPhone qui ne quittent jamais la pellicule.

Un week-end, j’ai pensé : Et si un robot publiait chaque jour un de mes poèmes sur Instagram, associé à une de mes photos, sans que je lève le petit doigt ?

Quelques heures plus tard, je l’ai fait fonctionner sur AWS. C’est l’histoire de comment – ​​et, plus important encore, de tout ce qui s’est brisé en cours de route.

Ce qu’il fait

Une fois par jour à 21h, le bot :

  1. Extrait le poème avec le nombre de posts le plus bas de DynamoDB
  2. Récupère la photo la plus ancienne en attente dans le dossier S3 / en attente
  3. Le redimensionne et le compresse pour répondre aux exigences d’Instagram
  4. Sert l’image via CloudFront
  5. Le publie sur Instagram via l’API Graph
  6. Déplace la photo vers /posted et incrémente le nombre de publications du poème

C’est ça. Je dépose des photos dans S3 chaque fois que j’en ai envie. Le bot s’occupe du reste.

L’architecture

EventBridge déclenche un événement programmé chaque jour à 21 heures. Cela déclenche une fonction Lambda, qui communique avec DynamoDB, S3, CloudFront et l’API Instagram Graph. Les secrets résident dans le magasin de paramètres Systems Manager. L’ensemble de la pile est défini dans AWS CDK (TypeScript), avec le code Lambda en Python.

Le choix de conception clé : S3 reste privé. CloudFront se trouve devant et diffuse publiquement des images sur Instagram. Cela compte beaucoup, comme vous le verrez ci-dessous.

Avant

Jusqu’ici, tout est la configuration. En dessous de la ligne, j’écris la mise en œuvre réelle : la procédure complète, chaque piège que j’ai frappé et comment je m’en suis sorti.

Les pièges sont la vraie valeur. Si vous envisagez de créer quelque chose qui publie sur Instagram via l’API Graph, vous en rencontrerez presque certainement au moins quelques-uns :

  • Pourquoi Instagram rejette l’URL de votre image même lorsqu’elle fonctionne dans un navigateur
  • Pourquoi votre image est « téléchargée » au lieu d’être affichée (et pourquoi Instagram déteste ça)
  • Comment gérer Pillow sur Lambda lorsque vous ne pouvez pas simplement l’installer localement
  • La danse asynchrone en deux temps dans laquelle l’API Instagram vous oblige

Si tu as déjà regardé "Seules les photos ou vidéos peuvent être acceptées comme type de média" vous vous demandez ce que cela signifie – cet article est pour vous.

Étape 1 : initialiser le projet CDK

AWS CDK (Cloud Development Kit) vous permet de définir une infrastructure dans TypeScript. Vous écrivez du code, exécutez cdk déployer et CDK génère un modèle CloudFormation en arrière-plan et provisionne tout pour vous.

Comparé à l’écriture manuelle de CloudFormation YAML, CDK semble magique : il résout les dépendances, connecte automatiquement les rôles IAM et conserve votre infrastructure et votre code d’application dans le même dépôt.

Initialisez le projet, démarrez votre compte/région AWS pour CDK et vous êtes prêt à commencer à définir les ressources.

Étape 2 : Le compartiment S3

Le bucket comporte deux dossiers logiques : / en attente (photos en attente de publication) et / posté (photos déjà utilisées).

S3 n’a pas réellement de dossiers, ce ne sont que des préfixes clés. Je crée des fichiers d’espace réservé .keep dans chacun afin qu’ils apparaissent dans la console.

Paramètres critiques :

  • BlockPublicAccess : BLOCK_ALL – le compartiment reste entièrement privé
  • RemovalPolicy : RETAIN – pour que cdk destroy ne détruit pas mes photos

Je me connecterai à ce bucket depuis mon iPhone à l’aide d’Owlfiles, une application qui peut monter directement le S3. Faire glisser une photo dans le dossier / en attente est tout le travail manuel que je dois effectuer.

Étape 3 : la table DynamoDB pour les poèmes

Le schéma est minimal :

  • poème_id (clé de partition) — un UUID
  • titre – le titre du poème
  • corps — le texte du poème
  • posts_count — combien de fois il a été publié

J’ajoute un index secondaire global sur posts_count afin de pouvoir interroger efficacement "le poème le moins posté." Le GSI a besoin d’une clé de partition, j’utilise donc une valeur factice constante ("poème") sur tous les éléments. Un petit hack, mais ça marche.

Étape 4 : Importer des poèmes depuis CSV

J’avais écrit tous mes poèmes sous forme de brouillons sur le Japon note plate-forme et les a exportés au format CSV. Le CSV contenait un tas de choses que je n’a pas veulent être importés – essais, fiction, pages de table des matières – et la plupart des poèmes avaient des préambules et des post-mots enroulés autour du corps du poème lui-même.

J’ai écrit un petit script Python en utilisant boto3 et pandas pour :

  1. Filtrez les lignes dont le titre contenait « essai », « fiction » ou « plan du site »
  2. Détectez les séparateurs ——– que j’utilise couramment dans les messages et extrayez uniquement le milieu (le poème lui-même)
  3. Ignorer n’importe quelle ligne avec un corps vide
  4. put_item chaque poème restant dans DynamoDB avecposted_count : 0

Sur 113 lignes, 101 ont réussi à passer le filtre. Tous ont atterri dans DynamoDB avecposted_count : 0, prêts à être choisis.

Étape 5 : La distribution CloudFront (c’est là que les choses sont devenues réelles)

Ma première tentative a été de générer une URL S3 pré-signée dans Lambda et de la transmettre à Instagram. Propre, simple, aucun seau public n’est nécessaire.

La réponse d’Instagram :

“Seules les photos ou vidéos peuvent être acceptées comme type de média.”

Après avoir longuement consulté la documentation, j’ai appris que Le robot d’exploration d’Instagram refuse les URL contenant des jetons d’authentification ou des redirections de chaîne de requête. Les URL pré-signées contiennent exactement celles-là. Les liens de « téléchargement direct » de Google Drive échouent pour la même raison. Instagram veut une URL propre, statique et publique pointant vers les octets bruts.

La solution : gardez le compartiment privé, placez CloudFront devant lui avec Origin Access Control et remettez à Instagram l’URL CloudFront à la place. URL propre, pas d’authentification, pas de redirection, fonctionne à chaque fois.

CDK en fait quelques lignes. Les paramètres importants sont HTTPS_ONLY pour le protocole de visualisation et withOriginAccessControl pour câbler l’OAC entre CloudFront et S3.

Étape 6 : Créer une couche d’oreiller pour Lambda

Pour redimensionner les images, j’avais besoin d’un oreiller. Lambda ne l’inclut pas par défaut, vous avez donc besoin d’une couche Lambda.

Le piège : Pillow a des binaires natifs. Si vous l’installez sur votre ordinateur portable, ces binaires sont créés pour votre système d’exploitation et la version de Python, pas pour celle de Lambda. L’importation échouera silencieusement (ou très fort) en production.

La solution la plus propre consiste à créer la couche dans AWS CloudShell, car l’environnement Linux de CloudShell correspond assez étroitement à celui de Lambda. Les indicateurs pip clés sont :

  • –platform manylinux2014_x86_64 — cible l’architecture de Lambda
  • –python-version 3.12 — ciblez le runtime que vous utiliserez
  • –only-binary=:all : — force pip à utiliser la roue pré-construite

Conditionnez le résultat sous forme de zip, publiez-le en tant que couche avec aws lambda submit-layer-version et référencez l’ARN de la couche dans votre pile CDK. Fait.

Étape 7 : La fonction Lambda

C’est là que tout converge. La fonction effectue six choses dans l’ordre :

1. Récupérez le poème le moins publié. Une requête DynamoDB GSI, ScanIndexForward : True, Limit : 1. Ennuyeuse et rapide.

2. Liste /en attente dans S3. S’il n’y a rien (en ignorant l’espace réservé .keep), la fonction revient plus tôt — pas de photo, pas de message. J’avais initialement prévu de m’appuyer sur Bedrock pour générer une image, mais j’ai décidé que "sauter aujourd’hui" est plus simple et honnête.

3. Redimensionnez et compressez l’image. Le plafond d’Instagram est de 8 Mo par image. Les photos de mon iPhone 16 font généralement entre 15 et 17 Mo. Utilisation de l’oreiller :

  • Appliquez d’abord ImageOps.exif_transpose – sinon les photos de portrait finissent sur le côté
  • Convertir en RVB (certaines images sont disponibles en RVBA ou CMJN, ce qu’Instagram déteste)
  • Redimensionner pour que le côté le plus long mesure au maximum 1 440 px (maximum d’Instagram)
  • Enregistrez au format JPEG, en commençant à la qualité 85, en diminuant de 5 jusqu’à ce que le résultat soit inférieur à 7 Mo (en me donnant un tampon de 1 Mo)

Puis la ligne la plus importante de toute la fonction: téléchargez à nouveau sur S3 avec ContentType=’image/jpeg’ explicitement défini.

Si vous ignorez cela, S3 stocke l’objet avec Content-Type : application/octet-stream. L’image fonctionne bien dans un navigateur (elle "téléchargements"), mais le robot d’exploration d’Instagram voit un type MIME non-image et le rejette. Cela m’a coûté une heure. Ne répétez pas mon erreur.

4. Publiez sur Instagram. L’API Graph nécessite une danse en deux étapes :

  1. POST /{ig-user-id}/media avec l’image_url et la légende. Cela crée un "récipient" et renvoie un Creation_id.
  2. POST /{ig-user-id}/media_publish avec ce Creation_id.

Si vous appelez l’étape 2 trop tôt, vous obtenez "L’ID média n’est pas disponible". Le conteneur est créé de manière synchrone mais traité de manière asynchrone : Instagram récupère et valide l’image en arrière-plan, et jusqu’à ce que cela soit fait, le conteneur n’est pas publiable.

Le correctif consiste à interroger : GET /{container_id}?fields=status_code toutes les quelques secondes jusqu’à ce que status_code == "FINI". J’interroge jusqu’à 15 fois à 3 secondes d’intervalle. En pratique, il est généralement prêt après la première ou la deuxième vérification.

5. Déplacez la photo. S3 n’a pas d’opération de renommage, donc « déplacer » est en fait une copie + une suppression. La source va de ending/xxx.jpg à posté/xxx.jpg.

6. Incrément post_count. Un simple UpdateItem avec SET posté_count = posté_count + :val.

Étape 8 : Secrets dans le magasin de paramètres

Le jeton d’accès Instagram et l’ID de compte professionnel sont transférés dans le magasin de paramètres AWS Systems Manager en tant que paramètres SecureString (chiffrés au repos avec KMS). J’accorde l’autorisation Lambda ssm:GetParameter limitée à mon chemin de paramètre uniquement.

Le jeton que j’utilise est de courte durée (~ 60 jours). Pour un bot personnel, l’actualiser manuellement plusieurs fois par an est très bien. Pour tout ce qui est partagé, vous souhaiterez l’échanger contre un jeton de longue durée et automatiser l’actualisation.

Étape 9 : Le calendrier EventBridge

Une règle cron, 12h00 UTC = 21h00 JST, avec le Lambda comme cible. Dans CDK, c’est trois lignes.

C’est tout le robot.

Coût de fonctionnement

Calcul approximatif pour 30 publications par mois :

  • Stockage S3— négligeable (quelques centimes)
  • Appels Lambda — le niveau gratuit le couvre
  • DynamoDB à la demande — le niveau gratuit le couvre
  • CloudFront — le premier 1 To de transfert est gratuit
  • Pont d’événements — 30 ​​appels est une erreur d’arrondi

Total: moins de 0,10 $/mois . Assez bon marché pour que je n’y pense même pas.

Les pièges que j’ai touchés, dans l’ordre

Cela vaut la peine de s’y retirer, car si vous construisez quelque chose de similaire, vous en rencontrerez un sous-ensemble :

  1. Les URL S3 pré-signées ne fonctionnent pas avec Instagram. Ils contiennent des jetons d’authentification ; Instagram les rejette. Utilisez CloudFront.
  2. URL CloudFront téléchargées sous forme de fichiers et non d’images.Parce que S3 les a stockés avec application/octet-stream. Définissez ContentType=’image/jpeg’ lors du téléchargement.
  3. Les photos de l’iPhone sont trop grandes.15 Mo+ par rapport à la limite de 8 Mo d’Instagram. Redimensionnez et compressez dans Lambda.
  4. L’oreiller ne fonctionne pas immédiatement.L’installation locale de pip produit des binaires pour la mauvaise plate-forme. Créez la couche dans CloudShell avec les bons indicateurs de plate-forme.
  5. « L’ID média n’est pas disponible » lors de la publication.Le conteneur d’Instagram est créé de manière synchrone mais traité de manière asynchrone. Sondage pour status_code == FINISHED avant la publication.
  6. Mauvais identifiant de compte professionnel Instagram.L’explorateur de l’API Graph peut mentir sur le compte auquel un jeton est mappé. Vérifiez toujours avec moi?fields=id,name avant d’utiliser un identifiant.

Remarque : les détails de l’API reflètent avril 2026. L’API Instagram Graph change fréquemment – ​​faites toujours des références croisées aux documents officiels de Meta pour le comportement actuel.


J’ai construit un robot AWS qui publie automatiquement ma poésie sur Instagram chaque jour a été initialement publié dans Stackademic sur Medium, où les gens poursuivent la conversation en soulignant et en répondant à cette histoire.

PakarPBN

A Private Blog Network (PBN) is a collection of websites that are controlled by a single individual or organization and used primarily to build backlinks to a “money site” in order to influence its ranking in search engines such as Google. The core idea behind a PBN is based on the importance of backlinks in Google’s ranking algorithm. Since Google views backlinks as signals of authority and trust, some website owners attempt to artificially create these signals through a controlled network of sites.

In a typical PBN setup, the owner acquires expired or aged domains that already have existing authority, backlinks, and history. These domains are rebuilt with new content and hosted separately, often using different IP addresses, hosting providers, themes, and ownership details to make them appear unrelated. Within the content published on these sites, links are strategically placed that point to the main website the owner wants to rank higher. By doing this, the owner attempts to pass link equity (also known as “link juice”) from the PBN sites to the target website.

The purpose of a PBN is to give the impression that the target website is naturally earning links from multiple independent sources. If done effectively, this can temporarily improve keyword rankings, increase organic visibility, and drive more traffic from search results.

Jasa Backlink

Download Anime Batch