1. 程式人生 > >Python之旅09:模組

Python之旅09:模組

Python(09)模組
本章內容:

  • 模組的簡介
  • time&datetime時間模組
  • random隨機模組
  • os 模組
  • sys 模組
  • json & picle模組
  • configparser
  • logging
  • hashlib
  • XML
  • requests
  • shutil 模組
  • Excel檔案(xlrd,xlsxwriter)

模組的簡介
類似於函數語言程式設計和麵向過程程式設計,函數語言程式設計則完成一個功能,其他程式碼用來呼叫即可,提供了程式碼的重用性和程式碼間的耦合。而對於一個複雜的功能來,可能需要多個函式才能完成(函式又可以在不同的.py檔案中),n個 .py 檔案組成的程式碼集合就稱為模組。
模組分為三種:

  • 自定義模組 (自己寫的.py檔案)
  • 第三方模組 (自己下載匯入的的模組)
  • 內建模組 (python自帶的)

Python之所以應用越來越廣泛,在一定程度上也依賴於其為程式設計師提供了大量的模組以供使用,如果想要使用模組,則需要匯入。匯入模組有一下幾種方法:

import module
from module.xx.xx import xx
from module.xx.xx import xx as rename 
from module.xx.xx import *

匯入模組其實就是告訴Python直譯器去解釋那個py檔案

  • 匯入一個py檔案,直譯器解釋該py檔案,就是先執行那個py檔案一次

那麼問題來了,匯入模組時是根據那個路徑作為基準來進行的呢?即:sys.path

import sys
import os
#絕對路徑修改方法
#project_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
#sys.path.append(project_path)
#相對路徑修改方法
pre_path = os.path.abspath('../')
sys.path.append(pre_path)

一、time時間模組
在這裡插入圖片描述

import time
#時間戳   #計算從1970-1-1 00:00:00
print(time.time())

1540693781.1374946
#結構化時間---本地時間
print(time.localtime())
t = time.localtime()
print(t.tm_year)#2018
time.struct_time(tm_year=2018, tm_mon=10, tm_mday=28, tm_hour=10, tm_min=36, tm_sec=15, tm_wday=6, tm_yday=301, tm_isdst=0)
2018
#結構化時間----UTC(世界標準時間)
print(time.gmtime()) #tm_hour=2 顯示 的是世界標準時間,我們位於東8區,10-8
time.struct_time(tm_year=2018, tm_mon=10, tm_mday=28, tm_hour=2, tm_min=39, tm_sec=6, tm_wday=6, tm_yday=301, tm_isdst=0)
#將結構化時間轉成字串時間strftime
print(time.strftime("%Y-%m-%d %X"))#%X代表時分秒
2018-10-28 10:47:49
#將字串時間轉成結構化時間strptime
print(time.strptime("2018:10:28:10:50:10","%Y:%m:%d:%X"))
time.struct_time(tm_year=2018, tm_mon=10, tm_mday=28, tm_hour=10, tm_min=50, tm_sec=10, tm_wday=6, tm_yday=301, tm_isdst=-1)
print(time.asctime())
print(time.ctime())
Sun Oct 28 10:52:25 2018
Sun Oct 28 10:52:25 2018
import datetime
print(datetime.datetime.now())
2018-10-28 10:53:48.666084

二、random隨機模組

>>> import random
>>> random.random() #取(0-1)之間的浮點數
0.0168715847341957
>>> random.uniform(1,3)#取(1-3)之間的浮點數
2.965567524578453
>>> random.randint(1,3)#取[1-3]的整數
2
>>> random.randrange(1,3)#取[1-3)的整數
1
>>> random.choice([11,22,44,66])#從列表中隨機取一個數
44
>>> random.sample([11,22,44,66],2)#從列表中隨機取二個數
[11, 44]
>>> 

隨機小數:習慣用numpy庫,利用np.random.randn(5)生成5個隨機小數

>>> import numpy as np
>>> res = np.random.randn(5)
>>> res
array([-1.90064532,  1.02424321, -0.68177688, -1.37728542, -0.74290642])
>>> 

例項:

########## 隨機驗證碼 ############
import random
temp = ''
for i in range(4):
    num = random.randrange(0,4)
    rad1 = random.randrange(65,91)
    c1 = chr(rad1)
    c1 = random.choice([num,c1])
    c1 = str(c1)
    temp = temp + c1
print(temp)

三、系統相關的模組都在os 模組裡:

#新增路徑
import sys
import os
#os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
pre_path = os.path.abspath('../') 
sys.path.append(pre_path)
os.getcwd() 獲取當前工作目錄,即當前python指令碼工作的目錄路徑
os.chdir("dirname")  改變當前指令碼工作目錄;相當於shell下cd
os.curdir  返回當前目錄: ('.')
os.pardir  獲取當前目錄的父目錄字串名:('..')
os.makedirs('dirname1/dirname2')    可生成多層遞迴目錄
os.removedirs('dirname1')    若目錄為空,則刪除,並遞迴到上一級目錄,如若也為空,則刪除,依此類推
os.mkdir('dirname')    生成單級目錄;相當於shell中mkdir dirname
os.rmdir('dirname')    刪除單級空目錄,若目錄不為空則無法刪除,報錯;相當於shell中rmdir dirname
os.listdir('dirname')    列出指定目錄下的所有檔案和子目錄,包括隱藏檔案,並以列表方式列印
os.remove()  刪除一個檔案
os.rename("oldname","newname")  重新命名檔案/目錄
os.stat('path/filename')  獲取檔案/目錄資訊
os.sep    輸出作業系統特定的路徑分隔符,win下為"\\",Linux下為"/"
os.linesep    輸出當前平臺使用的行終止符,win下為"\t\n",Linux下為"\n"
os.pathsep    輸出用於分割檔案路徑的字串
os.name    輸出字串指示當前使用平臺。win->'nt'; Linux->'posix'
os.system("bash command")  執行shell命令,直接顯示
os.environ  獲取系統環境變數
os.path.abspath(path)  返回path規範化的絕對路徑
os.path.split(path)  將path分割成目錄和檔名二元組返回
os.path.dirname(path)  返回path的目錄。其實就是os.path.split(path)的第一個元素
os.path.basename(path)  返回path最後的檔名。如何path以/或\結尾,那麼就會返回空值。即os.path.split(path)的第二個元素
os.path.exists(path)  如果path存在,返回True;如果path不存在,返回False
os.path.isabs(path)  如果path是絕對路徑,返回True
os.path.isfile(path)  如果path是一個存在的檔案,返回True。否則返回False
os.path.isdir(path)  如果path是一個存在的目錄,則返回True。否則返回False
os.path.join(path1[, path2[, ...]])  將多個路徑組合後返回,第一個絕對路徑之前的引數將被忽略
os.path.getatime(path)  返回path所指向的檔案或者目錄的最後存取時間
os.path.getmtime(path)  返回path所指向的檔案或者目錄的最後修改時間

