0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LinkedIn投稿をPythonで自動化する方法【Gemini×Claude×DALL-E・週3投稿対応】

0
Posted at

はじめに

こんにちは。ITフィールドセールスをしている長井洸太です。

LinkedInはエンジニア・経営者・ITパーソンが集まるSNSで、案件獲得やネットワーキングに非常に有効です。ただ、週3回・3パターンの投稿文を毎回考えるのは時間がかかる

そこで今回は、以下を全自動化する仕組みを作りました。

AIニュース収集(Gemini)
    ↓
週3投稿文を3パターン生成(Claude)
    ├── 月曜:反論型
    ├── 水曜:数字・リスト型
    └── 金曜:問題提起型
    ↓
LinkedIn用画像を自動生成(DALL-E / Gemini Imagen)
    ↓
Markdownに下書き保存(人間が確認して投稿)

実際にこのスクリプトで今週の投稿文と画像を生成しました。


必要なもの

pip install anthropic google-genai openai feedparser beautifulsoup4 python-dotenv requests
# .env
CLAUDE_API_KEY=sk-ant-...
GEMINI_API_KEY=AIza...
OPENAI_API_KEY=sk-...   # 画像生成用(任意、なければGemini Imagenで代替)

全体コード構成

scripts/linkedin/
├── linkedin_all_patterns.py   # メインスクリプト(投稿文+画像生成)
└── generate_images_from_md.py # 既存MDから画像だけ再生成

ステップ1:AIニュースをGeminiで収集・選定

Hacker News・OpenAI・Anthropic・Google DeepMindなど複数ソースからAI関連ニュースを収集し、Geminiで今週のテーマに合わせて3件に絞ります。

import feedparser
import requests
from google import genai

gemini_client = genai.Client(api_key=os.getenv("GEMINI_API_KEY"))

def fetch_hacker_news(limit=5):
    ids = requests.get(
        "https://hacker-news.firebaseio.com/v0/topstories.json", timeout=10
    ).json()[:80]
    results = []
    AI_KEYWORDS = ["ai", "llm", "gpt", "openai", "anthropic", "claude", "agent"]
    for sid in ids:
        item = requests.get(
            f"https://hacker-news.firebaseio.com/v0/item/{sid}.json", timeout=5
        ).json()
        if item and any(kw in item.get("title", "").lower() for kw in AI_KEYWORDS):
            results.append(f"- {item['title']}  ({item.get('url', '')})")
        if len(results) >= limit:
            break
    return results

def fetch_rss(name, url, limit=3):
    feed = feedparser.parse(url)
    return [f"- {e.get('title','')}  ({e.get('link','')})" for e in feed.entries[:limit]]

def summarize_news(raw_sources: str, theme: str) -> str:
    prompt = f"""
以下のAIニュースから、今週のテーマに最も関連する3件を選んでください。

【今週のテーマ】{theme}

【収集済みニュース】
{raw_sources}

【出力形式(プレーンテキストのみ)】
タイトル:〇〇
URL:〇〇
概要:1行
ビジネスへの衝撃:1行
"""
    resp = gemini_client.models.generate_content(
        model="gemini-2.5-flash", contents=prompt
    )
    return resp.text.replace("**", "")

週テーマは4つをローテーションします。

WEEKLY_THEMES = [
    {"theme": "AI × 医療・ヘルスケア"},
    {"theme": "AI × 法律・教育"},
    {"theme": "AI × ビジネス・経営"},
    {"theme": "AI × クリエイティブ"},
]
week_index = datetime.now().isocalendar()[1] % 4
current_theme = WEEKLY_THEMES[week_index]["theme"]

ステップ2:Claudeで3パターンの投稿文を生成

月曜・水曜・金曜向けに、それぞれ異なる型の投稿文を生成します。

import anthropic

claude_client = anthropic.Anthropic(api_key=os.getenv("CLAUDE_API_KEY"))

POST_PATTERNS = [
    {
        "name": "反論型",
        "day": "月曜向け",
        "rule": """
冒頭1行(20文字以内):通説を真っ向否定する断言
本文:
  1段落目 - ニュースの具体的な数字・事実で根拠を示す
  2段落目 - AIエンジニアとしての実務視点で一段深い本質を述べる
  3段落目 - 読者への問いかけ+月1回ソフトCTA(DM誘導)
禁止:「かもしれない」などの曖昧語、Markdown記号(**など)
文字数:280〜380文字(ハッシュタグ含む)
ハッシュタグ:3つ以内(#AI活用 必須)
""",
    },
    {
        "name": "数字・リスト型",
        "day": "水曜向け",
        "rule": """
冒頭1行:具体的な数字を含むフック(「知らないと損する3つ」など)
各項目の形式:
  [絵文字] 項目タイトル
  → 具体的な数字・ツール名・ビフォーアフターを1〜2行
締め:「だからまず動くべきことは1つだ:〇〇」+コメント促進
文字数:320〜420文字、ハッシュタグ3つ以内
""",
    },
    {
        "name": "問題提起型",
        "day": "金曜向け",
        "rule": """
冒頭1行:「誰も語らない本当の問題は〜」など立ち止まらせる一文
1段落目:世間の語られ方(ニュース引用)
2段落目:実務視点の深い問い(数字・具体例付き)
3段落目:読者へ答えを委ねる問いかけで終える(答えを出し切らない)
文字数:300〜400文字、ハッシュタグ3つ以内
""",
    },
]

