2013年01月15日

[Python]xmlrpclibを使ってブログにエントリ投稿する方法

今回はPythonからブログへ投稿する方法をご紹介する。
XML-RPCを公開しているブログサービスなら以下のやり方でプログラムからブログ記事を投稿できる。cronなどに登録すれば自動投稿も可能になる。
続きを読む
posted by 寄り道退屈男 at 21:39 | Comment(0) | TrackBack(0) | Python

2013年01月13日

[Python]feedparserライブラリでRSSフィードを簡単に処理

RSSなどのフィードをPythonプログラムから簡単に利用する方法をご紹介しよう。
今回はfeedparserというライブラリを使う。
続きを読む
posted by 寄り道退屈男 at 23:20 | Comment(0) | TrackBack(0) | Python

2012年04月20日

[Python]正規表現を使って半角記号を除去する方法。

ASCIIコード表を見ながら、除去したい記号を選ぶ。

!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_abcdefghijklmnopqrstuvwxyz{|}~


例えば、全ての半角記号を表す正規表現は、[!-/:-@[-`{-~] である。以下はこの正規表現を使って文字列から半角記号だけを取り除くサンプルである。

import re

str = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_abcdefghijklmnopqrstuvwxyz{|}~"
print re.sub(re.compile("[!-/:-@[-`{-~]"), '', str)


これを実行すると以下のように出力される。

0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz



おまけとして、数字だけを抽出したい場合の例も紹介しよう。

import re

str = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_abcdefghijklmnopqrstuvwxyz{|}~"
print re.sub(re.compile("[!-/:-~]"), '', str)


実行するとこのように表示される。

0123456789

posted by 寄り道退屈男 at 16:32 | Comment(0) | TrackBack(0) | Python

2011年12月11日

PythonでJPEG画像のEXIF情報やGPS情報を解析。

Pythonで画像ファイル(JPEG)のEXIF情報を解析する方法を紹介する。

画像に埋め込まれたEXIF情報を見れば、使用したカメラの機種情報や撮影日時、GPS情報なども分かる。最近のスマホは位置情報を知らず知らずのうちにデータに埋め込んでるから怖いね、、、。

さて、先ずはサンプルコードを読む前にPythonでバイナリデータを読む方法を読んでおいて欲しい。バイナリデータを扱う知識は必須である。pythonのstructを使ったバイナリデータ処理が理解できていれば、いよいよサンプルコードの解読である。

、、、おっとその前に解析対象となるJPEG画像を手元に用意しておこう。自分はこちらの画像を使わせてもらった。画像ファイルは適当に hoge.jpg とリネームしておいた。

では気を取り直してコードを見てみよう。

exif_read.py
# -*- coding: utf-8 -*-
import struct

'''
IFDタグ情報をダンプする関数
EXIFやGPSなIFDの存在が確認出来ればそちらもダンプする
'''
def disp_ifd(f, ifd_ptr):
'''
IFDヘッダ
'''
f.seek(ifd_ptr)
tag_num = struct.unpack('>H', f.read(2))[0]
print 'tag_num: %s' % tag_num

'''
IFDタグ群(12bytes * tag_num)
'''
for i in range(0, tag_num):
tag_id, val_type, val_num, val = struct.unpack('>HHII', f.read(12))
print " tagNo.%d" % i
print " tag_id: %s" % tag_id
print " val_type: %s" % val_type
print " val_num: %s" % val_num
print " val: %s" % val
''' val_num > 1 なら本データへのoffset、valがデータsize '''
if val_num > 1:
cfp = f.tell()
f.seek(tiff_start_pos + val)
val_ex = f.read(val_num)
print " val_ex: %s" % val_ex
f.seek(cfp)
print "\n"
'''
tag_idが、
ExifIFDPointer(34665)や
GPSIFDPointer(34853)の場合は
disp_ifd関数を再起呼び出し
'''
if tag_id == 34665 or tag_id == 34853:
print " ExifIFDPointer(34665) or GPSIFDPointer(34853) found.\n"
disp_ifd(f, tiff_start_pos + val)
return


f = open('hoge.jpg', 'rb')

'''
APマーカセグメント1情報取得
'''
jpg_soi, app1marker, app1size, exif_rcd = struct.unpack('>HHH6s', f.read(12))
print 'jpg_soi: %x' % jpg_soi
print 'app1marker: %x' % app1marker
print 'app1size: %s' % app1size
print 'exif_rcd: %s' % exif_rcd

'''
TIFFヘッダ情報取得
'''
tiff_start_pos = f.tell()
tiff_header, tiff_rcd, ifd_ptr_offset = struct.unpack('>2sHI', f.read(8))
print 'tiff_header: %s' % tiff_header
print 'tiff_rcd: %x' % tiff_rcd
print 'ifd_ptr_offset: %x' % ifd_ptr_offset

''' IFDへのポインタ '''
ifd_ptr = tiff_start_pos + ifd_ptr_offset

'''
IFD情報取得
'''
disp_ifd(f, ifd_ptr)

f.close()


実行結果は以下の通り。
jpg_soi: ffd8
app1marker: ffe1
app1size: 9773
exif_rcd: Exif
tiff_header: MM
tiff_rcd: 2a
ifd_ptr_offset: 8
tag_num: 11
tagNo.0
tag_id: 271
val_type: 2
val_num: 9
val: 146
val_ex: FUJIFILM

tagNo.1
tag_id: 272
val_type: 2
val_num: 11
val: 156
val_ex: FinePix40i

(略)

tagNo.10
tag_id: 34665
val_type: 4
val_num: 1
val: 250


ExifIFDPointer(34665) or GPSIFDPointer(34853) found.

tag_num: 28
tagNo.0
tag_id: 33437
val_type: 5
val_num: 1
val: 592

tagNo.1
tag_id: 34850
val_type: 3
val_num: 1
val: 131072

(略)

tagNo.27
tag_id: 41729
val_type: 7
val_num: 1
val: 16777216


EXIFの仕様はこちらのページが分り易い。タグIDの対応表もあるから便利である。

ざっくりと説明すると、以下のような仕様になっている。

 1) APPマーカーセグメント1
 2) TIFFヘッダ
 3) IFD情報(1..n)
   3-1) タグ情報群(1..n)

