はじめに
2020年1月にテックブログをリニューアルして以来、メンバーに記事を投稿してもらう度に記事のレビューや記事投稿を手作業で行ってきましたが、せっかくなので記事を自動投稿できるようにしたいと思います。
やること
- 記事のアップロード(下書き状態)
- 記事内の画像アップロード(フォトライフ)
をGitHubへのプルリクの作成時に起動するようにしたいと思います。
記事のアップロード(下書き状態)
はてなブログAPIのOAuth認証で記事をアップロードしたいと思います。 まずOAuth認証のアクセストークンを発行するためにConsumer KeyとConsumer Secretを取得します。 Consumer KeyとConsumer Secretを利用してAccess Tokenを取得するコードは以下となります。
require 'oauth' require 'mechanize' class HatenaAPI def initialize @consumer = OAuth::Consumer.new( ENV['CONSUMER_KEY'], ENV['CONSUMER_SECRET'], site: 'https://www.hatena.com', request_token_url: '/oauth/initiate?scope=read_public%2Cread_private%2Cwrite_public%2Cwrite_private', access_token_url: '/oauth/token', oauth_callback: 'oob', timeout: 300 ) @agent = Mechanize.new end def oauth_authorize request_token = @consumer.get_request_token oauth_verifier = '' page = @agent.get(request_token.authorize_url) form = page.forms[0] form.field_with(name: 'name').value = ENV['USER_NAME'] form.field_with(name: 'password').value = ENV['PASSWORD'] @agent.submit(form) page = @agent.get(request_token.authorize_url) form = page.forms[1] page = @agent.submit(form) oauth_verifier = page.css('div.verifier').text @consumer.options.delete(:oauth_callback) request_token.get_access_token(oauth_verifier: oauth_verifier) end end hatena = HatenaAPI.new access_token = hatena.oauth_authorize puts "AccessToken: #{access_token[:oauth_token]}" puts "AccessTokenSecret: #{access_token[:oauth_token_secret]}"
Consumer KeyとConsumer Secret、ユーザ名とパスワードを環境変数として定義しておくとAccess Tokenを取得することができます。
続いて、Access Tokenを利用して記事の投稿を行います。
class HatenaAPI attr_reader :header, :hatena_blog, :photolife class << self def generate_access_token(site) consumer = OAuth::Consumer.new( ENV['CONSUMER_KEY'], ENV['CONSUMER_SECRET'], site: site, timeout: 300 ) OAuth::AccessToken.new( consumer, ENV['ACCESS_TOKEN'], ENV['ACCESS_TOKEN_SECRET'] ) end end def initialize @hatena_blog = HatenaAPI.generate_access_token('http://blog.hatena.ne.jp') @photolife = HatenaAPI.generate_access_token('http://f.hatena.ne.jp') @header = { 'Accept' => 'application/xml', "Content-Type" => "application/xml" } end def upload_article(file_path) body = File.read(file_path) @hatena_blog.request(:post, "https://blog.hatena.ne.jp/#{ENV['USER_NAME']}/#{ENV['BLOG_ID']}/atom/entry", Oga.parse_xml(body).to_xml, @header) end end hatena = HatenaAPI.new hatena.upload_article('article.xml')
また、アップロードする記事はxmlである必要があるため、以下のテンプレートに記事内容やタイトルを置き換えてアップロードします。
<?xml version="1.0" encoding="utf-8"?> <entry xmlns="http://www.w3.org/2005/Atom" xmlns:app="http://www.w3.org/2007/app"> <title>{{title}}</title> <author><name>{{author}}</name></author> <content type="text/x-markdown"> {{content}} </content> <updated>{{time}}</updated> <app:control> <app:draft>yes</app:draft> </app:control> </entry>
- title: 記事のタイトル
- author: 執筆者のはてなID
- content: 記事内容
- time: 投稿時刻
となっています。
また、
<app:draft>yes</app:draft>
とすることで下書きとしてアップロードしてくれます。
記事内の画像アップロード(フォトライフ)
最後に、画像のアップロードですがこちらも記事とほぼ同様の手順でアップロードすることができます。
@photolife.request(:post, '/atom/post', body, @header).body)
また、画像アップロードようのxmlのテンプレートは以下となります。
<entry xmlns="http://purl.org/atom/ns#"> <title>{{title}}</title> <content mode="base64" type="{{mime_type}}">{{content}}</content> <dc:subject>{{dirname}}</dc:subject> </entry>
- title: 画像のタイトル
- mime_type: 画像のmimeタイプ
- content: 画像をBase64エンコードしたもの
- dirname: フォトライフのアップロードするディレクトリ(Hatena Blog等)
最後に
はてなブログAPIを利用した記事の自動投稿を実装しました。 これらをGitHubのイベントと連携することでより快適なテックブログ投稿ができるようになりました。
参考
筆者
dippeople.dip-net.jp (写真左)