Posts Tagged ‘python’

python-logo-master-v3-TM

先日Linux上でPythonのプログラムを開発していた時にディレクトリの中の画像ファイル一覧を取得したいなあと思う事がありました。

ディレクトリの中にはテキストファイルや、csvファイルが同時に含まれていたのですが、画像ファイルの一覧だけをリスト化したいなあと。

という事でどうやって解決したのかをここに記して置こうと思います。

import commands
jpgList = []
jpgList =  commands.getoutput("ls targetPath | grep *.jpg").split("\n")

osモジュールのlistdir()メソッドとかでもディレクトリとファイルの参照が出来るようですが、使い慣れたbashの出力をそのままゲット出来るcommands.getoutput()メソッドの方が便利だなと私は感じました。

このメソッドに文字列を渡すとカレントディレクトリでシェルコマンドを実行、返り値を取得する事ができます。

次のsplit()メソッドがキモなのですが、lsの返り値は”\n”で区切られています。

適当なファイルのあるディレクトリ内で

ls > result.txt
less result.txt

とやってみれば改行がIFS(内部フィールド区切り文字 (Internal Field Separator))となっている事が分かると思います。

よって、split(“\n”)で改行によって分割、リスト化してあげればlsの返り値を簡単にリスト化する事が出来るというワケです。

読者諸兄におかれましては蛇足となりましょうが、 ”| grep *.jpg” によってファイル末尾(拡張子)が”.jpg”のファイル群のみをリストアップするようにする事でjpgファイルらのみをリスト化しております。

python-logo-master-v3-TM

Pythonでは文字列型に文字を挿入するメソッドが存在しないようですね。
リスト型に挿入する方法はあるのですが・・・。

まあここらへんは各々ハックされていらっしゃる事だと存じますが、
今回私が使った手法をご紹介させていただこうとおもいます。

例えば 
“http://www.example.jp/0/1/700/500.1.jpg”という文字列があったとして
文字列中の”/1/”の部分を”/7/”に変更したいとします。
これだけなら.replace()メソッドを使う事で実現できてしまうのですが、もしも文字列が
“http://www.example.jp/1/1/700/500.1.jpg”
であった場合、”/1/”は2つ存在する事になり、両方とも置換されてしまいます。
この様な動作が目的に沿わない場合もある事でしょう。

こういうケースの場合以下の様に書く事によって、任意の場所の文字列を変更する事が可能です。

src = "http://www.example.jp/0/1/700/500.1.jpg"

#文字列の末尾から"/1/"を検索、その場所を確保
idx = src.rfind(r'/1/')

#ここがキモです。pythonでは文字列は非破壊なので、新しい変数を用意する必要があります。
#スライスを使って文字列srcのidxまでの文字列を取得、そこに"/7/"を加えて、更にスライスを用いてidx+3(+3は"/7/"の3文字を表す)より後の文字列を結合させています。
result = src[:idx] + "/7/" + src[idx+3:]

以上の方法によって私は、文字列の挿入を可能としました。

文字列の「スライス」の方法は以下に詳しく書いてあります。
スライスを使った部分文字列の取得

Today's latte, Summer is the season of Python!

Amazonで欲しい物がありました。
その商品は値段の乱高下激しく、ある時は6,000円台、またある時は4,000円台の事もある商品でした。

そこで僕は底値を探るべく、値段が下がった事を知らせてくれるシステムを作ろうと考えました。

という事で今回作ったシステムの概要を説明します。

■ システム概要

1. 欲しい商品のhtmlを取得。
2. 価格の部分を抜き出す。
3. 過去と現在の価格を比較して処理

という仕様を組みました。

■ 1.欲しい商品のhtmlを取得

まずは欲しい商品のhtmlを取得する際に使ったプログラムを示します。
プログラミングに使う言語はPythonを使いましたよ。

ちなみに欲しかった商品はコレ

import urllib2
f = urllib2.urlopen('http://www.amazon.co.jp/%E3%82%A2%E3%83%87%E3%82%A3%E3%83%80%E3%82%B9-adidas-FORUM-G1654900-%E3%83%9B%E3%83%AF%E3%82%A4%E3%83%88/dp/B003TJ91L8/ref=wl_it_dp_o_piT1_nS_nC?ie=UTF8&colid=2NPMF5TUB79UB&coliid=ISBLWHXEIDBUX')
html = f.read()

htmlの取得には”urllib2″というモジュール(ライブラリ)を使います。こいつをimportしてからurllib2のurlopen()関数を使用。結果を変数fに格納。