四、sys模組
用於提供對Python直譯器相關的操作:

sys.argv           命令列引數List,第一個元素是程式本身路徑
sys.exit(n)        退出程式,正常退出時exit(0)
sys.version        獲取Python解釋程式的版本資訊
sys.maxint         最大的Int值
sys.path           返回模組的搜尋路徑,初始化時使用PYTHONPATH環境變數的值
sys.platform       返回作業系統平臺名稱
sys.stdin          輸入相關
sys.stdout         輸出相關
sys.stderror       錯誤相關

進度條百分比輸出:

import sys,time
number = 151
for i in range(number):
    sys.stdout.write('\r')  #每一次清空原行。
    sys.stdout.write("%s%%  |%s|"%(int(int(i)/(number-1)*100),int(int(i)/(number-1)*100) * '#'))     #一共次數除當前次數算進度
    sys.stdout.flush()      #把緩衝區的內容強制重新整理到螢幕
    time.sleep(0.05)

五、json & picle 模組
Python中用於序列化的兩個模組(推薦使用json):

  • json,用於字串 和 python資料型別間進行轉換
  • pickle,用於python特有的型別 和 python的資料型別間進行轉換

Json模組提供了四個功能:dumps、dump、loads、load

pickle模組提供了四個功能:dumps、dump、loads、load
在這裡插入圖片描述
dumps, loads操作檔案與變通讀寫檔案的方法是一樣的:

import  json

l = {"k1":"nick","k2:":"jenny"}
data = json.dumps(l)

print(type(data))

with open("file.txt","w") as f:
    f.write(data)

六、configparser
configparser用於處理特定格式的檔案,其本質上是利用open來操作檔案。

#指定格式

#註釋
;註釋2

[aaron]           #節點
age = 18         #值
gender = man    #值
dearm = girl     #值

[kel]          #節點
age = 21         #值
gender = worman     #值

1、獲取所有節點

import configparser

conf = configparser.ConfigParser()
# print(conf)
conf.read("config",encoding="utf-8")

result = conf.sections()
print(result) # ['aaron', 'kel']

2、獲取指定節點下所有的鍵值對

result=conf.items("aaron")
print(result) #[('age', '18'), ('gender', 'man'), ('dearm', 'girl')]

3、獲取指定節點下所有的建

ret = conf.options("aaron")
print(ret) # ['age', 'gender', 'dearm']

4、獲取指定節點下指定key的值

v1 = conf.get('kel','age')
v2 = conf.get('aaron','gender')
print(v1,v2) # 21 man

5、檢查、刪除、新增節點

#檢查
has = conf.has_section('aaron')
print(has) # True

# 新增節點
conf.add_section("wang")
conf.write(open('config', 'w'))

# 刪除節點
conf.remove_section("wang")
conf.write(open('config', 'w'))

6、檢查、刪除、設定指定組內的鍵值對

#檢查
has_opt = conf.has_option('aaron','age')
print(has_opt)#True

# 刪除
conf.remove_option('aaron', 'age')
conf.write(open('config', 'w'))

# 設定
conf.set('aaron', 'menu', "1234")
conf.write(open('config', 'w'))

七、logging
1、單檔案日誌

import logging
  
  
logging.basicConfig(filename='log.log',
                    format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S %p',
                    level=10) #level=logging.DEBUG
  
logging.debug('debug')
logging.info('info')
logging.warning('warning')
logging.error('error')
logging.critical('critical')
logging.log(10,'log')

日誌等級:critical > error > warning > info > debug

CRITICAL = 50
FATAL = CRITICAL
ERROR = 40
WARNING = 30
WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0

2、多檔案日誌

對於上述記錄日誌的功能,只能將日誌記錄在單檔案中,如果想要設定多個日誌檔案,logging.basicConfig將無法完成,需要自定義檔案和日誌操作物件。
日誌一:

# 定義檔案
file_1_1 = logging.FileHandler('l1_1.log', 'a', encoding='utf-8')
fmt = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s")
file_1_1.setFormatter(fmt)

file_1_2 = logging.FileHandler('l1_2.log', 'a', encoding='utf-8')
fmt = logging.Formatter()
file_1_2.setFormatter(fmt)

# 定義日誌
logger1 = logging.Logger('s1', level=logging.ERROR)
logger1.addHandler(file_1_1)
logger1.addHandler(file_1_2)


# 寫日誌
logger1.critical('1111')

日誌二:

# 定義檔案
file_2_1 = logging.FileHandler('l2_1.log', 'a')
fmt = logging.Formatter()
file_2_1.setFormatter(fmt)

# 定義日誌
logger2 = logging.Logger('s2', level=logging.INFO)
logger2.addHandler(file_2_1)

如上述建立的兩個日誌物件

  • 當使用【logger1】寫日誌時,會將相應的內容寫入 l1_1.log 和 l1_2.log 檔案中
  • 當使用【logger2】寫日誌時,會將相應的內容寫入 l2_1.log 檔案中
