やっつけスクリプト。


はじめての方はこちらから

2014-01-10 ブログ移行しました。

2005-05-07

windows COMオブジェクトを操作する

win32allモジュールの中のwin32com.clientは、windowsのCOM(Component Object Model)オブジェクトを操作する拡張モジュール

Python Win32 Extensions(win32all)

http://starship.python.net/crew/mhammond/win32/Downloads.html

コレを使うことでWSHのように、オートメーション機能を持ったCOMオブジェクトPythonスクリプトから制御することができる。

IEExcelの作業を自動化するスクリプトなんかを書くときに便利。

(当然のことながらwin32comはwindows依存。)

>>> import win32com.client
>>> com = win32com.client.Dispatch("WScript.Shell")
>>> com.Run("notepad.exe")	#ノートパッド(メモ帳)の起動
0
>>>

参考:第5回 WshShellオブジェクトの詳細(1)

http://www.atmarkit.co.jp/fwin2k/operation/wsh05/wsh05_01.html

特殊フォルダパスを得る

WScript.ShellオブジェクトではSpecialFoldersプロパティを得ることができる。

このプロパティwindowsの特別なフォルダ(デスクトップやマイドキュメントなど)のパスを得ることができる。

>>> import win32com.client
>>> com = win32com.client.Dispatch("WScript.Shell")
>>> com.SpecialFolders("MyDocuments")		#マイドキュメントのパスを取得
u'C:\\My Documents'
>>> com.SpecialFolders("Favorites")		#「お気に入り」フォルダパスを取得
u'C:\\WINDOWS\\Favorites'
>>> com.SpecialFolders("Recent")		#「最近使ったファイル」のパスを取得
u'C:\\WINDOWS\\Recent'

windowsの使い捨てスクリプトを書くときに非常に便利。

参考:1.特殊フォルダの取得 ――SpecialFoldersプロパティ――

http://www.atmarkit.co.jp/fwin2k/operation/wsh06/wsh06_01.html

2005-05-04

webページをゲットする。

>>>import urllib2
>>>urlhandler = urllib2.urlopen("http://www.google.co.jp")
>>>html = urlhandler.read()

一行ずつ読み込む

>>>html = urlhandler.readline()

一行ずつリストに格納

>>>html = urlhandler.readlines()

User-Agentを指定してリクエスト

>>>import urllib2
>>>req = urllib2.Request("http://www.google.co.jp")
>>>req.add_header("User-agent", "python")
>>>urlhandler = urllib2.urlopen(req)

ヘッダーに色々追加してリクエスト

>>>import urllib2
>>>req = urllib2.Request("http://www.google.co.jp")
>>>req.add_header("User-agent", "python")
>>>req.add_header("Pragma", "no-cache")
>>>urlhandler = urllib2.urlopen(req)

プロクシを指定してリクエスト

>>>import urllib2
>>>req = urllib2.Request("http://www.google.co.jp")
>>>req.set_proxy("proxy.example.com:8080", "http")
>>>req.add_header("User-agent", "python")
>>>req.add_header("Pragma", "no-cache")
>>>site = urllib2.urlopen(req)

TCPWatchを使って、リクエストの中身を確認しながらテスト

http://hathawaymix.org/Software/TCPWatch

コマンドラインからTCPWatchを起動する。

c:>tcpwatch.py -p 127.0.0.1:3128

TCPWatchをset_proxyしてリクエストを飛ばす

>>>import urllib2
>>>req = urllib2.Request("http://www.google.co.jp")
>>>req.set_proxy("127.0.0.1:3128", "http")
>>>req.add_header("User-agent", "python")
>>>req.add_header("Pragma", "no-cache")
>>>site = urllib2.urlopen(req)

文字コードの推測

>>>import pykf
>>>string = "あいうえお"
>>>print pykf.guess(string)
2
対応表

    ASCII = 1
    ERROR = -1
    EUC = 3
    JIS = 4
    SJIS = 2
    UNKNOWN = 0
    UTF16 = 7
    UTF16_BE = 8
    UTF16_LE = 7
    UTF8 = 5
|< 
		

文字コード変換

