limitusus’s diary

主に技術のことを書きます

Google Document にファイルをアップロードするバッチを作ってみた

GitHub に上げたので最新ソースは GitHub からどうぞ

http://github.com/limitusus/google_docs_up/

Motivation

普段研究室のサーバにログインして作業することが多いので、メールもサーバ上で Emacs を立ち上げ、その上で Mew を使ってメールを読んでいます。

ときどき添付ファイルつきメールが来ることもあるんですが、 .doc なファイルとか、 .xls なファイルとか、挙げ句の果てには .docx とか .xlsx とかが添付されてきます。
普段は Ubuntu しか使ってないので、 Openoffice.org を使って .doc や .xls まではギリギリ読めるのですが、 .docx とか来るとどうしようもなく、 Google Docs にアップロードすることで開くという対処法が存在していました。

前述したとおりメールはサーバ上で読んでいるので、アップロードを Web 上で行うためには、

  1. メールを受信する
  2. 添付ファイルをサーバ上のどこかに保存する
  3. 添付ファイルをローカルマシンに持ってくる
  4. Web上でアップロード処理を行う
  5. 添付ファイルを見る

というプロセスが必要です。これはいかにも時間がかかる作業で、真のプログラマなら面倒で到底やってられないでしょう。
自然に考えて、

  1. メールを受信する
  2. 添付ファイルをサーバ上のどこかに保存する
  3. 添付ファイルをサーバから直接アップロードする
  4. 添付ファイルを見る

となっているべきです。
これを実現するため、 Google Documents の API を利用することにしました。
API の詳細はこちら。
Protocol Guide (v3.0) - Google Documents List Data API v3.0 - Google Code

API は各種言語のものが用意されていますが、 Python を利用することにしました。

Get API Library

Google Documents の API ライブラリは以下のページから入手できます。
Client Libraries and Sample Code - Google Documents List Data API - Google Code

今回は PythonSVN から引っ張ってくることに。

Python Client Library Project -> Source

とたどると、チェックアウトの方法が分かります。ここには Subversion によるチェックアウト方法が書かれています。

tarball でも SVN でも、とにかく持ってきて展開すれば、 setup.py などが手に入ります(ここでは git-svn でチェックアウトしました)。

 ~/git/gdata-python-client % ls
INSTALL.txt  MANIFEST  README.txt  RELEASE_NOTES.txt  build  pydocs  samples  setup.py  src  tests

Install API Library

API ライブラリをインストールします。これは setup.py がやってくれます。詳しくは INSTALL.txt を読んでください。
私はいつも ~/local 以下にいろいろ置くことにしているので

 ~/git/gdata-python-client % ./setup.py install --home=$HOME/local

としてインストールしました。
これにより、 $HOME/local/lib/python 以下に Google Documents API Library がセットアップされます。
このようにセットアップを行った場合、環境変数 PYTHONPATH に $HOME/local/lib/python が含まれている必要があります。必要に応じて設定します。

Modify API Library

実は 2009/09/29 現在の PythonAPI は PDFのアップロードに対応していません(Java は対応しているらしい)。
そこで、少し修正を行います。

Issue 591 - gdata-issues - Allow Upload of PDF Files to Google Docs - Project Hosting on Google Codeの Comment: 77 に修正が書かれています。

修正するファイルは [--home で指定したディレクトリ]/lib/python/gdata/docs/service.py です。

  • uri = の行の変更
  • GData-Version の追加

の2ヶ所です。

Usage

作成したプログラムに実行権限を付けて PATH を通しておけば、

$ google-docs-up hoge.pdf
$ google-docs-up hoge.docx

などとするだけでファイルがアップロードされ、閲覧するための URI が表示されます。

% google_docs_up hoge.pdf
('hoge.pdf', 'hoge.pdf', 'pdf')
Document now accessible online at: http://docs.google.com/fileview?id=ファイルID
Current Documents list: 

hoge.pdf

のように出力され、上で表示された URI にアクセスすれば Google Documents 上でファイルを閲覧できます。

コードは続きで。

コードを書く

実際に書いてみたのがこれです。
ちょっと前の API の名残で面倒なことやってますが、修正も面倒なので放置しています。
(前の API では各ファイル種類毎に別々のアップロードメソッドを指定する必要がありましたが、現在は Upload に統一されています。多分今は拡張子による分岐は不要でしょう。)

#!/usr/bin/env python2.5
# -*- python -*-
import gdata.docs.service
import sys, os

# Create a client class which will make HTTP requests with Google Docs server.
client = gdata.docs.service.DocsService()
# Authenticate using your Google Docs email address and password.
client.ClientLogin('ユーザ名', 'パスワード')
# Upload Specified File
filepath = sys.argv[1]
filename = filepath.split("/")[-1]
# Determine FILETYPES
suffix = filename.split(".")[-1].lower()
ft = None
uploadfunc = None
is_upload = True

"""
{
    'RTF': 'application/rtf',
    'PPT': 'application/vnd.ms-powerpoint',
    'ZIP': 'application/zip',
    'DOC': 'application/msword',
    'HTM': 'text/html',
    'ODS': 'application/x-vnd.oasis.opendocument.spreadsheet',
    'ODT': 'application/vnd.oasis.opendocument.text',
    'TXT': 'text/plain',
    'SWF': 'application/x-shockwave-flash',
    'PPS': 'application/vnd.ms-powerpoint',
    'HTML': 'text/html',
    'TAB': 'text/tab-separated-values',
    'SXW': 'application/vnd.sun.xml.writer',
    'TSV': 'text/tab-separated-values',
    'PDF': 'application/pdf',
    'CSV': 'text/csv',
    'XLS': 'application/vnd.ms-excel',
    'PNG': 'image/png'
}
"""

uploadfunc = client.Upload
if suffix in ('doc', 'docx'):
    ft = 'DOC'
elif suffix in ('xls', 'xlsx'):
    ft = 'XLS'
elif suffix in ('ppt', 'pptx'):
    ft = 'PPT'
elif suffix == 'pdf':
    ft = 'PDF'
else:
    is_upload = False
    print "Unknown suffix. Don't upload"

if is_upload:
    print (filepath, filename, suffix)
    ms = gdata.MediaSource(file_path=filepath , content_type=gdata.docs.service.SUPPORTED_FILETYPES[ft])
    entry = uploadfunc(media_source=ms, title=filename)
    print 'Document now accessible online at:', entry.GetAlternateLink().href
print "Current Documents list: \n"
# Query the server for an Atom feed containing a list of your documents.
documents_feed = client.GetDocumentListFeed()
# Loop through the feed and extract each document entry.
for document_entry in documents_feed.entry:
    # Display the title of the document on the command line.
    print document_entry.title.text