f.read()で変数htmlに該当Amazonページのhtmlソースが格納されてます。

■ 2.価格の部分を抜き出す

まずはソースを

import re
targetCol = re.search(r'priceLarge.*',html)
matchPrice = re.search(r'\d,\d+',targetCol.group(0))
nowPrice = matchPrice.group(0).replace(",","")

価格の部分を抜き出す為に、「正規表現」を用います。正規表現とは記号と文字で表現されたパターンを用いて文字列を検索する仕組みです。
正規表現を使うためには”re”というモジュールをimportします。

抜き出したい価格の部分は、htmlを調査してみると

<span class="priceLarge">¥ 3,905 - ¥ 6,615 </span>

の部分である事がわかりました。

と言う事で2行目では、パターンを使って文字列を検索するsearch()関数を使ってこの部分を抽出しています。

文字列の前にrをつけているのは、次の文字列はraw stringであるという事の宣言です。raw stringはエスケープシーケンスを無効にします。

正規表現では文字列中にエスケープ文字である”\”(バックスラッシュ)を多用しますので、通常の文字列だと正規表現で数字を表す”\d”を”\\d”としなければならず、冗長になるので最初からエスケープシーケンスを無効にしています。

正規表現のパターンとマッチした文字列はtargetColのMatch Objectにセットされます。こいつを取り出すにはgroup()関数を用います。引数の数値は複数のマッチが在った場合何番目のマッチ文字列を取り出すかの指定に使います。’priceLarge.*’パターンを使って

priceLarge">�� 3,905 - �� 6,615

を取り出します。さらにこの結果に対して’\d,\d+’のパターンを使って”3,905″を抜き出してカンマを削除して3905という数字を取り出しました。

これで価格を抜き出す事に成功です。

■ 3.過去と現在の価格を比較して処理

import commands
oldPrice = commands.getoutput('tail -1 /var/log/amazon/priceLog.txt')

mailCmd = 'echo "now price %s" | mail -s "price is changing"  example@gmail.com' %nowPrice
logCmd = 'echo %s >> /var/log/amazon/priceLog.txt' %nowPrice

if int(nowPrice) < int(oldPrice):
    commands.getoutput(mailCmd)

commands.getoutput(historyCmd)

ここでは価格を比較して、最新の価格が依然の価格よりやすかったらメールを発送するという処理を行います。
これらの実行にはLinuxシェルを使うのが簡単なので”commands”モジュールをimportします。

まず’/var/log/amazon/priceLog.txt’を作って、そこに今の価格を手入力します。
これを踏まえて、2行目ではoldPriceにpriceLogの最後の行の価格がはいってきます。
mailCmdにはLinuxでメールを送る用のコマンドを予めセット。
(Linux上でメールを使う方法は後日記事にアップします)
logCmdも同様、スクレイピングした価格をlogに追記する用のコマンドをセット。

7行目では現在価格が前回の価格よりも安ければ携帯にメールを送信。
最後に、価格をpriceLog.txtにセットしてます。

あとは30分毎にでも実行するようにcronにセットしてやれば、価格が下がった時にメールでお知らせが来るようになります。

最後にソース全文を置いておきます。

import urllib2
f = urllib2.urlopen('http://www.amazon.co.jp/%E3%82%A2%E3%83%87%E3%82%A3%E3%83%80%E3%82%B9-adidas-FORUM-G1654900-%E3%83%9B%E3%83%AF%E3%82%A4%E3%83%88/dp/B003TJ91L8/ref=wl_it_dp_o_piT1_nS_nC?ie=UTF8&colid=2NPMF5TUB79UB&coliid=ISBLWHXEIDBUX')
html = f.read()

import re
targetCol = re.search(r'priceLarge.*',html)
matchPrice = re.search(r'\d,\d+',targetCol.group(0))
nowPrice = matchPrice.group(0).replace(",","")

import commands
oldPrice = commands.getoutput('tail -1 /var/log/amazon/priceLog.txt')

mailCmd = 'echo "now price %s" | mail -s "price is changing"  example@gmail.com' %nowPrice
logCmd = 'echo %s >> /var/log/amazon/priceLog.txt' %nowPrice

if int(nowPrice) < int(oldPrice):
    commands.getoutput(mailCmd)

commands.getoutput(historyCmd)

余談:Ubuntuではファイルの作成日時がわからないのでアレなんですが2ヶ月くらい前から監視してて、最高価格6,615円の日がありましたが、最終的に3,900円くらいでゲットしました。

end

photo by: yukop