>>>import pykf
>>>import urllib
>>>url = "http://www.yahoo.co.jp" 
>>>urlhandler = urllib.urlopen(url)
>>>html = urlhandler.read()
>>>html = pykf.tosjis(html, pykf.EUC) 
>>>print html

yahooページの文字コードは「EUC」なので「SJIS」に変換する

html = pykf.tosjis(html, pykf.EUC) 

元データの文字コードが判らないときは自動判別

html = pykf.tosjis(html)  

日本語正規表現を使う

Shift-jisでは値にバックスラッシュ(=0x5c)が含まれる場合がある。(例えば"表"の字)

Pythonではバックスラッシュはエスケープ文字として扱われるので、そのような文字が正規表現パターンに含まれていると意図しない結果となる。

文字列をいったんunicodeに変換することで、この問題を回避できる。

▼例1

>>> ================================ RESTART ================================
>>> import re
>>> string = "表示できますか"
>>> print re.sub('表示', "お願い", string)
表示できますか			#ちゃんと変換されない
>>> patten = "表示"
>>> print re.sub(patten.decode("shift-jis"), "お願い",string.decode("shift-jis"))
お願いできますか			#ちゃんと変換されている

▼例2(yahooから取得したソース正規表現でサーチする。)

 環境:Yahooのページはeuc-jpPython Shellはshift-jis

 対象となる文字データ(ここでは変数html)の文字コードが解っている事を前提。

>>> ================================ RESTART ================================
>>> import urllib2
>>> urlhandler = urllib2.urlopen("http://www.yahoo.co.jp/")
>>> html = urlhandler.read()
>>> import re
>>> pattern = "免責事項"
>>> print re.search(pattern.decode("shift-jis"), html.decode("euc_jp")).group()
免責事項

参考:日本語環境でのPython (for Python 2.3 or later)

http://www.python.jp/Zope/articles/japanese/Python4Japanese-2

リンク先では、unicode関数を使っているのだけれど、個人的には文字列のメソッドに統一した方が美しい気がする。

(まぁ、気分の問題)

>>> ================================ RESTART ================================
>>> string = "表示できますか"
>>> unicode(string, "shift-jis")
u'\u8868\u793a\u3067\u304d\u307e\u3059\u304b'
>>> string.encode("shift-jis")
'表示できますか'
>>> ================================ RESTART ================================
>>> string = "表示できますか"
>>> string.decode("shift-jis")
u'\u8868\u793a\u3067\u304d\u307e\u3059\u304b'
>>> string.encode("shift-jis")
'表示できますか'

参考:2.3.6.1 文字列メソッド

http://www.python.jp/doc/release/lib/string-methods.html#l2h-175

2005-04-20

起動時の引数(args)解析

optparse*モジュールを使って起動時の引数の解析を行う基本。

[argsOp.py]

#!/bin/env python
# -*- coding: shift_jis -*-
import sys
from optparse import OptionParser

#引数の設定
parser = OptionParser()
parser.add_option("-f", "--file", dest="fileName",help="ファイル名指定", metavar="FILE")
parser.add_option("-v", action="store_true", dest="ver" )
parser.add_option("-q", action="store_false", dest="ver" )

#引数の取得
(options, args) = parser.parse_args()

#取得した引数の表示
print  "fileName:" , options.fileName
print  "ver     :" , options.ver
print  "args    :" , args

色々な引数を与ながら起動して試してみる

:\Python23jp>argsOp.py
fileName: None
ver     : None
args    : []

C:\Python23jp>argsOp.py -h
usage: argsOp.py [options]

options:
  -h, --help           show this help message and exit
  -fFILE, --file=FILE  ファイル名指定
  -v
  -q

C:\Python23jp>argsOp.py -f test.txt
fileName: test.txt
ver     : None
args    : []

C:\Python23jp>argsOp.py -q -ftest.txt
fileName: test.txt
ver     : False
args    : []

C:\Python23jp>argsOp.py -ftest.txt -v
fileName: test.txt
ver     : True
args    : []

C:\Python23jp>argsOp.py -ftest.txt -v aaa
fileName: test.txt
ver     : None
args    : ['aaa']

C:\Python23jp>argsOp.py -v aaa -ftest.txt ccc bbb
fileName: test.txt
ver     : True
args    : ['aaa', 'ccc', 'bbb']

