ふにゃるんv2

もとは、http://d.hatena.ne.jp/Wacky/

Google Documents List APIを使って、Google ドキュメントにファイルを自動アップロードする

自分は、個人的な気づきをテキストファイルにメモしたりしているんですね。
メールやはてブも使っていますが、ネット経由とローカルファイルでは、どうしても応答速度に違いが出てしまいますからね。


そうやって、書き留めたテキストファイルですが、何時までもローカルに置いておくのも嫌なんですね。
プライベートなネットストレージに突っ込んでおけば、ローカルマシンが壊れた際の復旧や、タブレットなどの別のマシンからも参照できるので、便利になる訳です。


ネットストレージに突っ込んだデータの検索性で、非常に便利なのは、今の所、Google ドキュメントかEvernote辺りかな?と感じています。
特に、Google ドキュメントは、検索がバカ早なので、結構お気に入りです。
(MicrosoftさんのSkyDriveは容量はピカイチなのですが、検索を自分のアップしたものに絞れないのがネック<何か方法があるのかなぁ?)
(ちなみに、Yahooはサービス規約をポンポン変えるので、不安で使えない)

という訳で

という訳で、テキストファイルをGoogle ドキュメントに自動アップロードしようと思いました。
要するに、タスクスケジューラ等で、ローカルに置いたテキストファイルを定期的にアップロード&更新しちゃおうって訳です。


当初は、適当なソフトを使おうか?と思っていたんですが、ぐぐると結構楽に実装できる事が判ったので、勉強がてら自作する事にしました。


クライアントのライブラリは、Client Libraries and Sample Code - Google Documents List API - Google CodeのDownloadから取得します。
自分が取得したのは、gdata-2.0.14.zip でした。


ダウンロードして、setup.pyでinstallすればインストールされます。

I:\Wacky\src\test\google\gdata-2.0.14>python setup.py install
...

byte-compiling C:\tool2\Python27\Lib\site-packages\gdata\youtube\__init__.py to
__init__.pyc
byte-compiling C:\tool2\Python27\Lib\site-packages\gdata\__init__.py to __init__
.pyc
running install_egg_info
Writing C:\tool2\Python27\Lib\site-packages\gdata-2.0.14-py2.7.egg-info


後は、上のリンクで紹介されているサンプルコードを元にAPIを叩けばOKです。


では、早速今回作ったコードを示します。

#!/bin/env python
# -*- encoding: cp932 -*-
"""
    Google Documentにテキストファイルをアップロードする
    なお、テキストファイルは、utf-8形式がデフォルトである。(Google Documentの場合)
"""
import sys
import os
import os.path
import pdb
import gdata.docs
import gdata.docs.service

def get_exe_dir_name():
    """実行スクリプトのフォルダを取得"""
    return os.path.abspath(os.path.dirname(__file__))

def copy_to_utf8(src_fpath, dst_dir=None):
    """src_fpath(コピー元のファイルパス)からdst_dir(コピー先ディレクトリ)に、utf-8変換コピーする"""
    fname = os.path.split(src_fpath)[1]
    if dst_dir == None: dst_dir = get_exe_dir_name()
    dst_fpath = os.path.join(dst_dir, fname)
    s = "nkf32 -w8 \"%s\" > \"%s\"" % (src_fpath, dst_fpath)
    print "call: ", s
    os.system(s)
    
    return dst_fpath

def list_file(cli):
    """Google Documentのファイル一覧を得る"""
    i = 0
    for e in cli.GetDocumentListFeed().entry:
        i = i + 1
        print "%02d : file [%s][%s]" % (i, e.title.text.decode('utf-8'), e.GetDocumentType())

def list_dir(cli):
    """Google Documentのフォルダ一覧(コレクション)を得る"""
    i = 0
    q = gdata.docs.service.DocumentQuery(categories=['folder'], params={'showfolders': 'true'})
    for e in cli.Query(q.ToUri()).entry:
        i = i + 1
        print "%02d : dir [%s]" % (i, e.title.text.decode('utf-8').encode('cp932'))

def find_file(cli, name):
    """Google Documentに指定した名前のファイルがあるか調べる。あればオブジェクトを、無ければNoneを返す"""
    for e in cli.GetDocumentListFeed().entry:
        if e.title.text.decode('utf-8') == unicode(name, 'cp932'):
            return e
    return None

def upload_text(cli, fpath, name=None):
    """Google Documentに、ファイルをアップロードする。既にファイルがあれば置き換える
        \arg    fpath   アップロード元のファイルパス
        \arg    name    アップロード時の名前
    """
    if name == None: name = os.path.split(fpath)[1]
    
    print "アップロード中(%s, %s)..." % (name, fpath)
    ms = gdata.MediaSource(file_path=fpath, content_type=gdata.docs.service.SUPPORTED_FILETYPES['TXT'])
    exist_file = find_file(cli, name)
    
    e = None
    if exist_file == None:
        print "  new upload file!!"
        e = cli.Upload(ms, unicode(name, 'cp932'))
    else:
        print "  replace file!!"
        e = cli.Put(ms, exist_file.GetEditMediaLink().href)
    print "  OK!!"
    print "  href=%s" % (e.GetAlternateLink().href)

def main(argv):
    print "[%s]のファイルを作業フォルダにコピー中" % argv[1]
    up_file = copy_to_utf8(argv[1])
    print "upload file:[%s]" % up_file
    
    print "Google Documentにアクセス中...",
    cli = gdata.docs.service.DocsService()
    cli.ClientLogin("<アカウント>", "<パスワード>")
    print "アクセス完了!!"
    
    print "\n--- Google Document List ---"
    list_dir(cli)
    list_file(cli)
    print ""
    
    upload_text(cli, up_file, None)
    
    print "アップロード完了!!"

if __name__ == "__main__":
    argv = sys.argv
    print "argc=%d" % len(argv)
    for i in range(len(argv)): print "%d-[%s]" % (i, argv[i])
    main(argv)


使い方は、アップロードしたいテキストファイルのパスを第1引数に与えるだけです。
スクリプトのフォルダに、nkf32でUTF-8変換したテキストファイルを一旦配置し、それからGoogle ドキュメントにアップロードする仕掛けです。

最後に

一応余談です。


Googleドキュメントは、テキストファイルはUTF-8が前提になっているみたいです。
なので、スクリプトでは、Windows版のnkf32を使って、一旦UTF-8に変換してからアップロードするようにしています。
そうしないと、アップロードしたファイルを参照しようとして、文字化けに遭遇しちゃいます。


後、UploadとReplaceをうまく使わないと、同じファイル名で、バンバンUploadするハメに陥りますので、気をつけてください。
(最初、同じ名前のファイルが連続して表示されたので、何が起きたのだろうと考えこんでしまった)


でわでわ。