本章涉及標準庫:html
一、sys
node
二、ospython
三、globlinux
四、mathweb
五、randomchrome
六、platform
shell
七、pikle與cPiklejson
八、subprocessubuntu
九、Queuewindows
十、StringIO
十一、logging
十二、ConfigParser
1三、urllib與urllib2
1四、json
1五、time
1六、datetime
10.1 sys
1)sys.argv
命令行參數。
argv[0] #表明自己名字
argv[1] #第一個參數
argv[2] #第二個參數
argv[3] #第三個參數
argv[N] #第N個參數
argv #參數以空格分隔存儲到列表。
看看使用方法:
#!/usr/bin/python# -*- coding: utf-8 -*-import sysprint sys.argv[0]print sys.argv[1]print sys.argv[2]print sys.argv[3]print sys.argvprint len(sys.argv)# python test.pytest.py a b c c['test.py', 'a', 'b', 'c']4
值得注意的是,argv既然是一個列表,那麼能夠經過len()函數獲取這個列表的長度從而知道輸入的參數數量。能夠看到列表把自身文件名也寫了進去,因此當咱們統計的使用應該-1纔是實際的參數數量,所以能夠len(sys.argv[1:])獲取參數長度。
2)sys.path
模塊搜索路徑。
>>> sys.path['', '/usr/local/lib/python2.7/dist-packages/tornado-3.1-py2.7.egg', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages']
輸出的是一個列表,裏面包含了當前Python解釋器所能找到的模塊目錄。
若是想指定本身的模塊目錄,能夠直接追加:
>>> sys.path.append('/opt/scripts')>>> sys.path['', '/usr/local/lib/python2.7/dist-packages/tornado-3.1-py2.7.egg', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/opt/scripts']
3)sys.platform
系統平臺標識符。
系統 | 平臺標識符 |
Linux | linux |
Windows | win32 |
Windows/Cygwin | cygwin |
Mac OS X | darwin |
>>> sys.platform
'linux2'
Python自己就是跨平臺語言,但也不就意味着全部的模塊都是在各類平臺通用,因此可使用這個方法判斷當前平臺,作相應的操做。
4)sys.subversion
在第一章講過Python解釋器有幾種版本實現,而默認解釋器是CPython,來看看是否是:
>>> sys.subversion('CPython', '', '')
5)sys.version
查看Python版本:
>>> sys.version'2.7.6 (default, Jun 22 2015, 17:58:13) \n[GCC 4.8.2]'
6)sys.exit()
退出解釋器:
#!/usr/bin/python# -*- coding: utf-8 -*-import sysprint "Hello world!"sys.exit()print "Hello world!"# python test.pyHello world!
代碼執行到sys.exit()就會終止程序。
7)sys.stdin、sys.stdout和sys.stderr
標準輸入、標準輸出和錯誤輸出。
標準輸入:通常是鍵盤。stdin對象爲解釋器提供輸入字符流,通常使用raw_input()和input()函數。
例如:讓用戶輸入信息
#!/usr/bin/python# -*- coding: utf-8 -*-import sys name = raw_input("Please input your name: ")print name# python test.pyPlease input your name: xiaoming xiaoming
import sysprint "Please enter your name: "name = sys.stdin.readline()print name# python b.pyPlease enter your name:xiaoming xiaoming
再例如,a.py文件標準輸出做爲b.py文件標準輸入:
# cat a.pyimport sys sys.stdout.write("123456\n")sys.stdout.flush()# cat b.pyimport sysprint sys.stdin.readlines()# python a.py | python b.py['123456\n']
sys.stdout.write()方法其實就是下面所講的標準輸出,print語句就是調用了這個方法。
標準輸出:通常是屏幕。stdout對象接收到print語句產生的輸出。
例如:打印一個字符串
#!/usr/bin/python# -*- coding: utf-8 -*-import sysprint "Hello world!"# python test.pyHello world!
sys.stdout是有緩衝區的,好比:
import sysimport timefor i in range(5): print i, # sys.stdout.flush() time.sleep(1)# python test.py0 1 2 3 4
本是每隔一秒輸出一個數字,但如今是循環完纔會打印全部結果。若是把sys.stdout.flush()去掉,就會沒執行到print就會刷新stdout輸出,這對實時輸出信息的程序有幫助。
錯誤輸出:通常是錯誤信息。stderr對象接收出錯的信息。
例如:引起一個異常
>>> raise Exception, "raise..."Traceback (most recent call last):File "<stdin>", line 1, in <module>Exception: raise...
10.2 os
os模塊主要對目錄或文件操做。
方法 | 描述 | 示例 |
os.name | 返回操做系統類型 | 返回值是"posix"表明linux,"nt"表明windows |
os.extsep | 返回一個"."標識符 | |
os.environ | 以字典形式返回系統變量 | |
os.devnull | 返回/dev/null標識符 | |
os.linesep | 返回一個換行符"\n" | >>> print "a" + os.linesep + "b" a b |
os.sep | 返回一個路徑分隔符正斜槓"/" | >>> "a" + os.sep + "b" 'a/b' |
os.listdir(path) | 列表形式列出目錄 | |
os.getcwd() | 獲取當前路徑 | >>> os.getcwd() '/home/user' |
os.chdir(path) | 改變當前工做目錄到指定目錄 | >>> os.chdir('/opt') >>> os.getcwd() '/opt' |
os.mkdir(path [, mode=0777]) | 建立目錄 | >>> os.mkdir('/home/user/test') |
os.makedirs(path [, mode=0777]) | 遞歸建立目錄 | >>> os.makedirs('/home/user/abc/abc') |
os.rmdir(path) | 移除空目錄 | >>> os.makedirs('/home/user/abc/abc') |
os.remove(path) | 移除文件 | |
os.rename(old, new) | 重命名文件或目錄 | |
os.stat(path) | 獲取文件或目錄屬性 | |
os.chown(path, uid, gid) | 改變文件或目錄全部者 | |
os.chmod(path, mode) | 改變文件訪問權限 | >>> os.chmod('/home/user/c/a.tar.gz', 0777) |
os.symlink(src, dst) | 建立軟連接 | |
os.unlink(path) | 移除軟連接 | >>> os.unlink('/home/user/ddd') |
urandom(n) | 返回隨機字節,適合加密使用 | >>> os.urandom(2) '%\xec' |
os.getuid() | 返回當前進程UID | |
os.getlogin() | 返回登陸用戶名 | |
os.getpid() | 返回當前進程ID | |
os.kill(pid, sig) | 發送一個信號給進程 | |
os.walk(path) | 目錄樹生成器,返回格式:(dirpath, [dirnames], [filenames]) | >>> for root, dir, file in os.walk('/home/user/abc'): ... print root ... print dir ... print file |
os.statvfs(path) | ||
os.system(command) | 執行shell命令,不能存儲結果 | |
popen(command [, mode='r' [, bufsize]]) | 打開管道來自shell命令,並返回一個文件對象 | >>> result = os.popen('ls') >>> result.read() |
os.path類用於獲取文件屬性。
os.path.basename(path) | 返回最後一個文件或目錄名 | >>> os.path.basename('/home/user/a.sh') 'a.sh' |
os.path.dirname(path) | 返回最後一個文件前面目錄 | >>> os.path.dirname('/home/user/a.sh') '/home/user' |
os.path.abspath(path) | 返回一個絕對路徑 | >>> os.path.abspath('a.sh') '/home/user/a.sh' |
os.path.exists(path) | 判斷路徑是否存在,返回布爾值 | >>> os.path.exists('/home/user/abc') True |
os.path.isdir(path) | 判斷是不是目錄 | |
os.path.isfile(path) | 判斷是不是文件 | |
os.path.islink(path) | 判斷是不是連接 | |
os.path.ismount(path) | 判斷是否掛載 | |
os.path.getatime(filename) | 返回文件訪問時間戳 | >>> os.path.getctime('a.sh') 1475240301.9892483 |
os.path.getctime(filename) | 返回文件變化時間戳 | |
os.path.getmtime(filename) | 返回文件修改時間戳 | |
os.path.getsize(filename) | 返回文件大小,單位字節 | |
os.path.join(a, *p) | 加入兩個或兩個以上路徑,以正斜槓"/"分隔。經常使用於拼接路徑 | >>> os.path.join('/home/user','test.py','a.py') '/home/user/test.py/a.py' |
os.path.split( | 分隔路徑名 | >>> os.path.split('/home/user/test.py') ('/home/user', 'test.py') |
os.path.splitext( | 分隔擴展名 | >>> os.path.splitext('/home/user/test.py') ('/home/user/test', '.py') |
10.3 glob
文件查找,支持通配符(*、?、[])
# 查找目錄中全部以.sh爲後綴的文件>>> glob.glob('/home/user/*.sh')['/home/user/1.sh', '/home/user/b.sh', '/home/user/a.sh', '/home/user/sum.sh']# 查找目錄中出現單個字符並以.sh爲後綴的文件>>> glob.glob('/home/user/?.sh')['/home/user/1.sh', '/home/user/b.sh', '/home/user/a.sh']# 查找目錄中出現a.sh或b.sh的文件>>> glob.glob('/home/user/[a|b].sh')['/home/user/b.sh', '/home/user/a.sh']
10.4 math
數字處理。
下面列出一些本身決定會用到的:
方法 | 描述 | 示例 |
math.pi | 返回圓周率 | >>> math.pi 3.141592653589793 |
math.ceil(x) | 返回x浮動的上限 | >>> math.ceil(5.2) 6.0 |
math.floor(x) | 返回x浮動的下限 | >>> math.floor(5.2) 5.0 |
math.trunc(x) | 將數字截尾取整 | >>> math.trunc(5.2) 5 |
math.fabs(x) | 返回x的絕對值 | >>> math.fabs(-5.2) 5.2 |
math.fmod(x,y) | 返回x%y(取餘) | >>> math.fmod(5,2) 1.0 |
math.modf(x) | 返回x小數和整數 | >>> math.modf(5.2) (0.20000000000000018, 5.0) |
math.factorial(x) | 返回x的階乘 | >>> math.factorial(5) 120 |
math.pow(x,y) | 返回x的y次方 | >>> math.pow(2,3) 8.0 |
math.sprt(x) | 返回x的平方根 | >>> math.sqrt(5) 2.2360679774997898 |
10.5 random
生成隨機數。
經常使用的方法:
方法 | 描述 | 示例 |
random.randint(a,b) | 返回整數a和b範圍內數字 | >>> random.randint(1,10) 6 |
random.random() | 返回隨機數,它在0和1範圍內 | >>> random.random() 0.7373251914304791 |
random.randrange(start, stop[, step]) | 返回整數範圍的隨機數,並能夠設置只返回跳數 | >>> random.randrange(1,10,2) 5 |
random.sample(array, x) | 從數組中返回隨機x個元素 | >>> random.sample([1,2,3,4,5],2) [2, 4] |
10.6 platform
獲取操做系統詳細信息。
方法 | 描述 | 示例 |
platform.platform() | 返回操做系統平臺 | >>> platform.platform() 'Linux-3.13.0-32-generic-x86_64-with-Ubuntu-14.04-trusty' |
platform.uname() | 返回操做系統信息 | >>> platform.uname() ('Linux', 'ubuntu', '3.13.0-32-generic', '#57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014', 'x86_64', 'x86_64') |
platform.system() | 返回操做系統平臺 | >>> platform.system() 'Linux' |
platform.version() | 返回操做系統版本 | >>> platform.version() '#57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014' |
platform.machine() | 返回計算機類型 | >>> platform.machine() 'x86_64' |
platform.processor() | 返回計算機處理器類型 | >>> platform.processor() 'x86_64' |
platform.node() | 返回計算機網絡名 | >>> platform.node() 'ubuntu' |
platform.python_version() | 返回Python版本號 | >>> platform.python_version() '2.7.6' |
10.7 pickle與cPickle
建立可移植的Python序列化對象,持久化存儲到文件。
1)pickle
pickle庫有兩個經常使用的方法,dump()、load() 和dumps()、 loads(),下面看看它們的使用方法:
dump()方法是把對象保存到文件中。
格式:dump(obj, file, protocol=None)
load()方法是從文件中讀數據,重構爲原來的Python對象。
格式:load(file)
示例,將字典序列化到文件:
>>> import pickle>>> dict = {'a':1, 'b':2, 'c':3}>>> output = open('data.pkl', 'wb') # 二進制模式打開文件>>> pickle.dump(dict, output) # 執行完導入操做,當前目錄會生成data.pkl文件>>> output.close() # 寫入數據並關閉
看看pickle格式後的文件:
# cat data.pkl(dp0 S'a'p1 I1 sS'c'p2 I3 sS'b'p3 I2 s.
讀取序列化文件:
>>> f = open('data.pkl')>>> data = pickle.load(f)>>> print data{'a': 1, 'c': 3, 'b': 2}
用法挺簡單的,就是先導入文件,再讀取文件。
接下來看看序列化字符串操做:
dumps()返回一個pickle格式化的字符串
格式:dumps(obj, protocol=None)
load()解析pickle字符串爲對象
示例:
>>> s = 'abc'>>> pickle.dumps(s) "S'abc'\np0\n.">>> pkl = pickle.dumps(s)>>> pkl"S'abc'\np0\n.">>> pickle.loads(pkl)'abc'
須要注意的是,py2.x使用的是pickle2.0格式版本,若是用3.0、4.0版本的pickle導入會出錯。能夠經過pickle.format_version 查看版本。
2)cPickle
cPickle庫是C語言實現,對pickle進行了優化,提高了性能,建議在寫代碼中使用。
cPicke提供了與pickle相同的dump()、load() 和dumps()、 loads()方法,用法同樣,再也不講解。
10.8 subprocess
subprocess庫會fork一個子進程去執行任務,鏈接到子進程的標準輸入、輸出、錯誤,並得到它們的返回代碼。這個模塊將取代os.system、os.spawn*、os.popen*、popen2.*和commands.*。
提供瞭如下經常使用方法幫助咱們執行bash命令的相關操做:
subprocess.call():運行命令與參數。等待命令完成,返回執行狀態碼。
>>> import subprocess >>> retcode = subprocess.call(["ls", "-l"])total 504-rw-r--r-- 1 root root 54 Nov 2 06:15 data.pkl>>> retcode0>>> retcode = subprocess.call(["ls", "a"]) ls: cannot access a: No such file or directory>>> retcode2# 也能夠這樣寫>>> subprocess.call('ls -l', shell=True)subprocess.check_call():運行命令與參數。若是退出狀態碼非0,引起CalledProcessError異常,包含狀態碼。>>> subprocess.check_call("ls a", shell=True)ls: cannot access a: No such file or directory Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/usr/lib/python2.7/subprocess.py", line 540, in check_call raise CalledProcessError(retcode, cmd)subprocess.CalledProcessError: Command 'ls a' returned non-zero exit status 2
subprocess.Popen():這個類咱們主要來使用的,參數較多。
參數 |
描述 |
args | 命令,字符串或列表 |
bufsize | 0表明無緩衝,1表明行緩衝,其餘正值表明緩衝區大小,負值採用默認系統緩衝(通常是全緩衝) |
executable | |
stdin stdout stderr |
默認沒有任何重定向,能夠指定重定向到管道(PIPE)、文件對象、文件描述符(整數),stderr還能夠設置爲STDOUT |
preexec_fn | 鉤子函數,在fork和exec之間執行 |
close_fds | |
shell | 爲True,表示用當前默認解釋器執行。至關於args前面添加「/bin/sh」「-c或win下"cmd.exe /c " |
cwd | 指定工做目錄 |
env | 設置環境變量 |
universal_newlines | 換行符統一處理成"\n" |
startupinfo | 在windows下的Win32 API 發送CreateProcess()建立進程 |
creationflags | 在windows下的Win32 API 發送CREATE_NEW_CONSOLE()建立控制檯窗口 |
subprocess.Popen()類又提供瞭如下些方法:
方法 |
描述 |
Popen.communicate(input=None) | 與子進程交互。讀取從stdout和stderr緩衝區內容,阻塞父進程,等待子進程結束 |
Popen. kill() | 殺死子進程,在Posix系統上發送SIGKILL信號 |
Popen.pid | 獲取子進程PID |
Popen.poll() | 若是子進程終止返回狀態碼 |
Popen.returncode | 返回子進程狀態碼 |
Popen.send_signal(signal) | 發送信號到子進程 |
Popen.stderr | 若是參數值是PIPE,那麼這個屬性是一個文件對象,提供子進程錯誤輸出。不然爲None |
Popen.stdin | 若是參數值是PIPE,那麼這個屬性是一個文件對象,提供子進程輸入。不然爲None |
Popen.stdout | 若是參數值是PIPE,那麼這個屬性是一個文件對象,提供子進程輸出。不然爲None |
Popen.terminate() | 終止子進程,在Posix系統上發送SIGTERM信號,在windows下的Win32 API發送TerminateProcess()到子進程 |
Popen.wait() | 等待子進程終止,返回狀態碼 |
示例:
>>> p = subprocess.Popen('dmesg |grep eth0', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)>>> p.communicate() ...... # 元組形式返回結果>>> p.pid57039>>> p.wait()0>>> p.returncode0
subprocess.PIPE提供了一個緩衝區,將stdout、stderr放到這個緩衝區中,p.communicate()方法讀取緩衝區數據。
緩衝區的stdout、stderr是分開的,能夠以p.stdout.read()方式得到標準輸出、錯誤輸出的內容。
再舉個例子,咱們以標準輸出做爲下個Popen任務的標準輸入:
>>> p1 = subprocess.Popen('ls', stdout=subprocess.PIPE, shell=True)
>>> p2 = subprocess.Popen('grep data', stdin=p1.stdout, stdout=subprocess.PIPE, shell=True)
>>> p1.stdout.close() # 調用後啓動p2,爲了得到SIGPIPE
>>> output = p2.communicate()[0]
>>> output
'data.pkl\n'
p1的標準輸出做爲p2的標準輸入。這個p2的stdin、stdout也能夠是個可讀、可寫的文件。
10.9 Queue
隊列,數據存放在內存中,通常用於交換數據。
類 |
描述 |
Queue.Empty | 當非阻塞get()或get_nowait()對象隊列上爲空引起異常 |
Queue.Full | 當非阻塞put()或put_nowait()對象隊列是一個滿的隊列引起異常 |
Queue.LifoQueue(maxsize=0) | 構造函數爲後進先出隊列。maxsize設置隊列最大上限項目數量。小於或等於0表明無限。 |
Queue.PriorityQueue(maxsize=0) | 構造函數爲一個優先隊列。級別越高越先出。 |
Queue.Queue(maxsize=0) | 構造函數爲一個FIFO(先進先出)隊列。maxsize設置隊列最大上限項目數量。小於或等於0表明無限。 |
Queue.deque | 雙端隊列。實現快速append()和popleft(),無需鎖。 |
Queue.heapq | 堆排序隊列。 |
用到比較多的是Queue.Queue類,在這裏主要了解下這個。
它提供了一些操做隊列的方法:
方法 |
描述 |
Queue.empty() | 若是隊列爲空返回True,不然返回False |
Queue.full() | 若是隊列是滿的返回True,不然返回False |
Queue.get(block=True, timeout=None) | 從隊列中刪除並返回一個項目。沒有指定項目,由於是FIFO隊列,若是隊列爲空會一直阻塞。timeout超時時間 |
Queue.get_nowait() | 從隊列中刪除並返回一個項目,不阻塞。會拋出異常。 |
Queue.join() | 等待隊列爲空,再執行別的操做 |
Queue.put(item, block=True, timeout=None) | 寫入項目到隊列 |
Queue.put_nowait() | 寫入項目到隊列,不阻塞。與get同理 |
Queue.qsize() | 返回隊列大小 |
Queue.task_done() | 表示原隊列的任務完成 |
示例:
>>> from Queue import Queue>>> q = Queue()>>> q.put('test')>>> q.qsize()1>>> q.get()'test'>>> q.qsize()0>>> q.full()False>>> q.empty()True
10.10 StringIO
StringIO庫將字符串存儲在內存中,像操做文件同樣操做。主要提供了一個StringIO類。
方法 |
描述 |
StringIO.close() | 關閉 |
StringIO.flush() | 刷新緩衝區 |
StringIO.getvalue() | 獲取寫入的數據 |
StringIO.isatty() | |
StringIO.next() | 讀取下一行,沒有數據拋出異常 |
StringIO.read(n=-1) | 默認讀取全部內容。n指定讀取多少字節 |
StringIO.readline(length=None) | 默認讀取下一行。length指定讀取多少個字符 |
StringIO.readlines(sizehint=0) | 默認讀取全部內容,以列表返回。sizehint指定讀取多少字節 |
StringIO.seek(pos, mode=0) | 在文件中移動文件指針,從mode(0表明文件起始位置,默認。1表明當前位置。2表明文件末尾)偏移pos個字節 |
StringIO.tell() | 返回當前在文件中的位置 |
StringIO.truncate() | 截斷文件大小 |
StringIO.write(str) | 寫字符串到文件 |
StringIO.writelines(iterable) | 寫入序列,必須是一個可迭代對象,通常是一個字符串列表 |
能夠看到,StringIO方法與文件對象方法大部分都同樣,從而也就能方面的操做內存對象。
示例:
>>> f = StringIO()>>> f.write('hello')>>> f.getvalue()'hello'
像操做文件對象同樣寫入。
用一個字符串初始化StringIO,能夠像讀文件同樣讀取:
>>> f = StringIO('hello\nworld!')>>> f.read()'hello\nworld!'>>> s = StringIO('hello world!')>>> s.seek(5) # 指針移動到第五個字符,開始寫入 >>> s.write('-') >>> s.getvalue()'hello-world!'
10.11 logging
記錄日誌庫。
有幾個主要的類:
logging.Logger | 應用程序記錄日誌的接口 |
logging.Filter | 過濾哪條日誌不記錄 |
logging.FileHandler | 日誌寫到磁盤文件 |
logging.Formatter | 定義最終日誌格式 |
日誌級別:
級別 | 數字值 | 描述 |
critical | 50 | 危險 |
error | 40 | 錯誤 |
warning | 30 | 警告 |
info | 20 | 普通訊息 |
debug | 10 | 調試 |
noset | 0 | 不設置 |
Formatter類能夠自定義日誌格式,默認時間格式是%Y-%m-%d %H:%M:%S,有如下這些屬性:
%(name)s | 日誌的名稱 |
%(levelno)s | 數字日誌級別 |
%(levelname)s | 文本日誌級別 |
%(pathname)s | 調用logging的完整路徑(若是可用) |
%(filename)s | 文件名的路徑名 |
%(module)s | 模塊名 |
%(lineno)d | 調用logging的源行號 |
%(funcName)s | 函數名 |
%(created)f | 建立時間,返回time.time()值 |
%(asctime)s | 字符串表示建立時間 |
%(msecs)d | 毫秒錶示建立時間 |
%(relativeCreated)d | 毫秒爲單位表示建立時間,相對於logging模塊被加載,一般應用程序啓動。 |
%(thread)d | 線程ID(若是可用) |
%(threadName)s | 線程名字(若是可用) |
%(process)d | 進程ID(若是可用) |
%(message)s | 輸出的消息 |
示例:
#!/usr/bin/python# -*- coding: utf-8 -*-#--------------------------------------------------# 日誌格式#--------------------------------------------------# %(asctime)s 年-月-日 時-分-秒,毫秒 2013-04-26 20:10:43,745# %(filename)s 文件名,不含目錄# %(pathname)s 目錄名,完整路徑# %(funcName)s 函數名# %(levelname)s 級別名# %(lineno)d 行號# %(module)s 模塊名# %(message)s 消息體# %(name)s 日誌模塊名# %(process)d 進程id# %(processName)s 進程名# %(thread)d 線程id# %(threadName)s 線程名import loggingformat = logging.Formatter('%(asctime)s - %(levelname)s %(filename)s [line:%(lineno)d] %(message)s')# 建立日誌記錄器info_logger = logging.getLogger('info')# 設置日誌級別,小於INFO的日誌忽略info_logger.setLevel(logging.INFO)# 日誌記錄到磁盤文件info_file = logging.FileHandler("info.log")# info_file.setLevel(logging.INFO)# 設置日誌格式info_file.setFormatter(format)info_logger.addHandler(info_file)error_logger = logging.getLogger('error')error_logger.setLevel(logging.ERROR)error_file = logging.FileHandler("error.log")error_file.setFormatter(format)error_logger.addHandler(error_file)# 輸出控制檯(stdout)console = logging.StreamHandler()console.setLevel(logging.DEBUG)console.setFormatter(format)info_logger.addHandler(console)error_logger.addHandler(console)if __name__ == "__main__": # 寫日誌 info_logger.warning("info message.") error_logger.error("error message!")
# python test.py2016-07-02 06:52:25,624 - WARNING test.py [line:49] info message.2016-07-02 06:52:25,631 - ERROR test.py [line:50] error message!# cat info.log2016-07-02 06:52:25,624 - WARNING test.py [line:49] info message.# cat error.log2016-07-02 06:52:25,631 - ERROR test.py [line:50] error message!
上面代碼實現了簡單記錄日誌功能。分別定義了info和error日誌,將等於或高於日誌級別的日誌寫到日誌文件中。在小項目開發中把它單獨寫一個模塊,很方面在其餘代碼中調用。
須要注意的是,在定義多個日誌文件時,getLogger(name=None)類的name參數須要指定一個惟一的名字,若是沒有指定,日誌會返回到根記錄器,也就是意味着他們日誌都會記錄到一塊兒。
10.12 ConfigParser
配置文件解析。
這個庫咱們主要用到ConfigParser.ConfigParser()類,對ini格式文件增刪改查。
ini文件固定結構:有多個部分塊組成,每一個部分有一個[標識],並有多個key,每一個key對應每一個值,以等號"="分隔。值的類型有三種:字符串、整數和布爾值。其中字符串能夠不用雙引號,布爾值爲真用1表示,布爾值爲假用0表示。註釋以分號";"開頭。
方法 |
描述 |
ConfigParser.add_section(section) | 建立一個新的部分配置 |
ConfigParser.get(section, option, raw=False, vars=None) | 獲取部分中的選項值,返回字符串 |
ConfigParser.getboolean(section, option) | 獲取部分中的選項值,返回布爾值 |
ConfigParser.getfloat(section, option) | 獲取部分中的選項值,返回浮點數 |
ConfigParser.getint(section, option) | 獲取部分中的選項值,返回整數 |
ConfigParser.has_option(section, option) | 檢查部分中是否存在這個選項 |
ConfigParser.has_section(section) | 檢查部分是否在配置文件中 |
ConfigParser.items(section, raw=False, vars=None) | 列表元組形式返回部分中的每個選項 |
ConfigParser.options(section) | 列表形式返回指定部分選項名稱 |
ConfigParser.read(filenames) | 讀取ini格式的文件 |
ConfigParser.remove_option( section, option) | 移除部分中的選項 |
ConfigParser.remove_section(section, option) | 移除部分 |
ConfigParser.sections() | 列表形式返回全部部分名稱 |
ConfigParser.set(section, option, value) | 設置選項值,存在則更新,不然添加 |
ConfigParser.write(fp) | 寫一個ini格式的配置文件 |
舉例說明,寫一個ini格式文件,對其操做:
# cat config.ini[host1] host = 192.168.1.1port = 22user = zhangsanpass = 123[host2]host = 192.168.1.2port = 22user = lisipass = 456[host3]host = 192.168.1.3port = 22user = wangwupass = 789
1)獲取部分中的鍵值
#!/usr/bin/python# -*- coding: utf-8 -*-from ConfigParser import ConfigParser conf = ConfigParser()conf.read("config.ini")section = conf.sections()[0] # 獲取隨機的第一個部分標識options = conf.options(section) # 獲取部分中的全部鍵key = options[2]value = conf.get(section, options[2]) # 獲取部分中鍵的值print key, valueprint type(value)# python test.pyport 22<type 'str'>
這裏有意打出來了值的類型,來講明下get()方法獲取的值都是字符串,若是有須要,能夠getint()獲取整數。測試發現,ConfigParser是從下向上讀取的文件內容!
2)遍歷文件中的每一個部分的每一個字段
#!/usr/bin/python# -*- coding: utf-8 -*-from ConfigParser import ConfigParser conf = ConfigParser()conf.read("config.ini")sections = conf.sections() # 獲取部分名稱 ['host3', 'host2', 'host1']for section in sections: options = conf.options(section) # 獲取部分名稱中的鍵 ['user', 'host', 'port', 'pass'] for option in options: value = conf.get(section, option) # 獲取部分中的鍵值 print option + ": " + value print "-------------" # python test.pyuser: wangwu host: 192.168.1.3port: 22pass: 789-------------user: lisi host: 192.168.1.2port: 22pass: 456-------------user: zhangsan host: 192.168.1.1port: 22pass: 123-------------
經過上面的例子,熟悉了sections()、options()和get(),能任意獲取文件的內容了。
也可使用items()獲取部分中的每一個選項:
from ConfigParser import ConfigParser conf = ConfigParser()conf.read("config.ini")print conf.items('host1')# python test.py[('user', 'zhangsan'), ('host', '192.168.1.1'), ('port', '22'), ('pass', '123')]
3)更新或添加選項
from ConfigParser import ConfigParser conf = ConfigParser()conf.read("config.ini")fp = open("config.ini", "w") # 寫模式打開文件,供後面提交寫的內容conf.set("host1", "port", "2222") # 有這個選項就更新,不然添加conf.write(fp) # 寫入的操做必須執行這個方法
4)添加一部分,並添加選項
from ConfigParser import ConfigParser conf = ConfigParser()conf.read("config.ini")fp = open("config.ini", "w")conf.add_section("host4") # 添加[host4]conf.set("host4", "host", "192.168.1.4")conf.set("host4", "port", "22")conf.set("host4", "user", "zhaoliu")conf.set("host4", "pass", "123")conf.write(fp)
5)刪除一部分
from ConfigParser import ConfigParser conf = ConfigParser()conf.read("config.ini")fp = open("config.ini", "w")conf.remove_section('host4') # 刪除[host4]conf.remove_option('host3', 'pass') # 刪除[host3]的pass選項conf.write(fp)
10.13 urllib與urllib2
打開URL。urllib2是urllib的加強版,新增了一些功能,好比Request()用來修改Header信息。可是urllib2還去掉了一些好用的方法,好比urlencode()編碼序列中的兩個元素(元組或字典)爲URL查詢字符串。
通常狀況下這兩個庫結合着用,那咱們也結合着瞭解下。
類 |
描述 |
urllib.urlopen(url, data=None, proxies=None) | 讀取指定URL,建立類文件對象。data是隨着URL提交的數據(POST) |
urllib/urllib2.quote(s, safe='/') | 將字符串中的特殊符號轉十六進制表示。如: quote('abc def') -> 'abc%20def' |
urllib/urllib2.unquote(s) | 與quote相反 |
urllib.urlencode(query, doseq=0) | 將序列中的兩個元素(元組或字典)轉換爲URL查詢字符串 |
urllib.urlretrieve(url, filename=None, reporthook=None, data=None) | 將返回結果保存到文件,filename是文件名 |
urllib2.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False) | 通常訪問URL用urllib.urlopen(),若是要修改header信息就會用到這個。 data是隨着URL提交的數據,將會把HTTP請求GET改成POST。headers是一個字典,包含提交頭的鍵值對應內容。 |
urllib2.urlopen(url, data=None, timeout=<object object>) | timeout 超時時間,單位秒 |
urllib2.build_opener(*handlers) | 構造opener |
urllib2.install_opener(opener) | 把新構造的opener安裝到默認的opener中,之後urlopen()會自動調用 |
urllib2.HTTPCookieProcessor(cookiejar=None) | Cookie處理器 |
urllib2.HTTPBasicAuthHandler | 認證處理器 |
urllib2.ProxyHandler | 代理處理器 |
urllib.urlopen()有幾個經常使用的方法:
方法 | 描述 |
getcode() | 獲取HTTP狀態碼 |
geturl() | 返回真實URL。有可能URL3xx跳轉,那麼這個將得到跳轉後的URL |
info() | 返回服務器返回的header信息。能夠經過它的方法獲取相關值 |
next() | 獲取下一行,沒有數據拋出異常 |
read(size=-1) | 默認讀取全部內容。size正整數指定讀取多少字節 |
readline(size=-1) | 默認讀取下一行。size正整數指定讀取多少字節 |
readlines(sizehint=0) | 默認讀取全部內容,以列表形式返回。sizehint正整數指定讀取多少字節 |
示例:
1)請求URL
>>> import urllib, urllib2>>> response = urllib.urlopen("http://www.baidu.com") # 獲取的網站頁面源碼>>> response.readline()'<!DOCTYPE html>\n'>>> response.getcode()200>>> response.geturl()'http://www.baidu.com'
2)假裝chrome瀏覽器訪問
>>> user_agent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36">>> header = {"User-Agent": user_agent}>>> request = urllib2.Request("http://www.baidu.com", headers=header) # 也能夠經過request.add_header('User-Agent', 'Mozilla...')方式添加 >>> response = urllib2.urlopen(request)>>> response.geturl()'https://www.baidu.com/'>>> print respose.info() # 查看服務器返回的header信息Server: bfe/1.0.8.18Date: Sat, 12 Nov 2016 06:34:54 GMT Content-Type: text/html; charset=utf-8Transfer-Encoding: chunked Connection: close Vary: Accept-Encoding Set-Cookie: BAIDUID=5979A74F742651531360C08F3BE06754:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com Set-Cookie: BIDUPSID=5979A74F742651531360C08F3BE06754; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com Set-Cookie: PSTM=1478932494; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com Set-Cookie: BDSVRTM=0; path=/Set-Cookie: BD_HOME=0; path=/Set-Cookie: H_PS_PSSID=1426_18240_17945_21118_17001_21454_21408_21394_21377_21525_21192; path=/; domain=.baidu.com P3P: CP=" OTI DSP COR IVA OUR IND COM "Cache-Control: private Cxy_all: baidu+a24af77d41154f5fc0d314a73fd4c48f Expires: Sat, 12 Nov 2016 06:34:17 GMT X-Powered-By: HPHP X-UA-Compatible: IE=Edge,chrome=1Strict-Transport-Security: max-age=604800BDPAGETYPE: 1BDQID: 0xf51e0c970000d938BDUSERID: 0Set-Cookie: __bsi=12824513216883597638_00_24_N_N_3_0303_C02F_N_N_N_0; expires=Sat, 12-Nov-16 06:34:59 GMT; domain=www.baidu.com; path=/
這裏header只加了一個User-Agent,防止服務器當作爬蟲屏蔽了,有時爲了對付防盜鏈也會加Referer,說明是本站過來的請求。還有跟蹤用戶的cookie。
3)提交用戶表單
>>> post_data = {"loginform-username":"test","loginform-password":"123456"}>>> response = urllib2.urlopen("http://home.51cto.com/index", data=(urllib.urlencode(post_data)))>>> response.read() # 登陸後網頁內容
提交用戶名和密碼錶單登陸到51cto網站,鍵是表單元素的id。其中用到了urlencode()方法,上面講過是用於轉爲字典格式爲URL接受的編碼格式。
例如:
>>> urllib.urlencode(post_data)'loginform-password=123456&loginform-username=test'
4)保存cookie到變量中
#!/usr/bin/python# -*- coding: utf-8 -*-import urllib, urllib2import cookielib# 實例化CookieJar對象來保存cookiecookie = cookielib.CookieJar()# 建立cookie處理器handler = urllib2.HTTPCookieProcessor(cookie)# 經過handler構造openeropener = urllib2.build_opener(handler)response = opener.open("http://www.baidu.com")for item in cookie: print item.name, item.value # python test.pyBAIDUID EB4BF619C95630EFD619B99C596744B0:FG=1BIDUPSID EB4BF619C95630EFD619B99C596744B0 H_PS_PSSID 1437_20795_21099_21455_21408_21395_21377_21526_21190_21306 PSTM 1478936429BDSVRTM 0BD_HOME 0
urlopen()自己就是一個opener,沒法知足對Cookie處理,全部就要新構造一個opener。
這裏用到了cookielib庫,cookielib庫是一個可存儲cookie的對象。CookieJar類來捕獲cookie。
cookie存儲在客戶端,用來跟蹤瀏覽器用戶身份的會話技術。
5)保存cookie到文件
#!/usr/bin/python# -*- coding: utf-8 -*-import urllib, urllib2import cookielib cookie_file = 'cookie.txt'# 保存cookie到文件cookie = cookielib.MozillaCookieJar(cookie_file)# 建立cookie處理器handler = urllib2.HTTPCookieProcessor(cookie)# 經過handler構造openeropener = urllib2.build_opener(handler)response = opener.open("http://www.baidu.com")# 保存cookie.save(ignore_discard=True, ignore_expires=True) # ignore_discard默認是false,不保存將被丟失的。ignore_expires默認flase,若是cookie存在,則不寫入。# python test.py# cat cookie.txt# Netscape HTTP Cookie File# http://curl.haxx.se/rfc/cookie_spec.html# This is a generated file! Do not edit..baidu.com TRUE / FALSE 3626420835 BAIDUID 687544519EA906BD0DE5AE02FB25A5B3:FG=1.baidu.com TRUE / FALSE 3626420835 BIDUPSID 687544519EA906BD0DE5AE02FB25A5B3.baidu.com TRUE / FALSE H_PS_PSSID 1420_21450_21097_18560_21455_21408_21395_21377_21526_21192_20927.baidu.com TRUE / FALSE 3626420835 PSTM 1478937189www.baidu.com FALSE / FALSE BDSVRTM 0www.baidu.com FALSE / FALSE BD_HOME 0
MozillaCookieJar()這個類用來保存cookie到文件。
6)使用cookie訪問URL
#!/usr/bin/python# -*- coding: utf-8 -*-import urllib2import cookielib# 實例化對象cookie = cookielib.MozillaCookieJar()# 從文件中讀取cookiecookie.load("cookie.txt", ignore_discard=True, ignore_expires=True)# 建立cookie處理器handler = urllib2.HTTPCookieProcessor(cookie)# 經過handler構造openeropener = urllib2.build_opener(handler)# request = urllib2.Request("http://www.baidu.com")response = opener.open("http://www.baidu.com")
7)使用代理服務器訪問URL
import urllib2 proxy_address = {"http": "http://218.17.252.34:3128"}handler = urllib2.ProxyHandler(proxy_address)opener = urllib2.build_opener(handler)response = opener.open("http://www.baidu.com")print response.read()
8)URL訪問認證
import urllib2 auth = urllib2.HTTPBasicAuthHandler()# (realm, uri, user, passwd)auth.add_password(None, 'http://www.example.com','user','123456')opener = urllib2.build_opener(auth)response = opener.open('http://www.example.com/test.html')
10.14 json
JSON是一種輕量級數據交換格式,通常API返回的數據大可能是JSON、XML,若是返回JSON的話,將獲取的數據轉換成字典,方面在程序中處理。
json庫常常用的有兩種方法dumps和loads():
# 將字典轉換爲JSON字符串
>>> dict = {'user':[{'user1': 123}, {'user2': 456}]}
>>> type(dict)
<type 'dict'>
>>> json_str = json.dumps(dict)
>>> type(json_str)
<type 'str'>
# 把JSON字符串轉換爲字典
>>> d = json.loads(json_str)
>>> type(d)
<type 'dict'>
JSON與Python解碼後數據類型:
JSON |
Python |
object | dict |
array | list |
string | unicode |
number(int) | init,long |
number(real) | float |
true | Ture |
false | False |
null | None |
10.15 time
這個time庫提供了各類操做時間值。
方法 |
描述 |
示例 |
time.asctime([tuple]) | 將一個時間元組轉換成一個可讀的24個時間字符串 | >>> time.asctime(time.localtime()) 'Sat Nov 12 01:19:00 2016' |
time.ctime(seconds) | 字符串類型返回當前時間 | >>> time.ctime() 'Sat Nov 12 01:19:32 2016' |
time.localtime([seconds]) | 默認將當前時間轉換成一個(struct_timetm_year,tm_mon,tm_mday,tm_hour,tm_min, tm_sec,tm_wday,tm_yday,tm_isdst) |
>>> time.localtime() time.struct_time(tm_year=2016, tm_mon=11, tm_mday=12, tm_hour=1, tm_min=19, tm_sec=56, tm_wday=5, tm_yday=317, tm_isdst=0) |
time.mktime(tuple) | 將一個struct_time轉換成時間戳 | >>> time.mktime(time.localtime()) 1478942416.0 |
time.sleep(seconds) | 延遲執行給定的秒數 | >>> time.sleep(1.5) |
time.strftime(format[, tuple]) | 將元組時間轉換成指定格式。[tuple]不指定默認以當前時間 | >>> time.strftime('%Y-%m-%d %H:%M:%S') '2016-11-12 01:20:54' |
time.time() | 返回當前時間時間戳 | >>> time.time() 1478942466.45977 |
strftime():
指令 |
描述 |
%a | 簡化星期名稱,如Sat |
%A | 完整星期名稱,如Saturday |
%b | 簡化月份名稱,如Nov |
%B | 完整月份名稱,如November |
%c | 當前時區日期和時間 |
%d | 天 |
%H | 24小時制小時數(0-23) |
%I | 12小時制小時數(01-12) |
%j | 365天中第多少天 |
%m | 月 |
%M | 分鐘 |
%p | AM或PM,AM表示上午,PM表示下午 |
%S | 秒 |
%U | 一年中第幾個星期 |
%w | 星期幾 |
%W | 一年中第幾個星期 |
%x | 本地日期,如'11/12/16' |
%X | 本地時間,如'17:46:20' |
%y | 簡寫年名稱,如16 |
%Y | 完全年名稱,如2016 |
%Z | 當前時區名稱(PST:太平洋標準時間) |
%% | 表明一個%號自己 |
10.16 datetime
datetime庫提供瞭如下幾個類:
類 |
描述 |
datetime.date() | 日期,年月日組成 |
datetime.datetime() | 包括日期和時間 |
datetime.time() | 時間,時分秒及微秒組成 |
datetime.timedelta() | 時間間隔 |
datetime.tzinfo() |
datetime.date()類:
方法 |
描述 |
描述 |
date.max | 對象所能表示的最大日期 | datetime.date(9999, 12, 31) |
date.min | 對象所能表示的最小日期 | datetime.date(1, 1, 1) |
date.strftime() | 根據datetime自定義時間格式 | >>> date.strftime(datetime.now(), '%Y-%m-%d %H:%M:%S') '2016-11-12 07:24:15 |
date.today() | 返回當前系統日期 | >>> date.today() datetime.date(2016, 11, 12) |
date.isoformat() | 返回ISO 8601格式時間(YYYY-MM-DD) | >>> date.isoformat(date.today()) '2016-11-12' |
date.fromtimestamp() | 根據時間戳返回日期 | >>> date.fromtimestamp(time.time()) datetime.date(2016, 11, 12) |
date.weekday() | 根據日期返回星期幾,週一是0,以此類推 | >>> date.weekday(date.today()) 5 |
date.isoweekday() | 根據日期返回星期幾,週一是1,以此類推 | >>> date.isoweekday(date.today()) 6 |
date.isocalendar() | 根據日期返回日曆(年,第幾周,星期幾) | >>> date.isocalendar(date.today()) (2016, 45, 6) |
datetime.datetime()類:
方法 |
描述 |
示例 |
datetime.now()/datetime.today() | 獲取當前系統時間 | >>> datetime.now() datetime.datetime(2016, 11, 12, 7, 39, 35, 106385) |
date.isoformat() | 返回ISO 8601格式時間 | >>> datetime.isoformat(datetime.now()) '2016-11-12T07:42:14.250440' |
datetime.date() | 返回時間日期對象,年月日 | >>> datetime.date(datetime.now()) datetime.date(2016, 11, 12) |
datetime.time() | 返回時間對象,時分秒 | >>> datetime.time(datetime.now()) datetime.time(7, 46, 2, 594397) |
datetime.utcnow() | UTC時間,比中國時間快8個小時 | >>> datetime.utcnow() datetime.datetime(2016, 11, 12, 15, 47, 53, 514210) |
datetime.time()類:
方法 |
描述 |
示例 |
time.max | 所能表示的最大時間 | >>> time.max datetime.time(23, 59, 59, 999999) |
time.min | 所能表示的最小時間 | >>> time.min datetime.time(0, 0) |
time.resolution | 時間最小單位,1微妙 | >>> time.resolution datetime.timedelta(0, 0, 1) |
datetime.timedelta()類:
# 獲取昨天日期>>> date.today() - timedelta(days=1) datetime.date(2016, 11, 11)>>> date.isoformat(date.today() - timedelta(days=1))'2016-11-11'# 獲取明天日期>>> date.today() + timedelta(days=1) datetime.date(2016, 11, 13)>>> date.isoformat(date.today() + timedelta(days=1))'2016-11-13'
來自51CTO博客做者李振良OK的原創做品 https://blog.51cto.com/lizhenliang/1872538