在logging.basicConfig()函式中可通過具體引數來更改logging模組預設行為,可用引數有
filename:用指定的檔名建立FiledHandler(後邊會具體講解handler的概念),這樣日誌會被儲存在指定的檔案中。
filemode:檔案開啟方式,在指定了filename時使用這個引數,預設值為“a”還可指定為“w”。
format:指定handler使用的日誌顯示格式。 
datefmt:指定日期時間格式。 
level:設定rootlogger(後邊會講解具體概念)的日誌級別 
stream:用指定的stream建立StreamHandler。可以指定輸出到sys.stderr,sys.stdout或者檔案,預設為sys.stderr。若同時列出了filename和stream兩個引數,則stream引數會被忽略。

format引數中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 數字形式的日誌級別
%(levelname)s 文字形式的日誌級別
%(pathname)s 呼叫日誌輸出函式的模組的完整路徑名,可能沒有
%(filename)s 呼叫日誌輸出函式的模組的檔名
%(module)s 呼叫日誌輸出函式的模組名
%(funcName)s 呼叫日誌輸出函式的函式名
%(lineno)d 呼叫日誌輸出函式的語句所在的程式碼行
%(created)f 當前時間,用UNIX標準的表示時間的浮 點數表示
%(relativeCreated)d 輸出日誌資訊時的,自Logger建立以 來的毫秒數
%(asctime)s 字串形式的當前時間。預設格式是 “2003-07-08 16:49:45,896”。逗號後面的是毫秒
%(thread)d 執行緒ID。可能沒有
%(threadName)s 執行緒名。可能沒有
%(process)d 程序ID。可能沒有
%(message)s使用者輸出的訊息

若要對logging進行更多靈活的控制,必須瞭解Logger,Handler,Formatter,Filter的概念:
logger提供了應用程式可以直接使用的介面;

handler將(logger建立的)日誌記錄傳送到合適的目的輸出;

filter提供了細度裝置來決定輸出哪條日誌記錄;

formatter決定日誌記錄的最終輸出格式。

 

logger

每個程式在輸出資訊之前都要獲得一個Logger。Logger通常對應了程式的模組名,比如聊天工具的圖形介面模組可以這樣獲得它的Logger:
LOG=logging.getLogger(”chat.gui”)
而核心模組可以這樣:
LOG=logging.getLogger(”chat.kernel”)

Logger.setLevel(lel):指定最低的日誌級別,低於lel的級別將被忽略。debug是最低的內建級別,critical為最高
Logger.addFilter(filt)、Logger.removeFilter(filt):新增或刪除指定的filter
Logger.addHandler(hdlr)、Logger.removeHandler(hdlr):增加或刪除指定的handler
Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical():可以設定的日誌級別

handler

handler物件負責傳送相關的資訊到指定目的地。Python的日誌系統有多種Handler可以使用。有些Handler可以把資訊輸出到控制檯,有些Logger可以把資訊輸出到檔案,還有些 Handler可以把資訊傳送到網路上。如果覺得不夠用,還可以編寫自己的Handler。可以通過addHandler()方法新增多個多handler
Handler.setLevel(lel):指定被處理的資訊級別,低於lel級別的資訊將被忽略
Handler.setFormatter():給這個handler選擇一個格式
Handler.addFilter(filt)、Handler.removeFilter(filt):新增或刪除一個filter物件


每個Logger可以附加多個Handler。接下來我們就來介紹一些常用的Handler:
1) logging.StreamHandler
使用這個Handler可以向類似與sys.stdout或者sys.stderr的任何檔案物件(file object)輸出資訊。它的建構函式是:
StreamHandler([strm])
其中strm引數是一個檔案物件。預設是sys.stderr


2) logging.FileHandler
和StreamHandler類似,用於向一個檔案輸出日誌資訊。不過FileHandler會幫你開啟這個檔案。它的建構函式是:
FileHandler(filename[,mode])
filename是檔名,必須指定一個檔名。
mode是檔案的開啟方式。參見Python內建函式open()的用法。預設是’a',即新增到檔案末尾。

3) logging.handlers.RotatingFileHandler
這個Handler類似於上面的FileHandler,但是它可以管理檔案大小。當檔案達到一定大小之後,它會自動將當前日誌檔案改名,然後建立 一個新的同名日誌檔案繼續輸出。比如日誌檔案是chat.log。當chat.log達到指定的大小之後,RotatingFileHandler自動把 檔案改名為chat.log.1。不過,如果chat.log.1已經存在,會先把chat.log.1重新命名為chat.log.2。。。最後重新建立 chat.log,繼續輸出日誌資訊。它的建構函式是:
RotatingFileHandler( filename[, mode[, maxBytes[, backupCount]]])
其中filename和mode兩個引數和FileHandler一樣。
maxBytes用於指定日誌檔案的最大檔案大小。如果maxBytes為0,意味著日誌檔案可以無限大,這時上面描述的重新命名過程就不會發生。
backupCount用於指定保留的備份檔案的個數。比如,如果指定為2,當上面描述的重新命名過程發生時,原有的chat.log.2並不會被更名,而是被刪除。


4) logging.handlers.TimedRotatingFileHandler
這個Handler和RotatingFileHandler類似,不過,它沒有通過判斷檔案大小來決定何時重新建立日誌檔案,而是間隔一定時間就 自動建立新的日誌檔案。重新命名的過程與RotatingFileHandler類似,不過新的檔案不是附加數字,而是當前時間。它的建構函式是:
TimedRotatingFileHandler( filename [,when [,interval [,backupCount]]])
其中filename引數和backupCount引數和RotatingFileHandler具有相同的意義。
interval是時間間隔。
when引數是一個字串。表示時間間隔的單位,不區分大小寫。它有以下取值:
S 秒
M 分
H 小時
D 天
W 每星期(interval==0時代表星期一)
midnight 每天凌晨

