Ruby

Qiita:Team の記事を画像付きでエクスポートする

Abstract

Qiita:Team 記事は,オーナー権限があるならば json 書き出しを使用することが出来る.しかし,一般ユーザは使うことが出来ないし,画像がエクスポートされない.そこで,記事IDを指定すると .md ファイルと画像ファイルをまとめてディレクトリにダウンロードしてくるスクリプトを作成した.

やってないこと

復数記事を一気にダウンロードするようにはしていない.また,直近の用事で必要だったので json 内の記事内容(.md)と画像を書き出す事しか扱っていないので,汎用的に使うにはすこし手を加える必要がある(jsonそのものを保存するようにするとか).ただ,そう拡張するのは簡単に思う.

Qiita API & Gem

Qiita には API があり,その ruby 用ドライバとして Gem が提供されている.Qiita:Team でなければ普通に Web ページをスクレイピング等でダウンロードしてくる手もあるが, Qiita:Team の場合は認証が必要なので, APIと gem を使ったほうが楽だ.

アクセストークン発行

このAPIを使うには,以下のように Qiita のアカウント設定画面からアクセストークンを発行する必要がある.

アカウント画面→アプリケーション

6925d0cd-0f6d-c862-16bc-9aa0113cc63a.png

個人用アクセストークン→新しくトークンを発行する

スクリーンショット 2018-05-08 18.49.29.png

適当に名前を入力して,権限をいちおう read_qiita_team のみに設定

発行されたトークンを保存

e40a534f-5da8-78fb-5c48-71e1dc51f26c.png

このトークンを何処かに丁重に保存しておく(取扱い注意)

Installation

現状の最新クライアントはこれのようです

$ ruby -v
ruby 2.4.2p198 (2017-09-14 revision 59899) [x86_64-darwin17]
$ gem install qiita

require 'qiita' して ruby から呼ぶことになるが,以下のように CLI ツールとしても使える

$ qiita get_user azumag -a '<TOKEN>'
or
$ export QIITA_ACCESS_TOKEN='<TOKEN>
$ qiita get_user azumag
{
  "description": "写真は詐欺です",
  "facebook_id": "",
  "followees_count": 7,
  "followers_count": 4,
  "github_login_name": "azumag",
  "id": "azumag",
  "items_count": 1,
  "linkedin_id": "",
  "location": "Tokyo, Japan",
  "name": "Tsubasa Azumagakito",
  "organization": "",
  "permanent_id": 205151,
  "profile_image_url": "https://avatars2.githubusercontent.com/u/9018513?v=4",
  "twitter_screen_name": null,
  "website_url": ""
}

CLIとして使えば,以下のようにitem 取得 (JSON)したり,jq を使って整形したりできるが,このままだと色々処理が辛いので,次章で ruby script を作る

$ qiita get_item f380eb3ec0636350797c -t seattle-consulting | jq .title
# qiita team の場合, -t でチームを指定することができる.

ダウンロードスクリプト

以下のように作成した.チームドメインと記事 ID を指定すると,実行ディレクトリの直下に記事 ID ディレクトリを作り,記事とそれに含まれる画像を保存する.メチャクチャ適当に作ったので内部品質はお察しください.

$ export QIITA_ACCESS_TOKEN='あなたのトークン'
$ ruby article2mdsets.rb <qiita team のドメイン> <記事のID>
article2mdsets.rb
require 'qiita'
require 'net/http'

token       = ENV['QIITA_ACCESS_TOKEN']
team_domain = ARGV[0]
item_id     = ARGV[1]
article_path = "./#{item_id}"

FileUtils.mkdir(article_path) unless File.exist?(article_path)

qbody_path = "#{article_path}/qbody.md"

host = "#{team_domain}.#{Qiita::Client::DEFAULT_HOST}"

client = Qiita::Client.new(access_token: token, host: host)
response = client.get_item(item_id).body

qbody = response['body']

images = qbody.scan(/\!\[image\..*\]\((.*)\)/)
images = qbody.scan(/src=\"(.*)\"/) if images.empty?

images.flatten!

https = Net::HTTP.new(host, 443)
https.use_ssl = true

# img をダウンロード
images.each do |url|
  puts url
  uri = URI.parse(url)
  open("#{article_path}/#{File.basename(uri.path)}", 'wb') do |file|
    req = Net::HTTP::Get.new(uri)
    req["Authorization"] = "Bearer #{token}"
    file.puts(https.request(req).body)
  end
end

# img path を相対パスに書き換える
images.each do |url|
  qbody.gsub!(/#{url}/, "./#{File.basename(URI.parse(url).path)}")
end

File.write(qbody_path, qbody)

OAuth認証とかにしたら?

後ろ向きに検討します.さっくり使いたかったんだ.