それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

imagemagick で画像を回転する

スキャナの画像を回転するなど

mogrify -rotate 180 hoge.jpg

mogrify は元のファイルを上書きするコマンド

回転角度は、右回り

向きを修正したり回転角度を修正したりするのに使える

マイナス90度回転するなら 360-90 = 270

mogrify -rotate 270 hoge.jpg

これでOK.

convert コマンドでも

convert コマンドでも同じこと

mogrify -rotate 270 hoge.jpg out.jpg

画像をタイル状に敷き詰めるコマンド

画像をタイル状に敷き詰めるには、montage コマンドが便利です。

## 画像を100枚取得してー
for i in {1..100} ; wget https://www.a8.net/a8v2/jcaptcha ; done
## 10x10に敷き詰める
montage jcaptcha.* -tile 10x10 -geometry 200x60+1+1 out.jpg

montage コマンド

montage jcaptcha.*.jpg -tile 10x10 -geometry 200x60+1+1 out.jpg
  • tile で縦横の枚数を指定
  • geometry はmagick のいつも通り、元画像の何処を取り出すか。
  • *.jpg は bashの引数展開
  • out.jpg は出力ファイル名

こんな感じ

簡単ですね

飾りじゃないのよCapthcaは。いまどきカウンタですか。

A8 . n e t のキャプチャがヒドイ。

彼女のクレジットカードを作るために、アフィリエイトでもやろうかと思ってA8のパスワードリマインダーをかけたらこれがヒドイの

cap cap2

これ、、、キャプチャじゃない・・・

こういうのは、昔からのカウンタじゃないですか

キャプチャ画像は次のURLから取得される。

https://www.a8.net/a8v2/jcaptcha

キャプチャの画像のサンプル一覧

見て分かる通り、文字の幅が決まっている、フォントサイズが固定。これでは簡単に解析ができますね。っていうかこのキャプチャなら付ける意味が無い。飾りにすらなってない。

縦に見たらこんな感じ

あー幅にゆらぎが無いですわ。せめてもう少し乱数調整を見なおしたほうが。。。

文字のベースラインも

ベースラインも揃ってますわ・・・せめて上下にずれてたら、、、、

飾りじゃないのよキャプチャは。

こんなもの、2006年の段階で、だめじゃんって高木先生も書いてる。

高木浩光@自宅の日記 - 飾りじゃないのよCAPTCHAは 〜前代未聞のCAPTCHAもどき, CAPTCHA機能の発注仕様をどうするか

余白がホワイトも良くない

余白が真っ白だから、 magick コマンドで1秒でサイズを統一できてしまう。

キャプチャのURLって固定だめじゃ?

https://www.a8.net/a8v2/jcaptcha このURLにアクセスると、Cookieが発行される。Cookieなしでキャプチャ出てるくるのは簡単に突破しろと言ってるような。。。

パスワードは6−10文字!!

6-10

パスワードの最大文字数決まってるの!!

パスワードの文字数に制限がある=パスワードを平文保存ってことですよね。

ハッシュ化してりゃ文字数制限なんてないものね。。。

ああ、これ以上何も言うまい。。

さらにさらに、誤安心のPマーク

何も言わないつもりだったけど、運営母体は、東証一部銘柄だとわかった。

p-mark

はいきた、「誤」安心のPマーク。ほんとうにPマークってなんのためにあるんでしょうね。

A8.n e t のプログラマさんは・・・

わかっててやってるのか、知らずにやってるのか。エンジニアの良心は無いのだろうか。

もう、これは高木先生の案件ですかね・・

上場企業なんだったら、高木先生案件ですかね。

2014-09-04 追記

東証一部銘柄だったので、いろいろと追加。

WEBページの更新があれば、通知センタで通知する。

WEBページの更新をチェックするのが面倒なので、チェッカーにする

curl を呼び出す。

curl でページ取得して、md5sum にかけて、ハッシュ値チェックする。

もっと簡単にlast-modified や modified Etag 使ってもいんだけど、汎用性考えたら、md5sumかな。

Cookie

Cookieの処理あ、 chromecurl コマンド取得すればいい。

hoge

これで、Cookie付きのCurlコマンド取得できる。

通知

osascript -e 'display notification "更新あったよ。"'

osascript で、簡単に通知が出せる。超楽ちん

チェッカー

#!/usr/bin/env ruby 
#