八、 hashlib模組
用於加密相關的操作,代替了md5模組和sha模組,主要提供md5(), sha1(), sha224(), sha256(), sha384(), and sha512()演算法

import hashlib
 
# ######## md5 ########
hash = hashlib.md5()
# help(hash.update)
hash.update(bytes('admin', encoding='utf-8'))
print(hash.hexdigest())
print(hash.digest())
 
 
######## sha1 ########
 
hash = hashlib.sha1()
hash.update(bytes('admin', encoding='utf-8'))
print(hash.hexdigest())
 
# ######## sha256 ########
 
hash = hashlib.sha256()
hash.update(bytes('admin', encoding='utf-8'))
print(hash.hexdigest())
 
 
# ######## sha384 ########
 
hash = hashlib.sha384()
hash.update(bytes('admin', encoding='utf-8'))
print(hash.hexdigest())
 
# ######## sha512 ########
 
hash = hashlib.sha512()
hash.update(bytes('admin', encoding='utf-8'))
print(hash.hexdigest())
 
 
##### 加鹽 ######
# ######## md5 ########
 
hash = hashlib.md5(bytes('898oaFs09f',encoding="utf-8"))
hash.update(bytes('admin',encoding="utf-8"))
print(hash.hexdigest())
 
#python內建還有一個 hmac 模組,它內部對我們建立 key 和 內容 進行進一步的處理然後再加密
 
import hmac
 
h = hmac.new(bytes('898oaFs09f',encoding="utf-8"))
h.update(bytes('admin',encoding="utf-8"))
print(h.hexdigest())

九、XML 模組
XML是實現不同語言或程式之間進行資料交換的協議,XML檔案格式如下:

<data>
    <country name="Liechtenstein">
        <rank updated="yes">2</rank>
        <year>2023</year>
        <gdppc>141100</gdppc>
        <neighbor direction="E" name="Austria" />
        <neighbor direction="W" name="Switzerland" />
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <year>2026</year>
        <gdppc>59900</gdppc>
        <neighbor direction="N" name="Malaysia" />
    </country>
    <country name="Panama">
        <rank updated="yes">69</rank>
        <year>2026</year>
        <gdppc>13600</gdppc>
        <neighbor direction="W" name="Costa Rica" />
        <neighbor direction="E" name="Colombia" />
    </country>
</data>

1、解析XML

from xml.etree import ElementTree as ET


# 開啟檔案,讀取XML內容
str_xml = open('xo.xml', 'r').read()

# 將字串解析成xml特殊物件,root代指xml檔案的根節點
root = ET.XML(str_xml)

利用ElementTree.XML將字串解析成xml物件
from xml.etree import ElementTree as ET

# 直接解析xml檔案
tree = ET.parse("xo.xml")

# 獲取xml檔案的根節點
root = tree.getroot()

2、操作XML

XML格式型別是節點巢狀節點,對於每一個節點均有以下功能,以便對當前節點進行操作:

