PDFからテキストを抽出する

データ入力とかの仕事で,PDFを扱っている方にとって,これは結構ありがちな問題だと思います. その他,論文をテキストにして解析したいとか,なかなかPDFからテキストへの変換はよく聞く話です(僕だけでしょうか笑). PDFMinerというものがあります.フォントの埋め込まれた?PDFにはこれで立ち向かえます.

以下使用例です. Pythonから使ったりできるみたいですけど,僕はshellで一旦ファイルに出して使っています.

pdf2txt.py test.pdf > test.txt

Pythonでcopyとdeepcopy

Pythonの辞書にはにはdict.copy()というメソッドが用意されているが,これは注意しないとはまります. 以下を見てください.

In [1]: d = {"a":1, "b":range(10)}

In [2]: d
Out[2]: {'a': 1, 'b': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}

In [3]: d2 = d.copy()

In [4]: d2
Out[4]: {'a': 1, 'b': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}

In [5]: d2["b"].append(10)

In [6]: d
Out[6]: {'a': 1, 'b': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}

In [7]: d2
Out[7]: {'a': 1, 'b': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}

このように,値にリスト(おそらく辞書や集合も)を持つような辞書をコピーすると, 値であるリストはコピーされません(番地への参照を持つだけ). そのため,dをコピーしたd2のキーbの値を変更すると,dの内容も変わってしまいます. これを解決するために,Pythonにはcopyというモジュールがあります. copy.deepcopy()を使うことによって,この問題を解決できます. 以下使用例です.

In [8]: from copy import deepcopy

In [9]: d = {"a":1, "b":range(10)}

In [10]: d
Out[10]: {'a': 1, 'b': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}

In [11]: d2 = deepcopy(d)

In [12]: d2
Out[12]: {'a': 1, 'b': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}

In [13]: d2["b"].append(10)

In [14]: d
Out[14]: {'a': 1, 'b': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]}

In [15]: d2
Out[15]: {'a': 1, 'b': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}

僕はよくこういうのにはまるので,皆さんもお気をつけて( ´ゝ`)

作業に行き詰まった時

僕はよく作業(主にプログラミングなどで)に行き詰まる。アホだからだ。

そうすると鬼の形相でGoogle Google Googleという有様だ。

こんな状態では、ほとんどの場合対応策が見つからない。無理もないが。見つかってもまた詰まってしまうこともある。そして、雑なコードを書いて後で直すなんてことも…。

冷静でなくてはならない。
良い対応策はソファに転んでiPhoneでなんとなく探してる時に見つかったりする。

僕は、これからこうしようと思う。

  • 1. 作業に詰まる
  • 2. PCを離れる
  • 3. 何か飲む、食べる
  • 4. ソファまたはベッドへダイブ
  • 5. 当分ダラダラする
  • 6. ダラダラに飽きてきたらそれとなくiPhoneで調べる
  • 7. 良さげな記事をリーディングリストへバンバン送る
  • 8. 後は散歩に出たりして気分転換
  • 9. PCの前へ。リーディングリストをチェック
  • 10. 何か見つかる→めでたしめでたし
    何も見つからない→3または4へ

どうですか。良くないですか?笑
自然と湧き出るエネルギーのみを使うよう心がける、ことにします。

Google App Engineでプロパティにアクセスできない

助けてください.笑 get_by_key_nameでとって来たエンティティのプロパティにアクセスできなくて困っています.

# こんな感じのEntityを想定
class Entity(db.Model):
    username = db.StringProperty()

# あるkey_nameを用意
e = Entity.get_by_key_name(key_name)
# ↓当然True
ekey = e.key()
print ekey in [entity.key() for entity in Entity.all()] 

# ↓正しく全てのusernameが表示される
for key in [entity.key() for entity in Entity.all()]:
    print Entity.get(key).username

# ↓なんとこれはNone
for key in [entity.key() for entity in Entity.all()]:
    if ekey == key:
        print Entity.get(ekey).username

# 原因不明, 当然ekey==keyがTrueになるEntityインスタンスはただ一つ存在するのだが.

追記:
開発用サーバを再起動したら直りました.2,3度再起動はしてたんですけどね.
かなり時間を置いてからの4回目で直りました.ああーなんだったんだー笑

JSONについて調べた時のキーワード遷移がおもしろい

JSONってよく聞くけど、全然わかってなかったので調べることにした。そしてなんとなくぐぐるときのキーワードに気をつけていた。

もちろん最初は、

JSON とは

だ。そしてなんとなくつかんで、じゃあそれどうやって使うの?となり、お気に入りの言語Pythonでの使用例を探す。

json python

じぇーそん ぱいそん。
そして、jsonというモジュールがあることを知る。パースもできるし、辞書をjson形式に変換もしてくれるみたい。

そしてここからAPI開発について、はっと思いつく。ああ、こうやってデータ渡すのか、と。

そして辿り着いたクエリがこれ、

objective-c json

秀逸だ。このクエリが全てを物語っている。良さそうなページを見つけたのでevernoteに投げて満足。笑
必要になったら掘り起こそう。

クエリの遷移っておもしろいですね。
ちょっと興味が湧きました。笑

Pythonを理解するためのたった一つのこと

僕の大好きな言語であるPython。
まだまだ使い始めて1年半なのに、もう自分の一部であるような感じがする。笑

Pythonは広く普及しているが、僕の周りではまだまだJavaやC++が多かったりする。

というわけで、こんなエントリを書くことにした。まぁ誰も見ないと思うけどね。笑

さて、Pythonを理解するためのたった一つの方法(断っておくがこれは初めてプログラミング言語を学ぶ人を対象としている)。それは、

データ構造を理解する

ということだと僕は思う。理解するデータ構造はリスト(list)、辞書(dict)、集合(set)だ。

これらはPythonに最初から組み込まれている。これらを理解することで、あなたは何でも書けるようになる(と僕は思う)。

分厚い本を読むのも良い。
難しいチュートリアルをやるのも良い。
ただ、挫折するくらいならやらなくていいと思う。その代わり、これらのデータ構造を抑えて、さっさと自分の書きたいコードを書く、これに尽きると思う。

ただ、何をして良いかわからないときはここだろう。
Python Tutorial
こいつのリストと辞書と集合のところ、あとはそれを回すループについて知る。
これだけで十分な気がする。
どうせ、山ほど本を読んでも、つまずくときはつまずくのだから、とりあえず書きたいものを書いてつまずいたら調べる、って感じでやっていけば良いと思う。
ちなみに僕はPythonについては1冊も本を読んでいない(´Д` )それはそれで問題なのだが。数学とか機械学習の本は読むのにね。でも明らかに数学とかよりプログラミングの方が上達が早い。ということ数学とかも本を読まずに考えたいものを考えていた方が良いのかもしれない。