cmd = "curl -s  'http://xxxx.example.gr.jp/score/index' "+
          " -H 'DNT: 1' -H 'Accept-Encoding: gzip,deflate,sdch' -H 'Accept-Language: en,ja;q=0.8' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2138.3 Safari/537.36' "+
        "-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Referer: http://score.2014su.nsc.gr.jp/score/detail/scenario_id/85' -H 'Cookie: EID=XXXXXXXXXXXX-1sEXIOa' -H 'Connection: keep-alive' "+
        "-H 'Cache-Control: max-age=0' --compressed "
     +"| md5sum"

last_id = `#{cmd}`

loop{
    ret = `#{cmd}`
    puts  ret 
   
    if last_id != ret 
    `osascript -e 'display notification "更新あったよ。"'`
    end

    last_id = ret

    sleep 10

}

更新チェッカーくらいパパっと

更新チェッカーとか、データのバックアップとかミラーとか、そういうのは10分位で書いてパパっと解決したいよね。

ソフトググってインストールしてる時間のほうが勿体ないとか言えるように

以前作ったのはこれ。

通知をメールにしたり、Growlにしたり、iPhoneにプッシュしたり色々と楽しいよ。

WEBページの更新チェッカー - それマグで!

xmlを扱う xmllint コマンドで xpath

xpath 大好きっ娘 な takuya です。こんばんは。

xpath をもっと手軽に扱いたい

xpath を扱うには、libxm2やlibxsltをrubypython から使ってたんですが。phpxpath は微妙だし。

コマンドラインから使おうと思ってコマンド書き始めてたら、すでにコマンドが用意されてるんですね。

xmllint コマンド

xmllint コマンドというものがあります。引数に --xpath をつけるとxpathを使えます。

takuya@rena:~/Desktop$ echo "<a><b><c>cccc</c></b></a>" | xmllint  --xpath "//c/text()"  - 
cccc

linuxOSX は標準装備

osx の場合は、最初から入ってる

takuya@osx:~/Desktop$ which xmllint
/usr/bin/xmllint

debianなどLinuxでも最初から入ってる。

takuya@debian:~$ which xmllint
/usr/bin/xmllint

どの環境でも使えるならとっても便利ですね!。

HTML を使う

html を扱うときは --html をつける

xmllint  --html  --xpath "//input"  -

HTMLは厳格な仕様で書かれていることが少ないので、Warningが大量に出る。これはSTDERRに出るので無視できる。

xmllint  --html  --xpath "//input[@name='post_id']/@value" - 2>/dev/null

2014-09-05 修正

標準入力 STDIN から受けるときは、 - を末尾に置かないと動かなかったの

2023-05-23 修正

html を扱うときにフラグが必要になっていた。

みんな大好き!man ページ

xmllint はその名の通りlint なので、奥が深いプログラムですね。

手軽にXpathを扱うxpath コマンド

OSX には、xpath というPerlで書かれてるコマンドがついてくる。

xpath コマンド。

takuya@rena:~/Desktop$ echo "<a><b><c>cccc</c></b></a>" | xpath "//c/text()"
Found 1 nodes:
-- NODE --
cccc

このように簡単にXpathを使って試すことが出来る。便利!

xpath コマンドは次の場所に

takuya@rena:~/Desktop$ which xpath
/usr/bin/xpath

実体は perl

takuya@rena:~/Desktop$ head /usr/bin/xpath -n 20
#!/usr/bin/perl

=for comment

The contents of this script should normally never run!  The perl wrapper
should pick the correct script in /usr/bin by appending the appropriate version.
You can try appending the appropriate perl version number.  See perlmacosx.pod
for more information about multiple version support in Mac OS X.

=cut

use strict;
use Config ();

my @alt = grep {m,^$0\d+\.\d+(?:\.\d+)?$,} glob("$0*");
print STDERR <<"EOF-A";
perl version $Config::Config{version} can't run $0.  Try the alternative(s):