class Element:
    """An XML element.

    This class is the reference implementation of the Element interface.

    An element's length is its number of subelements.  That means if you
    want to check if an element is truly empty, you should check BOTH
    its length AND its text attribute.

    The element tag, attribute names, and attribute values can be either
    bytes or strings.

    *tag* is the element name.  *attrib* is an optional dictionary containing
    element attributes. *extra* are additional element attributes given as
    keyword arguments.

    Example form:
        <tag attrib>text<child/>...</tag>tail

    """

    當前節點的標籤名
    tag = None
    """The element's name."""

    當前節點的屬性

    attrib = None
    """Dictionary of the element's attributes."""

    當前節點的內容
    text = None
    """
    Text before first subelement. This is either a string or the value None.
    Note that if there is no text, this attribute may be either
    None or the empty string, depending on the parser.

    """

    tail = None
    """
    Text after this element's end tag, but before the next sibling element's
    start tag.  This is either a string or the value None.  Note that if there
    was no text, this attribute may be either None or an empty string,
    depending on the parser.

    """

    def __init__(self, tag, attrib={}, **extra):
        if not isinstance(attrib, dict):
            raise TypeError("attrib must be dict, not %s" % (
                attrib.__class__.__name__,))
        attrib = attrib.copy()
        attrib.update(extra)
        self.tag = tag
        self.attrib = attrib
        self._children = []

    def __repr__(self):
        return "<%s %r at %#x>" % (self.__class__.__name__, self.tag, id(self))

    def makeelement(self, tag, attrib):
        建立一個新節點
        """Create a new element with the same type.

        *tag* is a string containing the element name.
        *attrib* is a dictionary containing the element attributes.

        Do not call this method, use the SubElement factory function instead.

        """
        return self.__class__(tag, attrib)

    def copy(self):
        """Return copy of current element.

        This creates a shallow copy. Subelements will be shared with the
        original tree.

        """
        elem = self.makeelement(self.tag, self.attrib)
        elem.text = self.text
        elem.tail = self.tail
        elem[:] = self
        return elem

    def __len__(self):
        return len(self._children)

    def __bool__(self):
        warnings.warn(
            "The behavior of this method will change in future versions.  "
            "Use specific 'len(elem)' or 'elem is not None' test instead.",
            FutureWarning, stacklevel=2
            )
        return len(self._children) != 0 # emulate old behaviour, for now

    def __getitem__(self, index):
        return self._children[index]

    def __setitem__(self, index, element):
        # if isinstance(index, slice):
        #     for elt in element:
        #         assert iselement(elt)
        # else:
        #     assert iselement(element)
        self._children[index] = element

    def __delitem__(self, index):
        del self._children[index]

    def append(self, subelement):
        為當前節點追加一個子節點
        """Add *subelement* to the end of this element.

        The new element will appear in document order after the last existing
        subelement (or directly after the text, if it's the first subelement),
        but before the end tag for this element.

        """
        self._assert_is_element(subelement)
        self._children.append(subelement)

    def extend(self, elements):
        為當前節點擴充套件 n 個子節點
        """Append subelements from a sequence.

        *elements* is a sequence with zero or more elements.

        """
        for element in elements:
            self._assert_is_element(element)
        self._children.extend(elements)

    def insert(self, index, subelement):
        在當前節點的子節點中插入某個節點,即:為當前節點建立子節點,然後插入指定位置
        """Insert *subelement* at position *index*."""
        self._assert_is_element(subelement)
        self._children.insert(index, subelement)

    def _assert_is_element(self, e):
        # Need to refer to the actual Python implementation, not the
        # shadowing C implementation.
        if not isinstance(e, _Element_Py):
            raise TypeError('expected an Element, not %s' % type(e).__name__)

    def remove(self, subelement):
        在當前節點在子節點中刪除某個節點
        """Remove matching subelement.

        Unlike the find methods, this method compares elements based on
        identity, NOT ON tag value or contents.  To remove subelements by
        other means, the easiest way is to use a list comprehension to
        select what elements to keep, and then use slice assignment to update
        the parent element.

        ValueError is raised if a matching element could not be found.

        """
        # assert iselement(element)
        self._children.remove(subelement)

    def getchildren(self):
        獲取所有的子節點(廢棄)
        """(Deprecated) Return all subelements.

        Elements are returned in document order.

        """
        warnings.warn(
            "This method will be removed in future versions.  "
            "Use 'list(elem)' or iteration over elem instead.",
            DeprecationWarning, stacklevel=2
            )
        return self._children

    def find(self, path, namespaces=None):
        獲取第一個尋找到的子節點
        """Find first matching element by tag name or path.

        *path* is a string having either an element tag or an XPath,
        *namespaces* is an optional mapping from namespace prefix to full name.

        Return the first matching element, or None if no element was found.

        """
        return ElementPath.find(self, path, namespaces)

    def findtext(self, path, default=None, namespaces=None):
        獲取第一個尋找到的子節點的內容
        """Find text for first matching element by tag name or path.

        *path* is a string having either an element tag or an XPath,
        *default* is the value to return if the element was not found,
        *namespaces* is an optional mapping from namespace prefix to full name.

        Return text content of first matching element, or default value if
        none was found.  Note that if an element is found having no text
        content, the empty string is returned.

        """
        return ElementPath.findtext(self, path, default, namespaces)

    def findall(self, path, namespaces=None):
        獲取所有的子節點
        """Find all matching subelements by tag name or path.

        *path* is a string having either an element tag or an XPath,
        *namespaces* is an optional mapping from namespace prefix to full name.

        Returns list containing all matching elements in document order.

        """
        return ElementPath.findall(self, path, namespaces)

    def iterfind(self, path, namespaces=None):
        獲取所有指定的節點,並建立一個迭代器(可以被for迴圈)
        """Find all matching subelements by tag name or path.

        *path* is a string having either an element tag or an XPath,
        *namespaces* is an optional mapping from namespace prefix to full name.

        Return an iterable yielding all matching elements in document order.

        """
        return ElementPath.iterfind(self, path, namespaces)

    def clear(self):
        清空節點
        """Reset element.

        This function removes all subelements, clears all attributes, and sets
        the text and tail attributes to None.

        """
        self.attrib.clear()
        self._children = []
        self.text = self.tail = None

    def get(self, key, default=None):
        獲取當前節點的屬性值
        """Get element attribute.

        Equivalent to attrib.get, but some implementations may handle this a
        bit more efficiently.  *key* is what attribute to look for, and
        *default* is what to return if the attribute was not found.

        Returns a string containing the attribute value, or the default if
        attribute was not found.

        """
        return self.attrib.get(key, default)

    def set(self, key, value):
        為當前節點設定屬性值
        """Set element attribute.

        Equivalent to attrib[key] = value, but some implementations may handle
        this a bit more efficiently.  *key* is what attribute to set, and
        *value* is the attribute value to set it to.

        """
        self.attrib[key] = value

    def keys(self):
        獲取當前節點的所有屬性的 key

        """Get list of attribute names.

        Names are returned in an arbitrary order, just like an ordinary
        Python dict.  Equivalent to attrib.keys()

        """
        return self.attrib.keys()

    def items(self):
        獲取當前節點的所有屬性值,每個屬性都是一個鍵值對
        """Get element attributes as a sequence.

        The attributes are returned in arbitrary order.  Equivalent to
        attrib.items().

        Return a list of (name, value) tuples.

        """
        return self.attrib.items()

    def iter(self, tag=None):
        在當前節點的子孫中根據節點名稱尋找所有指定的節點,並返回一個迭代器(可以被for迴圈)。
        """Create tree iterator.

        The iterator loops over the element and all subelements in document
        order, returning all elements with a matching tag.

        If the tree structure is modified during iteration, new or removed
        elements may or may not be included.  To get a stable set, use the
        list() function on the iterator, and loop over the resulting list.

        *tag* is what tags to look for (default is to return all elements)

        Return an iterator containing all the matching elements.

        """
        if tag == "*":
            tag = None
        if tag is None or self.tag == tag:
            yield self
        for e in self._children:
            yield from e.iter(tag)

    # compatibility
    def getiterator(self, tag=None):
        # Change for a DeprecationWarning in 1.4
        warnings.warn(
            "This method will be removed in future versions.  "
            "Use 'elem.iter()' or 'list(elem.iter())' instead.",
            PendingDeprecationWarning, stacklevel=2
        )
        return list(self.iter(tag))

    def itertext(self):
        在當前節點的子孫中根據節點名稱尋找所有指定的節點的內容,並返回一個迭代器(可以被for迴圈)。
        """Create text iterator.

        The iterator loops over the element and all subelements in document
        order, returning all inner text.

        """
        tag = self.tag
        if not isinstance(tag, str) and tag is not None:
            return
        if self.text:
            yield self.text
        for e in self:
            yield from e.itertext()
            if e.tail:
                yield e.tail