少し横道にそれたが、このエントリが少しでも新たなPythonistの手助けになれば良いなと思う!!

ちなみにこれは初めてのiPhoneアプリからの投稿。楽だね。

the get_or_insert method on Google App Engine

Google App Engine (GAE) であるものを作っています.
それにしてもよくつまづきます.

例えばある記事をデータストアに保存するとき,以下のようなモデルを使うとします.

class Entry(db.Model):
    link = db.LinkProperty()
    title = db.StringProperty()
    body = db.TextProperty()

linkはその記事のURLで,titleはその記事のタイトル,bodyはその記事の内容です.
記事の内容,つまりbodyを得るためにはurlopen*, requestsモジュールなどを使ってURLを開く必要があります.
この処理は時間がかかりますよね.
今回は,
link, titleは事前にわかっており,linkを使ってbodyを取得し,最後にデータストアに格納する際の処理について書きたいと思います.

さて,いろいろな記事があるわけですが,それぞれの記事に固有な(ユニークな)属性はなんでしょうか.
僕はURLを使いたいと思います.
URLがかぶっている記事なんて,存在しないと思うからです.
というわけで,ある一つの記事を格納する際に,既にデータストアにあるかどうかをチェックしたいと思います.
これにより,既にある記事の内容をもう一度読み込む必要はなくなります.
いろいろ調べたのですが,db.Model.get_or_insertというクラスメソッドが使えそうだな,という印象を受けました.
get_or_insertメソッドは以下のような形をしております.
get_or_insert(key_name, **kwds)
このkey_nameに記事のURLを指定してやるというわけです.
そうすると,あるURL uをkey_name=uとして指定してやると,既にデータストアにある場合はそのオブジェクトが,無い場合は新しいオブジェクトを作成し,それを格納してくれる,と思っています.
そこで,以下のようにしてみました.

a_entry = Entry.get_or_insert(key_name=entry.link,
                              title=entry.title,
                              link=entry.link,
                              body=unicode(f(entry.link), "utf-8"))

ただし,entry.linkはその記事のURLで,entry.titleはその記事のタイトル,関数fはURLを開き,HTMLを除去したテキストを返す関数です.
関数fは重い処理なので,できるだけ呼びたくありません.
これで,既にデータストアにある記事は関数fを呼ぶ必要はなくなると思っていました.
しかし,残念ながら呼んでしまうのです.
そこで以下のようにしてみました.

a_entry = Entry.get_or_insert(key_name=entry.link,
                              title=entry.title,
                              link=entry.link)
if a_entry.body is None:
    a_entry.body = unicode(f(entry.link), "utf-8")

つまり,bodyが無い場合だけ,関数fを呼ぶようにしました.そうすると,bodyがデータストアに格納されません.
これは,putすれば解決するかな,と思い,以下のように修正.

  a_entry = Entry.get_or_insert(key_name=entry.link,
                                title=entry.title,
                                link=entry.link)
  if a_entry.body is None:
      a_entry.body = unicode(f(entry.link), "utf-8")
   a_entry.put()

うまく動きました!感動です.
しかし,コードが汚いですね.
要は,getされたのか,insertされたのか知りたいわけです.
調べると,良い記事がありましたので紹介させて頂きます.ここの4です.

ここにあるクラスメソッドを使わせていただきます.モデルを変更.

class Entry(db.Model):
    link = db.LinkProperty()
    title = db.StringProperty()
    body = db.TextProperty()

    @classmethod
    def insert_or_fail(cls, key_name, **kwds):
        def txn():
            entity = cls.get_by_key_name(key_name, parent=kwds.get('parent'))
            if entity is None:
                entity = cls(key_name=key_name, **kwds)
                entity.put()
                return entity
            return None
        return run_in_transaction(txn)

そして,こう呼び出します.

a_entry = Entry.insert_or_fail(key_name=entry.link)
if a_entry is not None:
    a_entry.link = entry.link
    a_entry.title = entry.title
    a_entry.body = unicode(extract(entry.link), "utf-8")
    a_entry.put()

insert_or_failはinsertされたら(データストアにその記事がないなら)そのオブジェクトを返し,それ以外はNoneを返します.
Noneならば何もしなくていいわけですが,insertされたなら,各プロパティに値を入れて再度putしてやります.
これでコードが少しきれいになったでしょうか.しかし,別に最初のコードでよかったかもしれませんね.

さて,続きを書こう.
GAEには悩まされているので,またいろいろポストすると思われます!