EOF-A
if(scalar(@alt) > 0) {

うーん。便利だけど出力が気に入らないから、作ったほうが速いような。

Radikoの再生&録音スクリプトをPythonで書きなおした

Radikoの録音スクリプトBashで書かれていて、どういう仕組みか気になったので、Pythonで描き直ししつつ、Pythonでシェル・スクリプトを代用するために、いろいろ調べみた。

元になったBashのシェル・スクリプト

https://gist.github.com/matchy2/3956266

python で書きなおしたシェル・スクリプト

play_radiko_by_mplayer.py

いろいろ勉強になる

radikoの録音スクリプトは、スクリプトの基本要素がいっぱい入っていて、すごく勉強になる。

  • スクリプト引数チェック
  • ファイル作成・保存
  • ファイル削除
  • ファイル読み込み
  • ファイルの任意のバイトを読み込み
  • URLにHTTP GETアクセス
  • HTTP POSTでアクセス
  • プロセス起動
  • コマンド実行
  • xmlxpath でパース

プログラム書くときの基本がシッカリ入ってて勉強にはなかなかいいと思った。しかも、プログラムの実行結果が「音が再生される」という五感でわかりやすいプログラムなので、動いた時はやっぱり嬉しい。

Python以外でもRubyやNode、PHPなどでも書きなおしてみたらいいのじゃないのかな。

ラジコエラー

SSLのverify が出来なくてエラーで落ちてた

SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed

import ssl
ssl._create_default_https_context = ssl._create_unverified_context

pythonで文字列埋め込み変数

pythonって文字列に変数を埋め込むのには

% 記法のテンプレート文字列を使う。

name = "takuya"
print " hello %s " % name

名前付きのテンプレート文字列を使う

print " hello %(name)s " % { "name":"takuya" } ## %s の名前付きってことで %(varname)s

変数を直接埋めたい?

format を使うと実現できる。

name = "takuya"
print " hello {name} ".format (**vars())

正直なところvars でガッツリ埋め込みもちょっと怖いんだけど。よく考えたら、PHPRubyもガッツリ埋め込みだからいいか。

参考資料

5. 組み込み型 — Python 2.7.x ドキュメント

文字列(4) - バリケンのPython日記 - pythonグループ

7.1. string — 一般的な文字列操作 — Python 2.7.x ドキュメント

pythonでファイル削除

Pythonファイルシステムからファイルを消すには

os.remove

import os
os.remove("/tmp/my_temp_file")

簡単ですね。os モジュールにあるので、os.remove とモジュール名をつけるのがちょっと嫌だけど

参考資料

15.1. os — 雑多なオペレーティングシステムインタフェース — Python 2.7ja1 documentation

pythonでhttpリクエスト-POST

python で http リクエストをPOSTする。

curlwget をシェル・スクリプトで呼び出してもいいんだけど、urllib/urllib2 を使う方法も実現可能なのです。

import urllib
import urllib2
response ={}
url = "https://radiko.jp/v2/api/auth2_fms"
headers ={
  "pragma":"no-cache",
}
try :
  params = urllib.urlencode({'name':1, 'item_id':2})
  req = urllib2.Request(url, params ,headers )
  res = urllib2.urlopen(req)
  #print res.read()
  response["body"] = res.read()
  response["headers"] =  res.info().dict
except URLError, e:
  print e
  exit()

print   response["body"]

urllib は リクエストには使わないのですが、リクエストパラメータをURLエンコードするのに必須になるので使っている。

レスポンスのヘッダはres.info()で取れるのですが、dict形式にならないので、明示的に

res.info().dict

として取り出している。

POSTだけでパラメーターはなし。

POSTでリクエストだけ送って、本文は空っぽの場合は、改行を送ればいい。

  req = urllib2.Request(url, "\r\n" ,headers )

参考資料

urllib, urllib2を使ってGET/POST - YAMAGUCHI::weblog

pythonでファイルの指定場所の指定バイトを読み込むには

あるファイルの一部分を取り出して、保存するには、ddするのが手っ取り早い

dd でファイルから部分を取り出す。

offset=223
length=1024
partialkey=`dd if=test.swf bs=1 skip=${offset} count=${length} 2> /dev/null `

python でファイルを扱えば同じことが出来る。

ファイルをopen してseek して、read する。

offset = 223
length = 1024

f = open("test.swf", 'rb+')
f.seek(offset)
data = f.read(length)

ファイルの中身をseek するだけなので、結構簡単ですね。

参考資料

7. Input and Output — Python v2.7.8 documentation

pythonでコマンド実行するには

シェルスクリプトの代わりにPythonで書いてみる

コマンド実行をする

コレを使います。

import subprocess
import shlex
ret = subprocess.check_output(shlex.split("date -I")).decode("UTF-8").strip()
print(ret)

詳しく書いていきます。

subprocess モジュールを使う

subprocess はコマンド実行がちょっと面倒臭い。

import subprocess

input_f   = "player.swf"
output_f = "radiko.png"

cmd = "/usr/local/bin/swfextract -b 14 %s -o %s" % (input_f, output_f )
subprocess.call( cmd.strip().split(" ")  ) 

subpcorcess.call は配列でコマンドとコマンドの引数を与える。 面倒なので、コマンド文字列を作ってから、split(" ") で文字列を分割して配列にしたら楽かも。

シェル経由で実行する

シェル経由で実行すると楽ちんですよね。

bash の場合

バッククォート演算子を使って文字列を囲うだけで出来る。

`wget -O index.html http://www.yahoo.co.jp `

python をシェル経由で実行するには

call に shell=True のキーワード引数をつけるだけ。

import subprocess
cmd = "ls -lt | head -n 5"
subprocess.call( cmd, shell=True  ) 

これで、シェル経由実行される

subprocess.call([cmd,arg1,arg2..], shell=True)は 旧来のos.system の実行と同じ

import os
cmd = "ls -lt "
os.system( cmd )

os.system はすでにサポートされなくなりつつあるので、subprocessを使う方がいいようです。

シェル経由とは

シェル経由で実行するとは、こういうこと。

sh -c "コマンド"

のように、sh -c をつけて実行していることに相当する。

コマンドの文字列をそのまま渡せるので、Shell=Trueを使う人が多いとは思います。

コマンドの実行結果を取得したい

bash なら

ret=`ls -lt `
echo $ret

とするだけなのですが。

python のsubprocess モジュールで実行するには、check_outputを使う

import subprocess
cmd = "ls -lt "
ret  =  subprocess.check_output( cmd.split(" ") )
print ret

コマンドの実行終了をチャント待つには

check_callを使う。

import subprocess
cmd = "ls -lt "
ret  =  subprocess.check_call( cmd.split(" ") )
print ret == 0

実行結果が正常終了なら0がかえってくる。

call でパイプラインをチャント渡すには。

subprocessにシェル経由実行するように渡すと、パイプラインでもシッカリ処理してもらえる。

import subprcoess
cmd = "ls -lt | head -n 5"
subprocess.call( cmd , shell=True )

非シェル経由で呼び出すには。

subprocess のPIPEとstdoutを使うと実現できる。

cmd1 = "ls -lt "
cmd2 = "head -n 5 "
p1 = subprocess.Popen(cmd1.strip().split(" "), stdout=subprocess.PIPE)
p2 = subprocess.Popen(cmd2.strip().split(" "), stdin=p1.stdout)
p1.stdout.close()
output = p2.communicate()[0]

非シェル経由の場合コマンドの実行をパイプ経由で送るには、ちょっと面倒臭い手続きが必要になる。

最後の2行はおまじない

p1.stdout.close()
output = p2.communicate()[0]

これを書くことで、Python の実行を CTRL+C をで止めた時に、サブプロセスがちゃんと終了してくれる。書かないとゴーストで残る。時間のかかる処理をしていると怖い。

ただ、シェル経由しない実行は、コマンド・インジェクション対策などで使えるので重要なテクニックになると思う。

2016-06-28追記

spawn という名前はイメージしやすかったけどなくなりました。

2018-09-18

参考資料

15.1. os — 雑多なオペレーティングシステムインタフェース — Python 2.7.14 ドキュメント

17.1. subprocess — サブプロセス管理 — Python 2.7.14 ドキュメント

URLにアクセス & ファイルを保存する(http get)

Python でURLにアクセスしてファイルを保存するには urlib2 を使うのが手っ取り早い

import os
import urllib2

file_name = "yahoo.co.jp.html"
url  = "http://www.yahoo.co.jp"

if os.path.exists( file_name ) :
  try :
    body = urllib2.urlopen( url ).read()
    f = open( file_name,  "w" )
    f.write(body)
    f.close()
  except URLError, e:
    print e
    exit()

print "end"

pythonwget を起動してもいいんだけど、ここは敢えて urllib2 を使ってまみした。

python でシェル・コマンド呼び出しは、ちょっとだけ面倒なので、ここはurllib2を使いました。

ファイルに保存するには

f = open( file_name,  "w" )
f.write(body)
f.close()

これだけですね。簡単。

bashwget でやる場合

file_name="yahoo.co.jp.html"
url="http://www.yahoo.co.jp"

if [ ! -f $file_name ]; then
  wget -q -O $file_name $url

こうやってみると、wgetbashシェルスクリプトで呼び出すのはとっても手軽ですね。

pythonで引数を取得する。

pythonスクリプトを作って引数を取りたいときに引数の個数を取得するには。

import sys
if len(sys.argv) < 3  :
  print "引数が足りません"
  exit()

print sys.argv

実際に実行してみた結果

takuya@rena:~/Desktop$ python test.py  aaa
引数が足りません
takuya@rena:~/Desktop$ python test.py  aaa bbb
['test.py', 'aaa', 'bbb']
takuya@rena:~/Desktop$ python test.py  aaa bbb ccc
['test.py', 'aaa', 'bbb', 'ccc']

例に漏れずARGV[0] は自分自身のファイル名を示すことになります。

bashの場合

if [ $# -ge 2 ]; then
  echo "引数が足りません"
  exit()
fi