節點功能一覽表

由於 每個節點 都具有以上的方法,並且在上一步驟中解析時均得到了root(xml檔案的根節點),so 可以利用以上方法進行操作xml檔案。

a. 遍歷XML文件的所有內容

from xml.etree import ElementTree as ET

############ 解析方式一 ############
"""
# 開啟檔案,讀取XML內容
str_xml = open('xo.xml', 'r').read()

# 將字串解析成xml特殊物件,root代指xml檔案的根節點
root = ET.XML(str_xml)
"""
############ 解析方式二 ############

# 直接解析xml檔案
tree = ET.parse("xo.xml")

# 獲取xml檔案的根節點
root = tree.getroot()


### 操作

# 頂層標籤
print(root.tag)


# 遍歷XML文件的第二層
for child in root:
    # 第二層節點的標籤名稱和標籤屬性
    print(child.tag, child.attrib)
    # 遍歷XML文件的第三層
    for i in child:
        # 第二層節點的標籤名稱和內容
        print(i.tag,i.text)

b、遍歷XML中指定的節點

from xml.etree import ElementTree as ET

############ 解析方式一 ############
"""
# 開啟檔案,讀取XML內容
str_xml = open('xo.xml', 'r').read()

# 將字串解析成xml特殊物件,root代指xml檔案的根節點
root = ET.XML(str_xml)
"""
############ 解析方式二 ############

# 直接解析xml檔案
tree = ET.parse("xo.xml")

# 獲取xml檔案的根節點
root = tree.getroot()


### 操作

# 頂層標籤
print(root.tag)


# 遍歷XML中所有的year節點
for node in root.iter('year'):
    # 節點的標籤名稱和內容
    print(node.tag, node.text)

c、修改節點內容

由於修改的節點時,均是在記憶體中進行,其不會影響檔案中的內容。所以,如果想要修改,則需要重新將記憶體中的內容寫到檔案。

from xml.etree import ElementTree as ET

############ 解析方式一 ############

# 開啟檔案,讀取XML內容
str_xml = open('xo.xml', 'r').read()

# 將字串解析成xml特殊物件,root代指xml檔案的根節點
root = ET.XML(str_xml)

############ 操作 ############

# 頂層標籤
print(root.tag)

# 迴圈所有的year節點
for node in root.iter('year'):
    # 將year節點中的內容自增一
    new_year = int(node.text) + 1
    node.text = str(new_year)

    # 設定屬性
    node.set('name', 'alex')
    node.set('age', '18')
    # 刪除屬性
    del node.attrib['name']


############ 儲存檔案 ############
tree = ET.ElementTree(root)
tree.write("newnew.xml", encoding='utf-8')

解析字串方式,修改,儲存
from xml.etree import ElementTree as ET

############ 解析方式二 ############

# 直接解析xml檔案
tree = ET.parse("xo.xml")

# 獲取xml檔案的根節點
root = tree.getroot()

############ 操作 ############

# 頂層標籤
print(root.tag)

# 迴圈所有的year節點
for node in root.iter('year'):
    # 將year節點中的內容自增一
    new_year = int(node.text) + 1
    node.text = str(new_year)

    # 設定屬性
    node.set('name', 'alex')
    node.set('age', '18')
    # 刪除屬性
    del node.attrib['name']


############ 儲存檔案 ############
tree.write("newnew.xml", encoding='utf-8')

解析檔案方式,修改,儲存

d、刪除節點

from xml.etree import ElementTree as ET

############ 解析字串方式開啟 ############

# 開啟檔案,讀取XML內容
str_xml = open('xo.xml', 'r').read()

# 將字串解析成xml特殊物件,root代指xml檔案的根節點
root = ET.XML(str_xml)

############ 操作 ############

# 頂層標籤
print(root.tag)

# 遍歷data下的所有country節點
for country in root.findall('country'):
    # 獲取每一個country節點下rank節點的內容
    rank = int(country.find('rank').text)

    if rank > 50:
        # 刪除指定country節點
        root.remove(country)

############ 儲存檔案 ############
tree = ET.ElementTree(root)
tree.write("newnew.xml", encoding='utf-8')

解析字串方式開啟,刪除,儲存
from xml.etree import ElementTree as ET

############ 解析檔案方式 ############

# 直接解析xml檔案
tree = ET.parse("xo.xml")

# 獲取xml檔案的根節點
root = tree.getroot()

############ 操作 ############

# 頂層標籤
print(root.tag)

# 遍歷data下的所有country節點
for country in root.findall('country'):
    # 獲取每一個country節點下rank節點的內容
    rank = int(country.find('rank').text)

    if rank > 50:
        # 刪除指定country節點
        root.remove(country)

############ 儲存檔案 ############
tree.write("newnew.xml", encoding='utf-8')

解析檔案方式開啟,刪除,儲存

3、建立XML文件
建立方式一:

from xml.etree import ElementTree as ET


# 建立根節點
root = ET.Element("famliy")


# 建立節點大兒子
son1 = ET.Element('son', {'name': '兒1'})
# 建立小兒子
son2 = ET.Element('son', {"name": '兒2'})

# 在大兒子中建立兩個孫子
grandson1 = ET.Element('grandson', {'name': '兒11'})
grandson2 = ET.Element('grandson', {'name': '兒12'})
son1.append(grandson1)
son1.append(grandson2)


# 把兒子新增到根節點中
root.append(son1)
root.append(son1)

tree = ET.ElementTree(root)
tree.write('oooo.xml',encoding='utf-8', short_empty_elements=False)

建立方式二:

from xml.etree import ElementTree as ET

# 建立根節點
root = ET.Element("famliy")


# 建立大兒子
# son1 = ET.Element('son', {'name': '兒1'})
son1 = root.makeelement('son', {'name': '兒1'})
# 建立小兒子
# son2 = ET.Element('son', {"name": '兒2'})
son2 = root.makeelement('son', {"name": '兒2'})

