第四章——續2

4.9 xml模塊node

xml是實現不一樣語言或程序之間進行數據交換的協議,跟json差很少,但json使用起來更簡單,不過,古時候,在json還沒誕生的混沌年代,你們只能選擇用xml,至今不少傳統公司如金融行業的不少系統的接口還主要是xml。python

xml的格式以下,就是經過<>節點來區別數據結構的:git

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

xml協議在各個語言裏的都 是支持的,在python中能夠用如下模塊操做xml算法

import xml.etree.ElementTree as ET

tree = ET.parse("xmltest.xml")
root = tree.getroot()
print(root.tag)

#遍歷xml文檔
for child in root:
    print(child.tag, child.attrib)
    for i in child:
        print(i.tag,i.text)

#只遍歷year 節點
for node in root.iter('year'):
    print(node.tag,node.text)

修改和刪除xml文檔內容shell

import xml.etree.ElementTree as ET

tree = ET.parse("xmltest.xml")
root = tree.getroot()

#修改
for node in root.iter('year'):
    new_year = int(node.text) + 1
    node.text = str(new_year)
    node.set("updated","yes")

tree.write("xmltest.xml")
#刪除node
for country in root.findall('country'):
   rank = int(country.find('rank').text)
   if rank > 50:
     root.remove(country)

tree.write('output.xml')

本身建立xml文檔數據庫

import xml.etree.ElementTree as ET


new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
age = ET.SubElement(name,"age",attrib={"checked":"no"})
sex = ET.SubElement(name,"sex")
sex.text = '33'
name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
age = ET.SubElement(name2,"age")
age.text = '19'

et = ET.ElementTree(new_xml) #生成文檔對象
et.write("test.xml", encoding="utf-8",xml_declaration=True)

ET.dump(new_xml) #打印生成的格式

4.10    configparser模塊json

此模塊用於生成和修改常見配置文檔,當前模塊的名稱在 python 3.x 版本中變動爲 configparser。緩存

看一個好多軟件的常見配置文件格式以下安全

```cnf
[DEFAULT]
ServerAliveInterval = 45   
Compression = yes
CompressionLevel = 9
ForwardX11 = yes

[bitbucket.org]
User = hg

[topsecret.server.com]
Port = 50022
ForwardX11 = no
```

解析配置文件數據結構

```py
>>> import configparser # 導入模塊
>>> config = configparser.ConfigParser()  #實例化(生成對象)
>>> config.sections()  #調用sections方法
[]
>>> config.read('example.ini')  # 讀配置文件(注意文件路徑)
['example.ini']
>>> config.sections() #調用sections方法(默認不會讀取default)
['bitbucket.org', 'topsecret.server.com']
>>> 'bitbucket.org' in config #判斷元素是否在sections列表內
True
>>> 'bytebong.com' in config
False
>>> config['bitbucket.org']['User'] # 經過字典的形式取值
'hg'
>>> config['DEFAULT']['Compression']
'yes'
>>> topsecret = config['topsecret.server.com']
>>> topsecret['ForwardX11']
'no'
>>> topsecret['Port']
'50022'
>>> for key in config['bitbucket.org']: print(key) # for循環 bitbucket.org 字典的key
...
user
compressionlevel
serveraliveinterval
compression
forwardx11
>>> config['bitbucket.org']['ForwardX11']
'yes'
```

其它增刪改查語法

```python
[group1] # 支持的兩種分隔符「=」, 「:」
k1 = v1
k2:v2

[group2]
k1 = v1

import ConfigParser

config = ConfigParser.ConfigParser()
config.read('i.cfg')

# ########## 讀 ##########
#secs = config.sections()
#print(secs)
#options = config.options('group2') # 獲取指定section的keys
#print(options)

#item_list = config.items('group2') # 獲取指定 section 的 keys & values ,key value 以元組的形式
#print(item_list)

#val = config.get('group1','key') # 獲取指定的key 的value
#val = config.getint('group1','key')

# ########## 改寫 ##########
#sec = config.remove_section('group1') # 刪除section 並返回狀態(true, false)
#config.write(open('i.cfg', "w")) # 對應的刪除操做要寫入文件纔會生效

#sec = config.has_section('wupeiqi')
#sec = config.add_section('wupeiqi')
#config.write(open('i.cfg', "w")) # 


#config.set('group2','k1',11111)
#config.write(open('i.cfg', "w"))

#config.remove_option('group2','age')
#config.write(open('i.cfg', "w"))
```

