それマグで!

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

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

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 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 ドキュメント

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で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でファイル削除

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

os.remove

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

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

参考資料

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

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 ドキュメント

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