# 在大兒子中建立兩個孫子
# grandson1 = ET.Element('grandson', {'name': '兒11'})
grandson1 = son1.makeelement('grandson', {'name': '兒11'})
# grandson2 = ET.Element('grandson', {'name': '兒12'})
grandson2 = son1.makeelement('grandson', {'name': '兒12'})

son1.append(grandson1)
son1.append(grandson2)


# 把兒子新增到根節點中
root.append(son1)
root.append(son1)

tree = ET.ElementTree(root)
tree.write('oooo.xml',encoding='utf-8', short_empty_elements=False)

建立方式三:

from xml.etree import ElementTree as ET


# 建立根節點
root = ET.Element("famliy")


# 建立節點大兒子
son1 = ET.SubElement(root, "son", attrib={'name': '兒1'})
# 建立小兒子
son2 = ET.SubElement(root, "son", attrib={"name": "兒2"})

# 在大兒子中建立一個孫子
grandson1 = ET.SubElement(son1, "age", attrib={'name': '兒11'})
grandson1.text = '孫子'


et = ET.ElementTree(root)  #生成文件物件
et.write("test.xml", encoding="utf-8", xml_declaration=True, short_empty_elements=False)

由於原生儲存的XML時預設無縮排,如果想要設定縮排的話, 需要修改儲存方式:

from xml.etree import ElementTree as ET
from xml.dom import minidom


def prettify(elem):
    """將節點轉換成字串,並新增縮排。
    """
    rough_string = ET.tostring(elem, 'utf-8')
    reparsed = minidom.parseString(rough_string)
    return reparsed.toprettyxml(indent="\t")

# 建立根節點
root = ET.Element("famliy")


# 建立大兒子
# son1 = ET.Element('son', {'name': '兒1'})
son1 = root.makeelement('son', {'name': '兒1'})
# 建立小兒子
# son2 = ET.Element('son', {"name": '兒2'})
son2 = root.makeelement('son', {"name": '兒2'})

# 在大兒子中建立兩個孫子
# grandson1 = ET.Element('grandson', {'name': '兒11'})
grandson1 = son1.makeelement('grandson', {'name': '兒11'})
# grandson2 = ET.Element('grandson', {'name': '兒12'})
grandson2 = son1.makeelement('grandson', {'name': '兒12'})

son1.append(grandson1)
son1.append(grandson2)


# 把兒子新增到根節點中
root.append(son1)
root.append(son1)


raw_str = prettify(root)

f = open("xxxoo.xml",'w',encoding='utf-8')
f.write(raw_str)
f.close()

4、名稱空間

from xml.etree import ElementTree as ET

ET.register_namespace('com',"http://www.company.com") #some name

# build a tree structure
root = ET.Element("{http://www.company.com}STUFF")
body = ET.SubElement(root, "{http://www.company.com}MORE_STUFF", attrib={"{http://www.company.com}hhh": "123"})
body.text = "STUFF EVERYWHERE!"

# wrap it in an ElementTree instance, and save as XML
tree = ET.ElementTree(root)

tree.write("page.xml",
           xml_declaration=True,
           encoding='utf-8',
           method="xml")

十、requests
Python標準庫中提供了:urllib等模組以供Http請求,但是,它的 API 太渣了。它是為另一個時代、另一個網際網路所建立的。它需要巨量的工作,甚至包括各種方法覆蓋,來完成最簡單的任務。
傳送GET請求:

import urllib.request

f=urllib.request.urlopen('http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=424662508')
result = f.read().decode('utf-8')
print(result)

傳送攜帶請求頭的GET請求:

import urllib.request

req = urllib.request.Request('http://www.example.com/')
req.add_header('Referer', 'http://www.python.org/')
r = urllib.request.urlopen(req)

result = f.read().decode('utf-8')
print(result)

equests 是使用 Apache2 Licensed 許可證的 基於Python開發的HTTP 庫,其在Python內建模組的基礎上進行了高度的封裝,從而使得Pythoner進行網路請求時,變得美好了許多,使用Requests可以輕而易舉的完成瀏覽器可有的任何操作。

1、安裝模組

pip3 install requests

2、使用模組
GET請求:

# 1、無引數例項
 
import requests
 
ret = requests.get('https://github.com/timeline.json')
 
print(ret.url)
print(ret.text)
 
 
 
# 2、有引數例項
 
import requests
 
payload = {'key1': 'value1', 'key2': 'value2'}
ret = requests.get("http://httpbin.org/get", params=payload)
 
print(ret.url)
print(ret.text)

POST請求:

# 1、基本POST例項
 
import requests
 
payload = {'key1': 'value1', 'key2': 'value2'}
ret = requests.post("http://httpbin.org/post", data=payload)
 
print(ret.text)
 
 
# 2、傳送請求頭和資料例項
 
import requests
import json
 
url = 'https://api.github.com/some/endpoint'
payload = {'some': 'data'}
headers = {'content-type': 'application/json'}
 
ret = requests.post(url, data=json.dumps(payload), headers=headers)
 
print(ret.text)
print(ret.cookies)

其它請求:

requests.get(url, params=None, **kwargs)
requests.post(url, data=None, json=None, **kwargs)
requests.put(url, data=None, **kwargs)
requests.head(url, **kwargs)
requests.delete(url, **kwargs)
requests.patch(url, data=None, **kwargs)
requests.options(url, **kwargs)
 
# 以上方法均是在此方法的基礎上構建
requests.request(method, url, **kwargs)

更多requests模組相關的文件見
3、Http請求和XML例項

例項:檢測QQ賬號是否線上

import urllib
import requests
from xml.etree import ElementTree as ET

# 使用內建模組urllib傳送HTTP請求,或者XML格式內容
"""
f = urllib.request.urlopen('http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=630571017')
result = f.read().decode('utf-8')
"""