4.11        hashlib模塊

Hash,通常翻譯作「散列」,也有直接音譯爲」哈希」的,就是把任意長度的輸入(又叫作預映射,pre-image),經過散列算法,變換成固定長度的輸出,該輸出就是散列值。這種轉換是一種壓縮映射,也就是,散列值的空間一般遠小於輸入的空間,不一樣的輸入可能會散列成相同的輸出,而不可能從散列值來惟一的肯定輸入值。

簡單的說就是一種將任意長度的消息壓縮到某一固定長度的消息摘要的函數。

HASH主要用於信息安全領域中加密算法,他把一些不一樣長度的信息轉化成雜亂的128位的編碼裏,叫作HASH值.也能夠說,hash就是找到一種數據內容和數據存放地址之間的映射關係

什麼是MD5算法

MD5訊息摘要演算法(英語:MD5 Message-Digest Algorithm),一種被普遍使用的密碼雜湊函數,能夠產生出一個128位的散列值(hash value),用於確保信息傳輸完整一致。MD5的前身有MD二、MD3和MD4。

MD5功能

輸入任意長度的信息,通過處理,輸出爲128位的信息(數字指紋);
不一樣的輸入獲得的不一樣的結果(惟一性);

MD5算法的特色

  1. 壓縮性:任意長度的數據,算出的MD5值的長度都是固定的
  2. 容易計算:從原數據計算出MD5值很容易
  3. 抗修改性:對原數據進行任何改動,修改一個字節生成的MD5值區別也會很大
  4. 強抗碰撞:已知原數據和MD5,想找到一個具備相同MD5值的數據(即僞造數據)是很是困難的。

MD5算法是否可逆?

MD5不可逆的緣由是其是一種散列函數,使用的是hash算法,在計算過程當中原文的部分信息是丟失了的。

MD5用途

  1. 防止被篡改:

    • 好比發送一個電子文檔,發送前,我先獲得MD5的輸出結果a。而後在對方收到電子文檔後,對方也獲得一個MD5的輸出結果b。若是a與b同樣就表明中途未被篡改。

    • 好比我提供文件下載,爲了防止不法分子在安裝程序中添加木馬,我能夠在網站上公佈由安裝文件獲得的MD5輸出結果。

    • SVN在檢測文件是否在CheckOut後被修改過,也是用到了MD5.

  2. 防止直接看到明文:

    • 如今不少網站在數據庫存儲用戶的密碼的時候都是存儲用戶密碼的MD5值。這樣就算不法分子獲得數據庫的用戶密碼的MD5值,也沒法知道用戶的密碼。(好比在UNIX系統中用戶的密碼就是以MD5(或其它相似的算法)經加密後存儲在文件系統中。當用戶登陸的時候,系統把用戶輸入的密碼計算成MD5值,而後再去和保存在文件系統中的MD5值進行比較,進而肯定輸入的密碼是否正確。經過這樣的步驟,系統在並不知道用戶密碼的明碼的狀況下就能夠肯定用戶登陸系統的合法性。這不但能夠避免用戶的密碼被具備系統管理員權限的用戶知道,並且還在必定程度上增長了密碼被破解的難度。)
  3. 防止抵賴(數字簽名):

    • 這須要一個第三方認證機構。例如A寫了一個文件,認證機構對此文件用MD5算法產生摘要信息並作好記錄。若之後A說這文件不是他寫的,權威機構只需對此文件從新產生摘要信息,而後跟記錄在冊的摘要信息進行比對,相同的話,就證實是A寫的了。這就是所謂的「數字簽名」。

