📝

OASISを利用したNote.com自動投稿システム開発(開発日記 No.105)

に公開

関連リンク

はじめに

昨日は、Note.comへの自動投稿システム開発に向けた計画を立てました。今日は、その計画に基づき、OASISというPythonモジュールを利用した投稿機能の実装を進めていきます。

背景と目的

セキュリティ関連の記事を効率的にNote.comへ投稿するために、自動化システムの構築を目指しています。GitHub Actionsのパイプラインとして実装し、ローカル環境での動作検証も可能にすることで、柔軟な運用を実現します。

検討内容

OASISの動作検証、投稿スクリプトの実装、GitHub Actionsパイプラインの構築という流れで作業を進めることを決定しました。特に、OASISの動作検証では、仮想環境の構築や認証情報の確認が必要となるため、手順を詳細化しました。

実装内容

まずはOASISの動作検証から開始しました。

  1. 仮想環境の作成

    python3 -m venv .venv_note_oasis
    
  2. 仮想環境のアクティベートとOASISのインストール

    source .venv_note_oasis/bin/activate && pip install --upgrade pip && pip install oasis-article
    
  3. Note.comの認証情報を.envファイルに設定

    .env.example
    # OASIS(oasis-article)用 .env サンプル
    
    # Note.com 認証情報
    NOTE_EMAIL=your_note_email@example.com
    NOTE_PASSWORD=your_note_password
    NOTE_USER_ID=your_note_user_id
    
    # (必要に応じて他サービスの認証情報も追記可能)
    # QIITA_TOKEN=your_qiita_api_token
    # AUTH_USER=your_wordpress_username
    # AUTH_PASS=your_wordpress_password
    # BASE_URL=https://your_wordpress_site.com
    # GEMINI_API_KEY=your_gemini_api_key
    
  4. サンプル記事の作成

    mkdir -p tools/sample-article && echo -e '# サンプル記事\n\nOASISによるNote.com自動投稿テスト。' > tools/sample-article/sample.md
    
  5. OASISのヘルプ表示と動作確認

    .venv_note_oasis/bin/oasis --help | tee tools/oasis_help.txt
    
    .venv_note_oasis/bin/oasis --folder_path tools/sample-article --note --note-email dummy@example.com --note-password dummy_pass --note-user-id dummy_id --firefox-headless > tools/oasis_note_test_output2.txt 2>&1
    

    この段階で、Gemini APIキーが未設定であるという警告が表示されました。

  6. 自動投稿スクリプトの雛形を作成

    -
    + import argparse
    + import subprocess
    + import sys
    + from pathlib import Path
    +
    +
    + def main():
    +     parser = argparse.ArgumentParser(description="指定ディレクトリ内のMarkdownをNote.comに投稿する(OASIS利用)")
    +     parser.add_argument('--folder', required=True, help='投稿対象のMarkdownファイルが入ったディレクトリ')
    +     parser.add_argument('--note-email', required=False, help='Note.comのメールアドレス(省略時は.env参照)')
    +     parser.add_argument('--note-password', required=False, help='Note.comのパスワード(省略時は.env参照)')
    +     parser.add_argument('--note-user-id', required=False, help='Note.comのユーザーID(省略時は.env参照)')
    +     parser.add_argument('--firefox-headless', action='store_true', help='Firefoxをヘッドレスで実行')
    +     args = parser.parse_args()
    +
    +     folder_path = Path(args.folder)
    +     if not folder_path.exists() or not folder_path.is_dir():
    +         print(f"[ERROR] 指定ディレクトリが存在しません: {folder_path}")
    +         sys.exit(1)
    +
    +     # OASISコマンド組み立て
    +     cmd = [
    +         sys.executable.replace('python', 'oasis'),
    +         '--folder_path', str(folder_path),
    +         '--note'
    +     ]
    +     if args.note_email:
    +         cmd += ['--note-email', args.note_email]
    +     if args.note_password:
    +         cmd += ['--note-password', args.note_password]
    +     if args.note_user_id:
    +         cmd += ['--note-user-id', args.note_user_id]
    +     if args.firefox_headless:
    +         cmd += ['--firefox-headless']
    +
    +     print(f"[INFO] 実行コマンド: {' '.join(cmd)}")
    +     result = subprocess.run(cmd, capture_output=True, text=True)
    +     print(result.stdout)
    +     if result.stderr:
    +         print(result.stderr, file=sys.stderr)
    +     if result.returncode != 0:
    +         print(f"[ERROR] 投稿処理に失敗しました (exit code: {result.returncode})", file=sys.stderr)
    +         sys.exit(result.returncode)
    +
    + if __name__ == '__main__':
    +     main()
    

    ファイル名:tools/note_post.py

  7. テストコードの雛形を作成

    -
    + import subprocess
    + import sys
    + from pathlib import Path
    +
    + def test_no_args():
    +     result = subprocess.run([sys.executable, 'tools/note_post.py'], capture_output=True, text=True)
    +     assert result.returncode != 0
    +     assert 'usage:' in result.stderr or 'usage:' in result.stdout
    +
    + def test_invalid_folder():
    +     result = subprocess.run([
    +         sys.executable, 'tools/note_post.py', '--folder', 'not_exist_dir'
    +     ], capture_output=True, text=True)
    +     assert result.returncode != 0
    +     assert '存在しません' in result.stdout
    

    ファイル名:tests/test_note_post.py

  8. テストの実行とpytestのインストール

    .venv_note_oasis/bin/python -m pip install pytest
    
    .venv_note_oasis/bin/python -m pytest tests/ > tests/pytest_result.txt 2>&1
    
  9. Gemini APIキーを設定し、再度スクリプトを実行

    .venv_note_oasis/bin/python tools/note_post.py --folder tools/sample-article --firefox-headless
    

    この時点で、Gemini APIのレート制限超過のエラーが発生しました。

  10. GitHub Actionsのパイプラインを作成

    -
    + name: Post to Note.com with OASIS
    +
    + on:
    +   workflow_dispatch:
    +   push:
    +     paths:
    +       - 'security-study/**/*.md'
    +       - 'tools/note_post.py'
    +       - '.github/workflows/note_post.yml'
    +
    + jobs:
    +   post-to-note:
    +     runs-on: ubuntu-latest
    +     steps:
    +       - name: Checkout repository
    +         uses: actions/checkout@v4
    +
    +       - name: Set up Python
    +         uses: actions/setup-python@v5
    +         with:
    +           python-version: '3.12'
    +
    +       - name: Set up venv and install dependencies
    +         run: |
    +           python -m v
GitHubで編集を提案

Discussion