# 使用第三方模組requests傳送HTTP請求,或者XML格式內容
r = requests.get('http://www.webxml.com.cn//webservices/qqOnlineWebService.asmx/qqCheckOnline?qqCode=424662508')
result = r.text

# 解析XML格式內容
node = ET.XML(result)

# 獲取內容
if node.text == "Y":
    print("線上")
else:
    print("離線")

例項:檢視火車停靠資訊

import urllib
import requests
from xml.etree import ElementTree as ET

# 使用內建模組urllib傳送HTTP請求,或者XML格式內容
"""
f = urllib.request.urlopen('http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx/getDetailInfoByTrainCode?TrainCode=G666&UserID=')
result = f.read().decode('utf-8')
"""

# 使用第三方模組requests傳送HTTP請求,或者XML格式內容
r = requests.get('http://www.webxml.com.cn/WebServices/TrainTimeWebService.asmx/getDetailInfoByTrainCode?TrainCode=G666&UserID=')
result = r.text

# 解析XML格式內容
root = ET.XML(result)
for node in root.iter('TrainDetailInfo'):
    print(node.find('TrainStation').text,node.find('StartTime').text,node.tag,node.attrib)

十一、shutil 模組
高階的 檔案、資料夾、壓縮包 處理模組

shutil.copyfileobj(fsrc, fdst[, length])

將檔案內容拷貝到另一個檔案中

import shutil
  
shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))

shutil.copyfile(src, dst)

拷貝檔案

shutil.copyfile('f1.log', 'f2.log')

shutil.copymode(src, dst)

僅拷貝許可權。內容、組、使用者均不變

shutil.copymode('f1.log', 'f2.log')

shutil.copystat(src, dst)

拷貝狀態的資訊,包括:mode bits, atime, mtime, flags

shutil.copystat('f1.log', 'f2.log')

shutil.copy(src, dst)

拷貝檔案和許可權

import shutil
  
shutil.copy('f1.log', 'f2.log')

shutil.copy2(src, dst)

拷貝檔案和狀態資訊

import shutil
  
shutil.copy2('f1.log', 'f2.log')

shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)

遞迴的去拷貝資料夾

import shutil
  
shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*'))

shutil.rmtree(path[, ignore_errors[, onerror]])

遞迴的去刪除檔案

import shutil
  
shutil.rmtree('folder1')

shutil.move(src, dst)

遞迴的去移動檔案,它類似mv命令,其實就是重新命名。

import shutil
  
shutil.move('folder1', 'folder3')

shutil.make_archive(base_name, format,…)

建立壓縮包並返回檔案路徑,例如:zip、tar

  • base_name: 壓縮包的檔名,也可以是壓縮包的路徑。只是檔案 名時,則儲存至當前目錄,否則儲存至指定路徑,
  • 如:www =>儲存至當前路徑
  • 如:/Users/Aaron/www =>儲存至/Users/Aaron/
  • format: 壓縮包種類,“zip”, “tar”, “bztar”,“gztar”
  • root_dir: 要壓縮的資料夾路徑(預設當前目錄)
  • owner: 使用者,預設當前使用者
  • group: 組,預設當前組
  • logger: 用於記錄日誌,通常是logging.Logger物件
#將 /Users/Aaron/Downloads/test 下的檔案打包放置當前程式目錄
import shutil
ret = shutil.make_archive("test1", 'gztar', root_dir='/Users/wupeiqi/Downloads/test')
   
   
#將 /Users/wupeiqi/Downloads/test 下的檔案打包放置 /Users/Aaron/目錄
import shutil
ret = shutil.make_archive("/Users/Aaron/file1", 'gztar', root_dir='/Users/Aaron/Downloads/test')

shutil 對壓縮包的處理是呼叫 ZipFile 和 TarFile 兩個模組來進行的,詳細:
zipfile解壓縮:

import zipfile

z = zipfile.ZipFile("ini.zip","w")
z.write("ini")
z.write("pip")
z.close()
#壓縮包裡追加內容(開啟模式變為a)
#z = zipfile.ZipFile("ini.zip","a")
#z.write("db")
z.close()

#解壓
z = zipfile.ZipFile("ini.zip","r")
z.extractall()    #解壓全部
# z.extract("pip")    #解壓指定檔案
z.close()

tarfile解壓縮:

import tarfile

#壓縮
tar = tarfile.open("ini.zip","w")
tar.add("S:\stud\ini",arcname="iiini.txt")    #路徑、重新命名
tar.add("./pip",arcname="pip.log")
tar.close()

#解壓
tar = tarfile.open("ini.zip","r")
tar.extractall()    #可設定解壓地址
tar.close()

十二、Excel檔案(xlrd,xlsxwriter)

# -*- coding: utf-8 -*-
import xlrd

data = xlrd.open_workbook('F:\\message\\test.xlsx')

# 獲取一個工作表
# table = data.sheets()[0]
# table = data.sheet_by_index(0)
table = data.sheet_by_name(u'Sheet1')

# 獲取行數和列數
nrows = table.nrows
# nrows = table.ncols

# 使用行列索引
cell_A1 = table.row(0)[0].value
cell_A2 = table.col(1)[0].value
print cell_A1, cell_A2

# 單元格
cell_C1 = table.cell(0, 0).value
cell_C2 = table.cell(2, 1).value
print cell_C1, cell_C2

for i in range(nrows):
    print table.row_values(i)
    # # 獲取整行和整列的值(陣列)
    # table.row_values(i)
    # table.col_values(i)




# 寫入

import xlsxwriter

# 建立檔案
workbook = xlsxwriter.Workbook('F:\\message\\test.xlsx')
# 建立sheet, 可以work.add_worksheet('employee')來指定sheet名,但中文名會報UnicodeDecodeErro的錯誤
worksheet = workbook.add_worksheet()
# 向A1寫入
worksheet.write('A1', 'Hello world')
worksheet.write('B1', '2017-02-13')

workbook.close()