SHA-1

安全哈希算法(Secure Hash Algorithm)主要適用於數字簽名標準(Digital Signature Standard DSS)裏面定義的數字簽名算法(Digital Signature Algorithm DSA)。對於長度小於2^64位的消息,SHA1會產生一個160位的消息摘要。當接收到消息的時候,這個消息摘要能夠用來驗證數據的完整性。

SHA是美國國家安全局設計的,由美國國家標準和技術研究院發佈的一系列密碼散列函數。

因爲MD5和SHA-1於2005年被山東大學的教授王小云破解了,科學家們又推出了SHA224, SHA256, SHA384, SHA512,固然位數越長,破解難度越大,但同時生成加密的消息摘要所耗時間也更長。目前最流行的是加密算法是SHA-256 .

MD5與SHA-1的比較

因爲MD5與SHA-1均是從MD4發展而來,它們的結構和強度等特性有不少類似之處,SHA-1與MD5的最大區別在於其摘要比MD5摘要長32 比特。對於強行攻擊,產生任何一個報文使之摘要等於給定報文摘要的難度:MD5是2128數量級的操做,SHA-1是2160數量級的操做。產生具備相同摘要的兩個報文的難度:MD5是264是數量級的操做,SHA-1 是280數量級的操做。於是,SHA-1對強行攻擊的強度更大。但因爲SHA-1的循環步驟比MD5多80:64且要處理的緩存大160比特:128比特,SHA-1的運行速度比MD5慢。

Python的提供的相關模塊

用於加密相關的操做,3.x裏代替了md5模塊和sha模塊,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法

import hashlib

m = hashlib.md5()
m.update(b"Hello")
m.update(b"It's me")
print(m.digest())
m.update(b"It's been a long time since last time we ...")

print(m.digest()) #2進制格式hash
print(len(m.hexdigest())) #16進制格式hash
'''
def digest(self, *args, **kwargs): # real signature unknown
    """ Return the digest value as a string of binary data. """
    pass

def hexdigest(self, *args, **kwargs): # real signature unknown
    """ Return the digest value as a string of hexadecimal digits. """
    pass

'''
import hashlib

# ######## md5 ########

hash = hashlib.md5()
hash.update('admin')
print(hash.hexdigest())

# ######## sha1 ########

hash = hashlib.sha1()
hash.update('admin')
print(hash.hexdigest())

# ######## sha256 ########

hash = hashlib.sha256()
hash.update('admin')
print(hash.hexdigest())


# ######## sha384 ########

hash = hashlib.sha384()
hash.update('admin')
print(hash.hexdigest())

# ######## sha512 ########

hash = hashlib.sha512()
hash.update('admin')
print(hash.hexdigest())

4.12        subprocess模塊

咱們常常須要經過Python去執行一條系統命令或腳本,系統的shell命令是獨立於你的python進程以外的,每執行一條命令,就是發起一個新進程,經過python調用系統命令或腳本的模塊在python2有os.system,如:

>>> os.system('uname -a')
Darwin Alexs-MacBook-Pro.local 15.6.0 Darwin Kernel Version 15.6.0: Sun Jun  4 21:43:07 PDT 2017; root:xnu-3248.70.3~1/RELEASE_X86_64 x86_64
0

這條命令的實現原理是什麼呢?(視頻中講,解釋進程間通訊的問題...)

除了os.system能夠調用系統命令,,commands,popen2等也能夠,比較亂,因而官方推出了subprocess,目地是提供統一的模塊來實現對系統命令或腳本的調用

The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several older modules and functions:

  • os.system
  • os.spawn*

The recommended approach to invoking subprocesses is to use the run() function for all use cases it can handle. For more advanced use cases, the underlying Popen interface can be used directly.

The run() function was added in Python 3.5; if you need to retain compatibility with older versions, see the Older high-level API section.