IFD情報は複数個存在しうるのでIFD0番目からIFDn番目まで順番に舐めていく、、、べきなのだが、今回はちょっと面倒くさかったのでIFD0(とEXIF, GPS情報)しか見に行っていない。

GPS情報を取得したいのであれば、IFD情報内のタグ情報群から tag_id="34853" な値を見つけ出せば良い。TagIDの対応表によると、その値は"GPSInfoIFDPointer"、つまり"GPS情報を持つIFDへのポインタ"となっているから、そのポイントへf.seekすれば良い。GPS情報といえど所詮はIFD仕様のデータなので解析処理は使い回しでOK。サンプルコード内ではdisp_ifd関数を再起呼び出ししている。

ここで一つ注意が必要だ。
タグ値として格納されている"ポインタ情報"、例えば"GPSInfoIFDPointer"は、原則としてTIFFヘッダの開始位置からの"オフセット"を表しているということだ。そのため、サンプルコード内では、tiff_start_pos = f.tell() としてTIFFヘッダ開始位置を保存している。例えば、上の実行結果にある "tag_id: 34665" なデータの値 "val: 250" は、ExifIFD情報へのポインタを表しているが、これはあくまでもTIFFヘッダポインタからのオフセットなのである。ここはちゃんと覚えておこう。

というわけで、上の実行結果を見れば分かると思うが、このJPEG画像には、Exif情報IFD(TagID=34665)は存在していたが、GPS情報IFD(TagID=34853)は存在してなかったということだ。ちなみにスマホを持たない俺には、GPS情報が埋まったサンプル画像を入手する術が無かったため、ちゃんとGPS情報が出るか試していない。スマホをお持ちの人は試してみて欲しい。バグってたら教えて。


初めてのPython 第3版
初めてのPython 第3版
posted with amazlet at 11.12.10
Mark Lutz
オライリージャパン
売り上げランキング: 94573

タグ:python Exif JPEG
posted by 寄り道退屈男 at 21:13 | Comment(0) | TrackBack(0) | Python

2011年12月10日

Pythonでバイナリデータ解析。もうどんなデータも怖くない。

Pythonを使ってバイナリデータを解析する方法を紹介する。

まずはバイナリエディタなどで以下のサンプルバイナリデータを作ろう。

hoge.bin
FF AA AA 41 41 41 E3 81 82 E3 81 82 E3 81 82


上のバイナリデータを以下のように定義してみた。

初めの1byte: 0xFF = signed char (1) = 255
次の2bytes: 0xAAAA = unsigned short (2) = 43690
次の3bytes: 0x414141 = char[] = 'AAA'
次の9bytes: 0xE38182E38182E38182 = char[] = u'あああ'

早速このファイルをpythonで読み込み解析してみよう。

bin_read.py
# -*- coding: utf-8 -*-
import struct

print u"先ずは先頭から順番に読み込む"
f = open('hoge.bin', 'rb')
print '1. signed char (1): %s' % struct.unpack('<b', f.read(1))
print '2. unsigned short (2): %s' % struct.unpack('H', f.read(2))
print '3. char[3]: %s' % struct.unpack('3s', f.read(3))
print '4. char[9]: %s' % struct.unpack('9s', f.read(9))
f.close()

print u"tupleへ一気に格納することも可"
f = open('hoge.bin', 'rb')
data1, data2, data3, data4 = struct.unpack('<bH3s9s', f.read())
print '1. signed char (1): %s' % data1
print '2. unsigned short (2): %s' % data2
print '3. char[3]: %s' % data3
print '4. char[9]: %s' % data4
f.close()


以下が実行結果。
一部表示が文字化けしているが("縺ゅ≠縺")、これはUTF-8の "あああ" である。
C:\>bin_read.py
先ずは先頭から順番に読み込む
1. signed char (1): -1
2. unsigned short (2): 43690
3. char[3]: AAA
4. char[9]: 縺ゅ≠縺
tupleへ一気に格納することも可
1. signed char (1): -1
2. unsigned short (2): 43690
3. char[3]: AAA
4. char[9]: 縺ゅ≠縺


バイナリデータを読み込む上での重要箇所は、struct.unpack(arg1, arg2) の部分だ。arg1にはフォーマット形式、arg2には解析対象のバイナリデータをそれぞれ代入する。

上の例のフォーマット形式 '<bH3s9s' を丁寧に説明すると、まず最初の1文字目はバイトオーダーで "<" はリトルインディアンなデータを表す。
その次の "b" は signed char (1)を、
次の "H" は unsigned short(2)を、
次の "3s" は 文字列(char[]) 3バイトを、
次の "9s" で 文字列(char[]) 9バイトをそれぞれ表している。

フォーマット形式の詳細は本家サイトのstructの解説をご参照あれ。
今回はこちらも参考にさせてもらった。
posted by 寄り道退屈男 at 17:27 | Comment(0) | TrackBack(0) | Python