引数を設定した時のデータをもとに-h,-helpは自動的に作ってくれるらしい

2005-04-18

ファイルダウンロード

連番を開くスクリプトを書いたので、せっかくだから開いたurlからファイルダウンロードするスクリプトをつくってみようかと思ったのだけれど巧くいかない。

urllibのリファレンス

urlretrieve( url[, filename[, reporthook[, data])

URL で表されるネットワーク上のオブジェクトを、必要に応じてローカルファイルコピーします

ってあったので使ってみたのだけれど、コレ、404ファイルダウンロード(?)してきちゃう。

指定したurlが間違っていても気付かない。困った。

とりあえず、吐き出すモンぜんぶ吐き出させて指定したurlファイル有無を判定できるか調べてみる。

#!/bin/env python
# -*- coding: shift_jis -*-
import urllib

def feedback(count,size, total):
    print "count :%d" % count
    print "size  :%d" % size
    print "total :%d" % total

(file, header) = urllib.urlretrieve("http://www.google.co.jp/","test.html",feedback)
print file
print header 

feedback ダウンロードレポート(ブロックのカウントとサイズ、トータル)

file   指定したファイル

header HTTP応答ヘッダ

応答ヘッダで判定すればいいのかな?

とりあえずググッてみたら、外人さんのソースにこんなのがあった。

(tmp, headers) = urllib.urlretrieve("http://www.google.co.jp/","test.html")
if str(headers).count("Content-Length") == 0:
    print "ERROR: File not found (404 error)"

headersの中のContent-Lengthの数を数えて、それが0だったら404エラーと判定しているみたい。

でも、これだとContent-Lengthさえ応答ヘッダに含まれていればやっぱり存在しないファイルでもダウンロードしてきちゃうよ〜ん

とりあえず試してみた

#!/bin/env python
# -*- coding: shift_jis -*-
import urllib

(tmp, headers) = urllib.urlretrieve("http://www.google.co.jp/aa/bb/cc.gif","test.gif")
print str(headers).count("Content-Length")
print headers
if str(headers).count("Content-Length") == 0:
   print "ERROR: File not found (404 error)"
else:
   print "OK"

ちゃんと"ERROR: File not found (404 error)"がでた。

でも、よく見るとgoogleの応答ヘッダには「Content-length: 1223」とある。

う〜ん「Length」では「length」をカウントしないので404を出してしまう。やっぱり駄目ジャン。

要再考。

追記urllib2モジュールでは、ちゃんと404を検出するらしい。

>>> import urllib
>>> urllib.urlopen("http://www.google.co.jp/aa/bb/cc.gif")
<addinfourl at 11485272 whose fp = <socket._fileobject object at 0x00AEEB58>>
>>> import urllib2
>>> urllib2.urlopen("http://www.google.co.jp/aa/bb/cc.gif")

Traceback (most recent call last):
  File "<pyshell#7>", line 1, in -toplevel-
    urllib2.urlopen("http://www.google.co.jp/aa/bb/cc.gif")
  File "c:\Python23\lib\urllib2.py", line 129, in urlopen
    return _opener.open(url, data)
  File "c:\Python23\lib\urllib2.py", line 326, in open
    '_open', req)
  File "c:\Python23\lib\urllib2.py", line 306, in _call_chain
    result = func(*args)
  File "c:\Python23\lib\urllib2.py", line 901, in http_open
    return self.do_open(httplib.HTTP, req)
  File "c:\Python23\lib\urllib2.py", line 895, in do_open
    return self.parent.error('http', req, fp, code, msg, hdrs)
  File "c:\Python23\lib\urllib2.py", line 352, in error
    return self._call_chain(*args)
  File "c:\Python23\lib\urllib2.py", line 306, in _call_chain
    result = func(*args)
  File "c:\Python23\lib\urllib2.py", line 412, in http_error_default
    raise HTTPError(req.get_full_url(), code, msg, hdrs, fp)
HTTPError: HTTP Error 404: Not Found
>>> 

ちゃんと例外がでる、urllib2を使ったほうがいいみたい。

※参考

urllib.urlopen() fails to raise exception

http://mail.python.org/pipermail/python-bugs-list/2004-July/023990.html