三種執行命令的方法

  • subprocess.run(*popenargs, input=None, timeout=None, check=False, **kwargs) #官方推薦

  • subprocess.call(*popenargs, timeout=None, **kwargs) #跟上面實現的內容差很少,另外一種寫法

  • subprocess.Popen() #上面各類方法的底層封裝

run()方法

Run command with arguments and return a CompletedProcess instance.The returned instance will have attributes args, returncode, stdout and stderr. By default, stdout and stderr are not captured, and those attributes will be None. Pass stdout=PIPE and/or stderr=PIPE in order to capture them.

If check is True and the exit code was non-zero, it raises a CalledProcessError. The CalledProcessError object will have the return code in the returncode attribute, and output & stderr attributes if those streams were captured.

If timeout is given, and the process takes too long, a TimeoutExpired exception will be raised.

The other arguments are the same as for the Popen constructor.

標準寫法

subprocess.run(['df','-h'],stderr=subprocess.PIPE,stdout=subprocess.PIPE,check=True

涉及到管道|的命令須要這樣寫

subprocess.run('df -h|grep disk1',shell=True) #shell=True的意思是這條命令直接交給系統去執行,不須要python負責解析

call()方法

#執行命令,返回命令執行狀態 , 0 or 非0
>>> retcode = subprocess.call(["ls", "-l"])

#執行命令,若是命令結果爲0,就正常返回,不然拋異常
>>> subprocess.check_call(["ls", "-l"])
0

#接收字符串格式命令,返回元組形式,第1個元素是執行狀態,第2個是命令結果 
>>> subprocess.getstatusoutput('ls /bin/ls')
(0, '/bin/ls')

#接收字符串格式命令,並返回結果
>>> subprocess.getoutput('ls /bin/ls')
'/bin/ls'

#執行命令,並返回結果,注意是返回結果,不是打印,下例結果返回給res
>>> res=subprocess.check_output(['ls','-l'])
>>> res
b'total 0\ndrwxr-xr-x 12 alex staff 408 Nov 2 11:05 OldBoyCRM\n'

Popen()方法

經常使用參數:

  • args:shell命令,能夠是字符串或者序列類型(如:list,元組)
  • stdin, stdout, stderr:分別表示程序的標準輸入、輸出、錯誤句柄
  • preexec_fn:只在Unix平臺下有效,用於指定一個可執行對象(callable object),它將在子進程運行以前被調用
  • shell:同上
  • cwd:用於設置子進程的當前目錄
  • env:用於指定子進程的環境變量。若是env = None,子進程的環境變量將從父進程中繼承。

下面這2條語句執行會有什麼區別?

a=subprocess.run('sleep 10',shell=True,stdout=subprocess.PIPE)
a=subprocess.Popen('sleep 10',shell=True,stdout=subprocess.PIPE)

區別是Popen會在發起命令後馬上返回,而不等命令執行結果。這樣的好處是什麼呢?

若是你調用的命令或腳本 須要執行10分鐘,你的主程序不需卡在這裏等10分鐘,能夠繼續往下走,幹別的事情,每過一會,經過一個什麼方法來檢測一下命令是否執行完成就行了。

Popen調用後會返回一個對象,能夠經過這個對象拿到命令執行結果或狀態等,該對象有如下方法

poll()

Check if child process has terminated. Returns returncode

wait()

Wait for child process to terminate. Returns returncode attribute.

terminate()終止所啓動的進程Terminate the process with SIGTERM

kill() 殺死所啓動的進程 Kill the process with SIGKILL

communicate()與啓動的進程交互,發送數據到stdin,並從stdout接收輸出,而後等待任務結束

>>> a = subprocess.Popen('python3 guess_age.py',stdout=subprocess.PIPE,stderr=subprocess.PIPE,stdin=subprocess.PIPE,shell=True)

>>> a.communicate(b'22')

(b'your guess:try bigger\n', b'')

send_signal(signal.xxx)發送系統信號

pid 拿到所啓動進程的進程號

相關文章
相關標籤/搜索