PERSONA = """
AIエンジニア・自動化エンジニアとして活動中。
業務自動化・AIツール導入・生産性向上が専門領域。
エンジニア・IT経営者・マーケターに向けて発信。
フリーランス/副業で案件獲得を目指している。
"""

def generate_post(news_summary: str, pattern: dict) -> str:
    prompt = f"""
あなたはLinkedInで案件獲得を目指すAIエンジニアの投稿ライターです。

【投稿者プロフィール】
{PERSONA}

【今週のAIニュース】
{news_summary}

【投稿スタイル:{pattern['name']}{pattern['day']})】
{pattern['rule']}

【共通ルール】
・URLは本文中に入れない(リーチが下がる)
・Markdown記号(**など)は一切使わない
・投稿文のみ出力。前置き不要。

投稿文:
"""
    resp = claude_client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1200,
        messages=[{"role": "user", "content": prompt}],
    )
    return resp.content[0].text.strip()

ステップ3:DALL-Eで画像を自動生成

パターンごとに3種類のスタイルプールを持ち、実行のたびにランダム選択します。

import random
from openai import OpenAI

openai_client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

IMAGE_STYLE_POOLS = {
    "反論型": [
        "LinkedIn-optimised professional portrait: a confident Japanese woman in her mid-20s "
        "in a sharp navy blazer, seated at a clean minimal desk with a laptop, looking directly "
        "into the camera with calm authority. Studio lighting, dark background. 16:9, no text overlay.",

        "LinkedIn-optimised environmental portrait: a Japanese woman in her mid-20s standing "
        "at floor-to-ceiling office windows, arms loosely crossed, city skyline behind her. "
        "Shot on 35mm f/2. 16:9, no text overlay.",

        "LinkedIn-optimised action portrait: a Japanese woman in her mid-20s mid-explanation "
        "at a whiteboard, marker in hand. Bright workshop room. 16:9, no text overlay.",
    ],
    "数字・リスト型": [
        "LinkedIn-optimised productivity portrait: a Japanese woman in her mid-20s at a "
        "standing desk, three monitors neatly arranged. She is half-turned to camera. "
        "Dark mode screens, warm desk lamp. 16:9, no text overlay.",
        # ...(他2スタイル)
    ],
    "問題提起型": [
        "LinkedIn-optimised candid work portrait: a Japanese woman in her mid-20s at a café "
        "table, both hands around a coffee mug, looking slightly upward mid-thought. "
        "Natural window light. Shot on 50mm f/1.4. 16:9, no text overlay.",
        # ...(他2スタイル)
    ],
}

def generate_image(pattern_name: str, post_text: str, output_path: Path) -> bool:
    pool = IMAGE_STYLE_POOLS.get(pattern_name, [])
    style = random.choice(pool) if pool else ""
    prompt = f"{style} Theme: {post_text[:100]}..."

    try:
        resp = openai_client.images.generate(
            model="gpt-image-1",
            prompt=prompt[:4000],
            size="1536x1024",
            n=1,
        )
        item = resp.data[0]
        img_data = (
            base64.b64decode(item.b64_json) if item.b64_json
            else requests.get(item.url, timeout=30).content
        )
        output_path.write_bytes(img_data)
        return True
    except Exception as e:
        print(f"  [WARN] DALL-E失敗: {e}")
        return False

実行方法

# 投稿文+画像を一括生成
python scripts/linkedin/linkedin_all_patterns.py

# カスタムコンテンツ(自分で用意したMD)をベースに生成
python scripts/linkedin/linkedin_all_patterns.py --content-file path/to/content.md

# 自分の一言コメントを投稿に反映
python scripts/linkedin/linkedin_all_patterns.py --comment "先週試したら〇〇だった"

# 既存MDから画像だけ再生成
python scripts/linkedin/generate_images_from_md.py Earning/linkedin-posts/2026-06/2026-06-27_all_patterns.md

出力サンプル

実行すると以下のようなMDが Earning/linkedin-posts/YYYY-MM/ に保存されます。

## パターン1:反論型(月曜向け)

### 📝 投稿文(コピペ用)
「AIエージェントは実務で使えない」は設計の問題だった。

でも3ヶ月間、実際に業務へ組み込んで使い続けた感想は正反対だった...

#AI活用 #AIエージェント #業務自動化

### 🖼️ 生成画像
![反論型](2026-06-27_pattern1_反論型.png)

### 💬 30分後コメント
「設計の問題という指摘、まさにそこ。タスクの粒度と検証ステップが8割...」

やってみてわかったこと(セールス視点)

LinkedInはX(Twitter)と違い、投稿の"賞味期限"が長い。

Xは投稿後数時間でタイムラインから消えますが、LinkedInでは良い投稿が1〜2週間後にバズることがあります。

そのため「毎日投稿」より**「週3回・質の高い投稿」**の方がLinkedInでは効果的です。

このスクリプトは最初からその設計にしており、3パターンを曜日で使い分けることで、同じニュースから多角的な視点の投稿を生み出せます。


おわりに

このスクリプトを使って毎週LinkedInに投稿することで、エンジニア・IT経営者からのコメントやDMが増えています。

SNS自動化シリーズの関連記事:

X(@kotajobs0)でも毎日AI活用の話を投稿しています。よかったらフォローしてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?