環境搭建
單機環境搭建
安裝python
apt-get install python python-dev python-setuptools
安裝pip
apt-get install python-pip
簡單主機信息
說明:主要參考網站psutil文檔
安裝psutil
pip install psutil
cpu
cpu times
import psutil
cputimes = psutil.cpu_times()
psutil.cpu_times().user
結果如下:
scputimes(user=1751.49, nice=57.5, system=1126.75, idle=61666.12, iowait=745.43, irq=0.0, softirq=1.58, steal=0.0, guest=0.0, guest_nice=0.0)
解釋: user:用戶cpu time; nice: ; system:系統cpu time; idle:cpu空閒狀態cpu time; iowait:io等待時間;
取出cpu_times()中的參數,例如用戶cpu時間
psutil.cpu_times().user
獲取物理cpu個數
psutil.cpu_count(lgicol=False)
內存和交換分區
內存信息
psutil.virtual_memory()
結果如下:
svmem(total=8288972800L, available=6737719296L, percent=18.7, used=3927216128L, free=4361756672L, active=2380361728, inactive=1244004352, buffers=150831104L, cached=2225131520)
解釋 total: 所有物理內存 available: 實際上可以立刻使用的內存(單位是byte) percent:內存使用的內存(total - available) / total * 100. used: 使用的內存 free: 空閒內存 Platform-specific fields:特定平臺的屬性
active: (UNIX): memory currently in use or very recently used, and so it is in RAM. inactive: (UNIX): 未被使用的內存 buffers: (Linux, BSD): 文件緩存 cached: (Linux, BSD): 緩存 wired: (BSD, OSX):常駐內存 在RAM中的 shared: (BSD): 共享內存
交換分區
psutil.virtual_memory()
結果:
sswap(total=4999606272L, used=0L, free=4999606272L, percent=0.0, sin=0, sout=0)
硬盤
分區信息
psutil.disk_partitions()
結果:
[sdiskpart(device='/dev/sda4', mountpoint='/', fstype='ext4', opts='rw,errors=remount-ro')]
使用信息
psutil.disk_usage('/')
結果:
sdiskusage(total=202632327168, used=6518771712, free=185796829184, percent=3.2)
進程信息
pid=3923
p = psutil.Process(pid)
#print process name
p.name()
#print process execuable file path
p.exe()
#print process current work directory
p.cwd()
#print process children process
p.get_children()
net IO
psutil.net_io_counters()
結果:
snetio(bytes_sent=4469434, bytes_recv=64367107, packets_sent=40469, packets_recv=53242, errin=0, errout=0, dropin=0, dropout=0)
Ip information
IPy模塊處理IP信息
- 安裝
sudo pip install Ipy
- IPy包中的IP類 2.1 列出網段中的IP數目:
ip = IP('8.8.8.8')
for i in ip:
print (x)
2.2 IP轉換
ip.int()#將IP轉爲整數型
ip.strHex()#將IP轉爲十六進制
ip.strBIn()#將IP轉爲二進制
2.3 將十六進制的IP地址轉換成爲常見的澱粉十進制
print(IP(0x8080808))#輸出爲8.8.8.8
2.4 生成子網掩碼
IP('8.8.8.8').make_net('255.255.255.0)
IP('8.8.8.8/255.255.255.0',make_net=True)
dns information
- 安裝dnspython
sudo pip install dnspython
- 域名解析知識清理:
- A記錄:域名轉爲IP地址
- MX記錄:郵件交換記錄,定義郵件服務器的域名信息
- CNAME記錄:實現域名見的映射。別名記錄
- NS記錄:標記區域的域名服務器授權服務器和授權子域
- PTR記錄:反響解析,與A記錄相反
- SOA記錄:標記一個其實授權去的定義
A記錄解析過程:
import dns.resolver
domain = "www.google.com"
A = dns.resolver.query(domain,'A')
for x in A.response.answer:
for i in x:
print (i.address)
MX記錄解析
#! /usr/bin/python
import dns.resolver
domain="163.com"
MX = dns.resolver.query(domain,'MX')
for i in MX:
print i.preference, i.exchange
NS記錄解析
#! /usr/bin/python
import dns.resolver
domain= "baidu.com"
NC = dns.resolver.query(domain,'Ns')
for x in NC.response.answer:
for i in x.items:
print i.to_text()
CNAME記錄解析
#!/usr/bin/python
import dns.resolver
domain = "www.baidu.com"
cname = dns.resolver.query(domain,'CNAME')
for i in cname.response.answer:
for j in i.items:
print (j.to_text())
實例:DNS輪循服務業務監控
#! /usr/bin/python
import dns.resolver
import os
import httplib
iplist=[]
domain = "baidu.com"
def getIpList(domain=""):
try:
A = dns.resolver.query(domain,'A')
except Exception,e:
print "dns resolver error:"+str(e)
return
for x in A.response.answer:
for i in x.items:
iplist.append(i.address)
return True
def checkIp(ip):
checkurl = ip + ":80"
getcontent = ""
httplib.socket.setdefaulttimeout(5)
conn = httplib.HTTPConnection(checkurl)
try:
conn.request("GET","/",headers={"Host":domain})
r = conn.getresponse()
getcontent = r.read(15)
finally:
if getcontent == "<!doctype html>":
print ip+"[OK]"
else:
print ip+"[Error]"
print getcontent+"\n"
if __name__ =="__main__":
if(getIpList(domain) and len(iplist)>0):
for ip in iplist:
checkIp(ip)
else:
print "dns resolver error."
業務服務質量監控
文本內容對比工具
#!/usr/bin/python
#coding:utf-8
import difflib
import sys
try:
firstfile = sys.argv[1]#python 的參數是從一開始的
secondfile = sys.argv[2]
except Exception,e:
print ("Error:"+ str(e))
print ("Usage: compare.py file1 file2")
sys.exit()
def readfile(path):
try:
filehandle = open(path,'r')
text = filehandle.read().splitlines()
filehandle.close()
return text
except IOError as error:
print ("Read file error:" + str(error))
print ("Usage: compare.py file1 file2")
sys.exit()
if(firstfile =="" or secondfile ==""):
print ("Usage: compare.py file1 file2")
sys.exit()
file1lines = readfile(firstfile)
file2lines = readfile(secondfile)
diff = difflib.HtmlDiff()
print diff.make_file(file1lines,file2lines)
文件目錄差異對比工具
python
自帶的filecmp
滿足需求。
filecmp模塊常見的方法的說明
filecmp
常見的方法有:cmp(單文件對比),cmpfiles(多文件對比),dircmp(目錄對比)
+ filecmp.cmp(f1,f2[,shallow=True])
:對比文件f1和f2是否相同,相同就返回True,不同爲False。shallow爲可選的參數,默認爲True。shallow爲True時表示根據文件的屬性值(最後修改時間,作者,狀態改變時間等)進行對比判斷兩文件是否相同;shallow爲false時,同時對比os.stat()和對比兩文件的內容判斷是否相同。
+ filecmp.cmpfiles(dir1,dir2[,shallow=True]).對比dir1和dir2給定的文件清單。該方法返回三個列表:匹配,不匹配,錯誤(目錄中不存在,讀寫權限不夠,或其他原因導致的不能比較的清單)。
+ filecmp.dircmp(a,b[,ignore[,hide]])創建一個目錄比較對象,a,b,是參加比較的目錄名,ignore是忽略的文件列表,並默認爲['RCS','CVS',tags'];hide表示隱藏的文件愛你列表,默認爲[os.curdir,os.pardir]。dircmp類可以獲得目錄比較的詳細信息,如只有a含有的文件。dircmp提供3個輸出報告的方式:
* report():比較當前目錄的內容
* report_partial_closure():比較當前目錄和第一級子目錄的內容
* report_full_clourse():遞歸比較所有的文件
校驗源與備份目錄的差異
python
shutil
模塊常見函數:
copyfile( src, dst)
從源src複製到dst中去。當然前提是目標地址是具備可寫權限。拋出的異常信息爲IOException. 如果當前的dst已存在的話就會被覆蓋掉copymode( src, dst)
只是會複製其權限其他的東西是不會被複制的copystat( src, dst)
複製權限、最後訪問時間、最後修改時間copy( src, dst)
複製一個文件到一個文件或一個目錄copy2( src, dst)
在copy上的基礎上再複製文件最後訪問時間與修改時間也複製過來了,類似於cp –p的東西copy2( src, dst)
如果兩個位置的文件系統是一樣的話相當於是rename操作,只是改名;如果是不在相同的文件系統的話就是做move操作copytree(olddir,newdir,True/Flase)
把olddir拷貝一份newdir,如果第3個參數是True,則複製目錄時將保持文件夾下的符號連接,如果第3個參數是False,則將在複製的目錄下生成物理副本來替代符號連接
使用python發送郵件
簡單郵件發送
1.smtplib.SMTP(host,port[,local_hostname[,timeout]])
構造smtp類,每個參數的含義:
- host:郵件服務器地址
- port:郵件服務器端口
- local_hostname:在本地主機的FQDN發送HELO/EHLO(標識身份)指令
- timeout:超時時間,單位s(秒)
#! /usr/bin/python
# coding:utf-8
import smtplib
import string
HOST = "smtp.google.com"
SUBJECT = "TEST EMAIL"
TO = "[email protected]"
FROM = "[email protected]"
text = "this is the mail body main test!"
other = "other info" #BODY中的other如果包含字符,則收到的郵件中沒有內容,爲什麼?這個字段是什麼意思?
BODY = string.join(
(
"From: %s" % FROM,
"TO: %s" % TO,
"Subject: %s" % SUBJECT,
other,
text
), "\r\n"
)
server = smtplib.SMTP()
server.connect(HOST, 25)
server.starttls()
server.login("[email protected]", "password")
server.sendmail(FROM, TO, BODY)
server.quit()
定製豐富內容的郵件
1.使用html編寫郵件內容
#! /usr/bin/python
# coding:utf-8
import smtplib
from email.mime.text import MIMEText
HOST = "smtp.qq.com"
SUBJECT = u"官方流量數據報表"
FROM = "[email protected]"
TO = "[email protected]"
msg = MIMEText("""
<table width="800" b cellspacing="0" order="0">
<tr>
<td bgcolor="gray" style="font-size:14px">
*官網數據
</td>
</tr>
<tr>
<td>
<ol>
<li>日訪問量:<font color=red>152433</font> 訪問次數:23651 頁面瀏覽量:45123 點擊數:545122 數據流量:504Mb</li>
<li>狀態碼信息:<br></li> 500:105 404:3264 503:214
<li>瀏覽器瀏覽信息:<br></li> IE:50% firefox:10% chrome:30% other:10%
<li>頁面信息:<br></li> /index.php 42153<br> /view.php 21451<br> /login.php 5122<br>
</ol>
</td>
</tr>
</table>
""", "html", "utf-8"
)
msg['Subject'] = SUBJECT
msg['From'] = FROM
msg['TO'] = TO
try:
server = smtplib.SMTP()
server.connect(HOST, "25")
server.starttls()
server.login("[email protected]", "password")
server.sendmail(FROM, TO, msg.as_string())
server.quit()
print("郵件發送成功!")
except Exception, e:
print("失敗!原因:"+str(e))
注意點 在使用
email.mime.text.MIMEText
對象的時候,需要將MIMEText對象的內容,編碼和內容使用的語言交代清楚。
2.在郵件中添加圖片
- 定義一個
email.mime.multipart.MIMEMultipart
對象 - 使用
MIMEMultipart
對象的attach
函數,將html
內容嵌入到郵件中,其中使用contentID
來訪問嵌入到郵件中的圖片信息 - 使用
MIMEImage
對象,將圖片文件從本地以二進制的形式讀入到內存,並用圖像文件的二進制序列初始化MIMEImage
對象,使用MIMEImage
的add_header()
方法給MIMEImage
對象設置contentID
- 使用
MIMEMultipart
對象的attach
函數,將MIMEImage
對象嵌入到郵件中
#! /usr/bin/python
# coding:utf-8
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
__author__ = 'hgf'
HOST = "smtp.qq.com"
SUBJECT = u"業務性能數據表"
FROM = "[email protected]"
TO = "[email protected]"
def addimg(src, imgid):
fp = open(src, 'rb')
msgImg = MIMEImage(fp.read())
fp.close()
msgImg.add_header('Content-ID', imgid)
return msgImg
# 使用related定義內嵌資源
msg = MIMEMultipart('related')
msgtext = MIMEText("""
<table width="800" b cellspacing="0" order="0">
<tr>
<td bgcolor="gray" style="font-size:14px">
*官網logo
</td>
</tr>
<tr bgcolor="#EFEBDE" height="100" style="font-size:13px">
<td>
<img src="cid:p1">
</td>
<td>
<img src="cid:p2">
</td>
</tr>
<tr bgcolor="#EFEBDE" height="100" style="font-size:13px">
<td>
<img src="cid:p3">
</td>
<td>
<img src="cid:p4">
</td>
</tr>
</table>
""", "html", "utf-8")
msg.attach(msgtext)
msg.attach(addimg("/home/hgf/Pictures/program/logo/1.PNG", "p1"))
msg.attach(addimg("/home/hgf/Pictures/program/logo/2.PNG", "p2"))
msg.attach(addimg("/home/hgf/Pictures/program/logo/3.PNG", "p3"))
msg.attach(addimg("/home/hgf/Pictures/program/logo/4.PNG", "p4"))
msg['Subject'] = SUBJECT
msg['From'] = FROM
msg['To'] = TO
try:
server = smtplib.SMTP()
server.connect(HOST, 25)
server.starttls()
server.login(FROM, "password")
server.sendmail(FROM, TO, msg.as_string())
server.quit()
print("發送成功")
except Exception, e:
print("失敗!原因:"+str(e))
3.在郵件中添加附件
- 初始化
MIMEText
對象作爲附件:將本地的文件以讀取二進制的方式,將文件內容用於初始化MIMEText
對象,設置MIMEText
的格式爲base64編碼
,文字編碼爲utf-8
- 設置
MIMEText
實例的Content-Type
屬性爲application/octet-stream
(專用來說明不知道文件類型的二進制流), - 設置
MIMEText
實例的Content-Disposition
屬性爲attachment;filename=文件名
,使得附件可以用來下載 - 將
MIMEText
實例attach
到MIMEMultipart對象中
#! /usr/bin/python
# coding:utf-8
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.mime.text import MIMEText
__author__ = 'hgf'
HOST = "smtp.qq.com"
SUBJECT = u"業務性能數據表"
FROM = "[email protected]"
TO = "[email protected]"
def addimg(src, imgid):
fp = open(src, 'rb')
msgImg = MIMEImage(fp.read())
fp.close()
msgImg.add_header('Content-ID', imgid)
return msgImg
msg = MIMEMultipart('related')
msgtext = MIMEText("""
<font>官網業務平均時延圖表:<br><img src=\"cid:p1\" border =\"1\"><br>詳細內附件圖表</font>
""", "html", "utf-8")
msg.attach(msgtext)
msg.attach(addimg("/home/hgf/Pictures/program/logo/1.PNG", "p1"))
attach = MIMEText(open("/home/hgf/test.xlsx", 'rb').read(), "base64", "utf-8")
attach["Content-type"] = "application/octet-stream"
# 指定文件格式類型
# 指定ContentDisposition 屬性值爲attachement 則會出現自愛在保存對話框
# qqmail使用gb18030編碼,爲保證中文不會亂碼,對文件名進行編碼轉換
attach["Content-Disposition"] = "attachment;filename=\"excel.xlsx\"".decode("utf-8").encode("gb18030")
msg.attach(attach)
msg['Subject'] = SUBJECT
msg['From'] = FROM
msg['To'] = TO
try:
server = smtplib.SMTP()
server.connect(HOST, 25)
server.starttls()
server.login(FROM, "passwprd")
server.sendmail(FROM, TO, msg.as_string())
server.quit()
print("發送成功!")
except Exception, e:
print("發送失敗:"+str(e))
web服務器性能
安裝pycurl
- 安裝curl:
sudo apt-get install curl
- 安裝openssl:
apt-get install openssl
- 安裝pycurl:
sudo pip install pycurl
TIPS:
In [2]: pycurl.version Out[2]: 'PycURL/7.19.5.1 libcurl/7.35.0 OpenSSL/1.0.1f zlib/1.2.8 libidn/1.28 librtmp/2.3'
安裝問題
- 錯誤
__main__.ConfigurationError: Could not run curl-config: [Errno 2] No such file or directory
Downloading/unpacking pycurl
Running setup.py egg_info for package pycurl
Traceback (most recent call last):
File "<string>", line 16, in <module>
File "/tmp/pip-build-root/pycurl/setup.py", line 563, in <module>
ext = get_extension()
File "/tmp/pip-build-root/pycurl/setup.py", line 368, in get_extension
ext_config = ExtensionConfiguration()
File "/tmp/pip-build-root/pycurl/setup.py", line 65, in __init__
self.configure()
File "/tmp/pip-build-root/pycurl/setup.py", line 100, in configure_unix
raise ConfigurationError(msg)
__main__.ConfigurationError: Could not run curl-config: [Errno 2] No such file or directory
Complete output from command python setup.py egg_info:
Traceback (most recent call last):
File "<string>", line 16, in <module>
File "/tmp/pip-build-root/pycurl/setup.py", line 563, in <module>
ext = get_extension()
File "/tmp/pip-build-root/pycurl/setup.py", line 368, in get_extension
ext_config = ExtensionConfiguration()
File "/tmp/pip-build-root/pycurl/setup.py", line 65, in __init__
self.configure()
File "/tmp/pip-build-root/pycurl/setup.py", line 100, in configure_unix
raise ConfigurationError(msg)
__main__.ConfigurationError: Could not run curl-config: [Errno 2] No such file or directory
解決方案:
在debian系列操作系統中需要安裝openssl
sudo apt-get install libcurl4-openssl-dev
簡單使用curl
#! /usr/bin/python
# coding:utf-8
import pycurl
__author__ = 'hgf'
c = pycurl.Curl()
c.setopt(pycurl.URL, "http://www.baidu.com")
c.setopt(pycurl.CONNECTTIMEOUT, 5)
c.setopt(pycurl.NOPROGRESS, 0)
c.setopt(pycurl.FORBID_REUSE, 1)
f = open("a.txt",'wb')
c.setopt(pycurl.WRITEHEADER, f)
c.setopt(pycurl.WRITEDATA, f)
c.setopt(pycurl.DNS_CACHE_TIMEOUT, 30)
c.perform()
c.close()
** 注意: ** 使用pycurl必須定義pycurl.URL的值,必須調用perform函數使pycurl生效,並且一般需要定義處理pycurl返回的結果。
使用curl探測web服務質量
#! /usr/bin/python
# coding:utf-8
import pycurl
import os
import sys
__author__="hgf"
URL = "http://www.baidu.com"
c = pycurl.Curl()
c.setopt(pycurl.URL, URL)
c.setopt(pycurl.CONNECTTIMEOUT, 5)
c.setopt(pycurl.TIMEOUT, 5)
c.setopt(pycurl.NOPROGRESS, 1)
c.setopt(pycurl.FORBID_REUSE, 1)
c.setopt(pycurl.DNS_CACHE_TIMEOUT, 30)
c.setopt(pycurl.MAXREDIRS, 1)
indexfile = open(os.path.dirname(os.path.realpath(__file__))+"/content.txt",'wb')
c.setopt(pycurl.WRITEHEADER, indexfile)
c.setopt(pycurl.WRITEDATA, indexfile)
try:
c.perform()
except Exception, e:
print ("error:"+str(e))
indexfile.close()
c.close()
sys.exit()
NAMELOOKUP_TIME = c.getinfo(c.NAMELOOKUP_TIME)
CONNECT_TIME = c.getinfo(c.CONNECT_TIME)
PRETRANSFER_TIME = c.getinfo(c.PRETRANSFER_TIME)
STARTTRANSFER_TIME = c.getinfo(c.STARTTRANSFER_TIME)
TOTAL_TIME = c.getinfo(c.TOTAL_TIME)
HTTP_CODE = c.getinfo(c.HTTP_CODE)
SIZE_DOWNLOAD = c.getinfo(c.SIZE_DOWNLOAD)
HEADER_SIZE = c.getinfo(c.HEADER_SIZE)
SPEED_DOWNLOAD = c.getinfo(c.SPEED_DOWNLOAD)
print "HTTP狀態碼:%s" % HTTP_CODE
print "DNS解析時間:%.2f ms" % (NAMELOOKUP_TIME*1000)
print "建立連接時間:%.2f ms" % (CONNECT_TIME*1000)
print "準備傳輸時間: %.2f ms" % (PRETRANSFER_TIME*1000)
print "傳輸開始時間:%.2f ms" % (STARTTRANSFER_TIME*1000)
print "傳輸結束時間: %.2f ms" % ((TOTAL_TIME - STARTTRANSFER_TIME)*1000)
print "下載數據包大小: %.2f bytes/s" % SIZE_DOWNLOAD
print "HTTP 頭部大小: %.2f byte" % HEADER_SIZE
print "下載速度:%.2f bytes/s" % SPEED_DOWNLOAD
indexfile.close()
c.close()
定製報表
python處理excel
安裝slsxwriter
pip install XlsxWriter
XlsxWriter常見方法的使用
-
Workbook類
Worlbook
對象代表了Excel的整個文件,並且存儲在磁盤上,- 構造方法:
Workbook(filename[, option])
- 主要的方法:
add_Worksheet([sheetname])
:添加一個新的工作表,不定義sheetname
時,默認爲sheet[工作表序號]
。add_format([proprties])
:創建一個新的格式對象來格式化單元格,參數proprties
爲dict類型, 指定一個單元格屬性的字典。- 例如:
workbook.add_format({'bold':True})
,設置加粗的單元格。 - 上述設置等價方式:
bold = workbook.add_format()
和bold.set_bold()
- 例如:
add_chart(options)
:在工作表中創建一個圖表對象,內部通過insert_chart()
實現。option爲dict類型。close()
:關閉工作表文件。
-
WorkSheet類
write(row, col, *args)
:將普通數據寫道單元格中,其中(row, col)
爲單元格在表格中的位置,起始位置爲(0,0)
;×args
爲要寫入的數據內容, 可以爲數字,字符串,格式對象。set_row(row, height, cell_format, option)
:設置行單元格的屬性,row
指定行位置;height
設置行高,單位爲像素;cell_format
爲format
類型,指定格式對象;參數option
是dict類型,設置行hiden
(隱藏),level
(組合分級),collapsed
(摺疊)。set_column(first_col, last_col, wodth, cell_format, option)
:設置一列或多列單元格屬性。參數wodth
(float類型)設置列寬,cell_format
和options
同上。insert_image(row, col, image[, option])
:插入圖片到指定單元格,支持PNG
,JPEG
,BMP
等圖片格式。image
(String類型)表示圖片的路徑。options
(dist類型):制定圖片的位置、比例、鏈接URL等。- 例如:worksheet.insert_image('B5', 'img/python-logo.jpg', {'url':'http://python.org'})`
-
Chart類
- 支持的圖表類型包括面積,條形圖,柱形圖,餅狀圖,散點圖,shares,雷達。
- 圖表通過
worksheet
的add_chart
方法創建圖表。chart = worksheet.add_chart({type,'column'})
創建一個柱形圖。
圖表類型說明: |類型關鍵字|圖表類型| |--------|-------| |area|面積樣式圖表| |bar|條形態| |column|柱形圖| |line|條形圖| |pie|餅狀圖| |scatter|散點圖| |stock|shares圖| |radar|雷達圖|
+ 通過`insert_chart()`方法將圖標插入到指定的地方。
+ 主要的方法:
- `chat.add_series(options)`:添加一個數據系列到圖表。
* 例子:
```python
chat.add_series({
'categories': '=Sheet1!$a$1:$A$5',
'values': '=Sheet1!$B$1:$B$5',
'line': {'color':'red'},
})
>說明:
>`add_series`最長見的option是
>`categories`:表示圖表標籤的範圍[將表格中的對應位置的內容作爲圖表的橫軸];
>`value`:圖表的數據範圍[表格中的範圍內的數據作爲畫圖的數據]
>`line`:圖標的線條屬性,包括顏色,寬度等。
>`name`:圖例項,[一個圖的多種內容的區分]
- `set_x_axis(options)`:設置X軸選項,
* 例子
```python
char.set_x_axis({
'name': 'Earning_per_!Quater',#設置X軸標題名字
'name_font': {'size':14, 'bold':True},#設置X軸標題字體
'num_foont': {'italic':True},#設置X軸數字字體
})
- `set_size(options)`:設置圖表大小。例如`chart.set_size({'width':720, 'height':576})`
- `set_title`:設置圖表的標題。`chart.set_title({'name':'Year End Result'})`
- `set_styke(style_id))':`style_id`爲不同數字代表不同的樣式。
- `set_table(options)`:設置X軸爲數字表格樣式
實例:定製自動化業務流量報表
python與rrdtool結合
安裝rrdtool
pip install python-rrdtool
可能的錯誤:
- I found a copy of pkgconfig, but there is no libxml-2.0.pc file around. You may want to set the PKG_CONFIG_PATH variable to point to its location. 原因:沒有安裝libxml 解決方案:
sudo apt-get install libxml2
sudo apt-get install libxml2-dev
- 出現
cannot find -lrrd
原因:庫文件沒有導入到ld檢索目錄中,或者是庫文件是在so後面加上了序號,導致找不到庫文件 解決方案:只需要使用ln命令,將帶號碼的so文件軟鏈接到不帶序號的庫文件,如sudo ln -sv librrd.so.4 librrd.so
python與系統安全
病毒掃描
nmap端口掃描
在使用python-nmap前,需要在操作系統上安裝namp:yum install namp
- 模塊說明
- PortScanner類【nmap端口掃描的封裝】
scan(self, host='127.0.0.1', ports=None, arguments='-sV')
:制定掃描的主機端口,nmap命令行掃描的參數。其中host
的參數形式可以是域名('scanne.nmap.org'),網段('192.168.0-255.1-127'或'192.168.128.20/20'),IP地址;ports表示掃描的端口,可以用22,53,110,143-4564
來表示;arguments爲字符串類型,是nmap命令行下的掃描參數。comman_line(self)
:返回掃描方法對應的命令行下面的nmap命令。scaninfo(self)
:掃描的信息,字典類型all_hosts(self)
:返回nmap掃描的主機清單,格式爲listhostname(self)
:返回掃描對西那個的名字state(self)
:返回掃描對象的狀態(主要包括up,down,unknow,skipped)all_protocals(self)
:返回掃描協議all_tcp(self)
:返回TCP協議端口tcp(self,port)
:返回TCP協議port端口的信息
- PortScannerHostDict類【存儲與訪問主機的掃描結果】
- 示例
#! /usr/bin/python
# -*- coding:utf-8 -*-
import nmap
import sys
__author__ = 'hgf'
def detailinfo(hosts, ports):
'''
使用nmap test hosts中的所有的ports,並輸出詳細的信息
:param hosts: 所有主機
:param ports:所有端口號
:return:
'''
try:
nm.scan(hosts = hosts, arguments='-v -sS -p'+ports)
except Exception,e:
print("Scan error:"+ str(e))
for host in nm.all_hosts():
print('-------------------------------------------------------------------------------------------------------')
print('Host: %s (%s)'% (host, nm[hosts].hostname()))
print('State: %s' % nm[host].state())
for proto in nm[host].all_protocols():
print('------------------------------------------------')
print('Protocal: %s'% proto)
iport = nm[host][proto].keys()
iport.sort()
for port in iport:
print('Port: %s \tstate: %s' %(port, nm[host][proto][port]['state']))
def printcsv(nm):
'''
將nmap的結果以excel表的格式輸出
:param nm: namp實例
:return:
'''
print('-----------------------------------------------------------------------------------------------------------')
print('print result as csv')
print(nm.csv())
def pingsweep(hosts,ports):
'''
根據ports端口,查詢網段內存活主機
:param hosts:網段
:param ports:端口
:return:
'''
nm.scan(hosts=hosts, arguments='-n -sP -PE -PA'+ports)
host_list=[(x,nm[x]['status']['state']) for x in nm.all_hosts()]
for host, state in host_list:
print('{0}:{1}'.format(host,state))
def call_back(host, scan_result):
print("----------------------------------")
print host, scan_result
def arsynNmap(hosts):
'''
異步Nmap
:param hosts:
:return:
'''
nma = nmap.PortScannerAsync()
nma.scan(hosts=hosts, arguments='-sP', callback=call_back)
while nma.still_scanning():
print('wait')
nma.wait(2)
# do some other things
scan_row=[]
input_data = raw_input("Please input hosts and ports:")
scan_row = input_data.split(' ')
if len(scan_row)!=2:
print("input error, example input \"192.168.1.0/24 80,433-560\"")
sys.exit(0)
hosts = scan_row[0]
ports = scan_row[1]
try:
nm = nmap.PortScanner()
except nmap.PortScannerError:
print("Nmap not found ", sys.exc_info()[0])
sys.exit(0)
except:
print("Unexcepted error!")
sys.exit(0)
arsynNmap(hosts)
pexpect
純python編寫的系統批量運維管理器。
安裝
sudo pip install pexpect
pexpect使用
pexpect主要有兩大功能:
run方法
run
方法主要替代原來的'os.system()'
spawn 類
spawn
主要實現了自動交互的功能。
注意:
spawn
;類不會解析shell命令中的元字符,包括重定向>
,管道|
,或者是通配符*
,但是我們可以使用給/bin/bash
傳遞參數的形式使用元字符。 例如:pexpect.spawn('/bin/bash -c "ls -al | grep LOG > logs.txt"')
- pexpect日誌輸出到文件:``` child = pexpect.spawn('some_command') fout = file('mylog.txt','w') child.logfile(fout)
* pexpect日誌輸出到標準輸出流:```
child = pexpect.spawn('some_command')
child.logfile = sys.stout
使用pexpect的注意事項
- 注意使用
scp
時,傳送文件的權限,當使用pexpect的命令中,包含用scp傳送權限比較高,或者傳送文件的所有者不是運行pexpect程序的人的時候,需要考慮處理文件權限的問題。特別是傳送系統配置文件時,就算root運行程序也不能傳送文件成功。 - 一般的使用步驟:
- 保證目錄下有那個文件
- 保證執行py的用戶有那個傳送文件的權限
paramiko
基於python實現的SSH2安全連接,支持認證及密鑰方式,可以實現遠程命令執行,文件傳輸,中間ssh代理等。
安裝paramiko
sudo pip install paramiko
paramiko的簡單test
#/usr/bin/python
# coding:utf-8
import paramiko
import sys
__author__='hgf'
try:
data = raw_input("Please input hostname username and password:").split()
if len(data)!=3:
print("input error! make sure your input like \"192.168.1.1 root 123456\"")
sys.exit(0)
except Exception,e:
print("Exception occourred!")
print (str(e))
hostname = data[0]
username = data[1]
password = data[2]
paramiko.util.log_to_file('sys.log')
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.connect(hostname = hostname, username = username, password = password)
stdin, stdout, stderr = ssh.exec_command('free -m')
print stdout.read()
ssh.close()
paramiko的核心組件
- SSHClient
-
connect方法
connect(self, hostname, port=22, username=None, password=None, pkey=None, key_filename=None, timeout=None, allow=True, look_for_keys=True. compress=False)
- 各個參數的含義:
hostname
:(str類型)目的主機port
:(int類型)端口號username
:(str類型)目的主機的用戶名(默認與當前的本地主機用戶名相同)password
:(str類型)密碼用於身份校驗或解鎖私鑰pkey
:(PKey類型)私鑰方式進行驗證key_filename
:(list(str))或者是str類型)一個文件名或是文件列表,用於私鑰的身分驗證timeout
:(int類型)設定鏈接的超時信息allow_agent
:(bool類型)設置爲False時,禁止連接到SSH代理look_for_keys
:(bool類型)False時禁止在~/.ssh目錄中搜索私鑰文件compress
:(bool類型) 設置爲True打開壓縮
-
exec_command
方法:遠程執行命令的方法,輸入輸出流爲標準的的輸入輸出流,錯誤流(stdin,stdout,stderr)exec_command(self, command, bufsize=-1)
command
:(str類型),執行的命令
-
load_system_host_keys
方法,指定遠程主機的公鑰記錄文件(默認爲~/.ssh/known_hosts
)load_system_host_keys(self, filename=None)
-
set_missing_host_key_policy
方法:設置遠程主機沒有本地主機密鑰或Hostskye的情況時的策略,目前支持3種。AutoAddPolicy
,自動添加主機名及主機密鑰到本地hostsKeys對象(具體時那個文件????),並保存。不依賴於load_system_host_keys()
的配置。RejectPolicy
,自動拒絕未知主機名和密鑰, 依賴load_system_host_keys
的配置。WarningPolicy
,用於記錄一個位置的主機名和密鑰的python警告,並接受。功能上與AutoAddPolicy
相似但是未知主機會有警告。
使用方法:
ssh = paramiko.SSHClient() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
說明: 可以通過
SSHClient
對象的invoke_shell
方法獲取paramiko
的Channel
,開啓命令調用.即使用Channel
的send()
方法,可以發送一系列的shell命令。例如:
ssh = paramiko.SSHClient() ssh.connect(hostname,username,password) channel = ssh.invoke_shell() channel.send('ls')
- SFTPClient
-
from_transport
方法:創建愛哪一個已經連通的SFTP客戶端通道from_transport(self, t)
- 參數
t
表和isyige已經驗證過的傳輸對象(paramiko.Transport
對象) - 例子:```python t = paramiko.Transport(('192.168.1.22',22)) t.connect(username='root', password = '123456') sftp = paramiko.SFTPClient.from_transport(t)
-
put
方法:上傳本地文件到遠程SFTP服務端put(self, localpath, remotepath, callback=None, confirm=True)
- 參數說明:
localpath
: (str類型)需要上傳的本地文件remotepath
:(str類型)遠程路徑callback(function (int, int))
:獲取已經接收的字節數及宗的傳輸字節數, 以便毀掉函數調用confirm
:文件上傳完畢後是否使用stat()
方法,以便確認文件的大小
注意:
remotepath
必須是文件路徑+文件名+文件擴展名的完整形式,不能只指定文件夾的名字- 例子:
localpath = '/home/access.log' remotepath = '/data/logs/access.log' sftp.put(localpath, remotepath)
-
get方法:從遠程sftp服務端下載文件到本地 +
get(self, remotepath, localpath, callback=None)
+ 參數說明: -remotepath
:(str類型)遠程文件路徑 -localpath
: (str類型)本地保存路徑 -callback(function (int, int))
:獲取已經接收的字節數及宗的傳輸字節數, 以便毀掉函數調用 >注意: >localpath
必須是文件路徑+文件名+文件擴展名的完整形式,不能只指定文件夾的名字 + 例子:python localpath = '/home/access.log' remotepath = '/data/logs/access.log' sftp.put(localpath, remotepath)
-
mkdir
:在遠程服務器上創建文件夾 -
remove
:刪除SFTP服務端指定的目錄 -
rename
:重命名SFTP服務端的文件或目錄 -
stat
:獲取SFTP服務端指定文件的信息 -
listdir
:獲取SFTP服務端指定的目錄列表,以python list的形式返回。#! /usr/bin/python import paramiko __author__ = 'hgf' username = "root" password = "1qaz2wsx" hostname = "10.109.33.163" port = 22 paramiko.util.log_to_file('log.txt') try: t = paramiko.Transport((hostname, port)) t.connect(username=username, password=password) sftp = paramiko.SFTPClient.from_transport(t) sftp.put('/home/hgf/authorized_keys', '/root/aaaaa',) sftp.get('/root/install.log', './server.log') sftp.mkdir('/root/test', '700') print(sftp.stat('/root/install.log')) sftp.rmdir('/root/a') print(sftp.listdir('/home')) t.close() except Exception, e: print "Error!" print(str(e))
Fabric
Fabric
在paramiko
的基礎上,做了更高一層的封裝
安裝
pip install fabric
全局屬性的設置
與全局屬性有關的是env
對象。
常用API
例子1
查看本地與遠程主機信息
例子2
動態獲取遠程目錄列表
例子3
網關模式文件的上傳
編寫webserver
python處理命令行提示
python主要是使用optparse處理命令行的提示功能,並且響應命令行的輸入參數。 例子:
MSG_USAGE = "program [-v] [-h]"
parser = OptionParser(MSG_USAGE)
parser.add_option("-v", "--version", action="store_true", dest="verbose", help="描述命令參數的用途")
opts, args = parser.parse_args()
if opts.verbose:
# 執行滿足參數-v後的運行程序
print "輸出系統的版本"
sys.exit()
python處理配置文件
python主要是使用configobj庫來處理配置文件。 詳細的使用請看《python配置文件configobj使用》
BaseHTTPServer.py源碼分析
BaseHTTPServer.py
源碼分析主要是方便理解如何自己編寫webserver。
從SocketServer.py
分析中可以知道其設計思想是將socket編程的監聽循環和客戶端處理劃分成Server
類和RequestHandler
類,而BaseHTTPServer
是基於SocketServer
基礎之上的,因此可以知道BaseHTTPServer
就是分別擴展Server
類和RequestHandler
類。BaseHTTPServer
實現了一個簡單的HTTP Server
,可以知道主要工作應該是擴展RequestHandler
的功能,處理客戶端的HTTP
請求,具體包括HTTP
協議解析,給客戶端返回HTTP
響應,日誌記錄等功能。
- HTTPServer
該類只是簡單包裝了SocketServer
中的TCPServer
類
- BaseHTTPRequestHandler
類定義:
class BaseHTTPRequestHandler(SocketServer.StreamRequestHandler):
擴展RequestHandler
需要覆蓋一個接口handler()
,定義如下:
def handle(self):
"""Handle multiple requests if necessary."""
self.close_connection = 1
self.handle_one_request()
while not self.close_connection:
self.handle_one_request()
主要處理的是HTTP是否保持連接的問題,如果保持連接就持續處理客戶請求,否則就結束了。
handle_one_request()
比較重要語句:
self.raw_requestline = self.rfile.readline(65537)
self.parse_request()
mname = 'do_' + self.command
if not hasattr(self, mname)
self.send_error(501, "Unsupported method (%r)" % self.command)
return
method = getattr(self, mname)
method()
self.wfile.flush() #actually send the response if not already done.
- 讀取第一行
raw_requestline
,一般格式應該是:COMMAND PATH VERSION\r\n
; - 解析請求,
parse_request()
主要的代碼都在處理raw_requestline
,最終得到self.command
,self.path
,self.request_version
幾個變量,然後就是利用mimetools.Message
解析頭部。 - 後面幾行代碼意思是根據HTTP方法獲取對應處理函數,其實就是根據GET或POST請求調用對應的
do_GET()
或do_POST()
方法,然後刷新輸出。
下面還有幾個的函數,功能都比較簡單:
def send_error(self, code, message=None):
def send_response(self, code, message=None):
def send_header(self, keyword, value):
def end_headers(self):
def log_request(self, code='-', size='-'):
def log_error(self, format, *args):
def log_message(self, format, *args):
總結:可以看到,BaseHTTPRequestHandler
主要實現了客戶端HTTP請求解析,以及一些輔助功能,如日誌記錄、錯誤處理、發送響應代碼等。
但是還沒有實現如何執行HTTP請求,簡單來說就是還需要實現諸如do_GET()
,do_POST()
等函數,具體執行對應的HTTP命令。
HTTP協議返狀態碼含義
- 1xx 狀態碼
表示臨時響應並需要請求者繼續執行操作的狀態碼。
* `100(繼續)` 請求者應當繼續提出請求。服務器返回此代碼表示已收到請求的第一部分,正在等待其餘部分。
* `101(切換協議)` 請求者已要求服務器切換協議,服務器已確認並準備切換。
- 2xx 狀態碼
表示成功處理了請求的狀態碼。
* `200(成功)` 服務器已成功處理了請求。通常,這表示服務器提供了請求的網頁。如果針對您的 robots.txt 文件顯示此狀態碼,則表示 Googlebot 已成功檢索到該文件。
* `201(已創建)` 請求成功並且服務器創建了新的資源。
* `202(已接受)` 服務器已接受請求,但尚未處理。
* `203(非授權信息)` 服務器已成功處理了請求,但返回的信息可能來自另一來源。
* `204(無內容)` 服務器成功處理了請求,但沒有返回任何內容。
* `205(重置內容)` 服務器成功處理了請求,但沒有返回任何內容。與 204 響應不同,此響應要求請求者重置文檔視圖(例如,清除表單內容以輸入新內容)。
* `206(部分內容)` 服務器成功處理了部分 GET 請求。
- 3xx 狀態碼
要完成請求,需要進一步操作。通常,這些**狀態碼用來重定向**。建議您在每次請求中使用重定向不要超過 5 次。您可以使用網站管理員工具查看一下 Googlebot 在抓取重定向網頁時是否遇到問題。診斷下的網絡抓取頁列出了由於重定向錯誤導致 Googlebot 無法抓取的網址。
* `300(多種選擇)` 針對請求,服務器可執行多種操作。服務器可根據請求者 (`user-agent`) 選擇一項操作,或提供操作列表供請求者選擇。
* `301(永久移動)` 請求的網頁已永久移動到新位置。服務器返回此響應(對 GET 或 HEAD 請求的響應)時,會自動將請求者轉到新位置。您應使用此代碼告訴 Googlebot 某個網頁或網站已永久移動到新位置。
* `302(臨時移動)` 服務器目前從不同位置的網頁響應請求,但申請人應當繼續使用原有位置來響應以後的請求。此代碼與響應 GET 和 HEAD 請求的 301 代碼類似,會自動將請求者轉到不同的位置,但不應使用此代碼來告訴 Googlebot 頁面或網站已經移動,因爲 Googlebot 要繼續抓取原來的位置並編制索引。
* `303(查看其他位置)` 請求者應當對不同的位置使用單獨的 GET 請求來檢索響應時,服務器返回此代碼。對於除 HEAD 之外的所有請求,服務器會自動轉到其他位置。
* `304(未修改)` 自從上次請求後,請求的網頁未修改過。服務器返回此響應時,不會返回網頁內容。如果網頁自請求者上次請求後再也沒有更改過,您應當將服務器配置爲返回此響應(稱爲 `If-Modified-Since HTTP` 標頭)。由於服務器可以告訴 Googlebot 自從上次抓取後網頁沒有變更,因此可節省帶寬和開銷。
* `305(使用代理)` 請求者只能使用代理訪問請求的網頁。如果服務器返回此響應,還表示請求者應當使用代理。
* `307(臨時重定向)` 服務器目前從不同位置的網頁響應請求,但請求者應當繼續使用原有位置來響應以後的請求。此代碼與響應 GET 和 HEAD 請求的 301 代碼類似,會自動將請求者轉到不同的位置,但您不應使用此代碼來告訴 Googlebot 某個網頁或網站已經移動,因爲 Googlebot 會繼續抓取原有位置並編制索引。
- 4xx 狀態碼
這些狀態碼錶示請求可能出錯,這妨礙了服務器的處理。
* `400(錯誤請求)` 服務器不理解請求的語法。
* `401(身份驗證錯誤)` 此頁要求授權。您可能不希望將此網頁納入索引。如果您的 Sitemap 中列出該網頁,您可以將其刪除。但如果您將其保留在您的 Sitemap 中,我們就不會抓取或索引該網頁(儘管該網頁將繼續保持錯誤狀態在此處列出)。如果我們將其作爲搜索抓取的一部分抓取,您可以在我們的網站管理員信息中查閱其原因。
* `403(禁止)` 服務器拒絕請求。如果您在 Googlebot 抓取您網站上的有效網頁時看到此狀態碼,可能是您的服務器或主機拒絕 Googlebot 訪問。
* `404(未找到)` 服務器找不到請求的網頁。例如,對於服務器上不存在的網頁經常會返回此代碼。
* `405(方法禁用)` 禁用請求中指定的方法。
* `406(不接受)` 無法使用請求的內容特性響應請求的網頁。
* `407(需要代理授權)` 此狀態碼與 401 類似,但指定請求者必須授權使用代理。如果服務器返回此響應,還表示請求者應當使用代理。
* `408(請求超時)` 服務器等候請求時發生超時。
* `409(衝突)` 服務器在完成請求時發生衝突。服務器必須在響應中包含有關衝突的信息。服務器在響應與前一個請求相沖突的 PUT 請求時可能會返回此代碼,以及兩個請求的差異列表。
* `410(已刪除)` 請求的資源永久刪除後,服務器返回此響應。該代碼與 404(未找到)代碼相似,但在資源以前存在而現在不存在的情況下,有時會用來替代 404 代碼。如果資源已永久刪除,您應當使用 301 指定資源的新位置。
* `411(需要有效長度)` 服務器不接受不含有效內容長度標頭字段的請求。
* `412(未滿足前提條件)` 服務器未滿足請求者在請求中設置的其中一個前提條件。
* `413(請求實體過大)` 服務器無法處理請求,因爲請求實體過大,超出服務器的處理能力。
* `414(請求的 URI 過長)` 請求的 URI(通常爲網址)過長,服務器無法處理。
* `415(不支持的媒體類型)` 請求的格式不受請求頁面的支持。
* `416(請求範圍不符合要求)` 如果頁面無法提供請求的範圍,則服務器會返回此狀態碼。
* `417(未滿足期望值)` 服務器未滿足"期望"請求標頭字段的要求。
- 5xx 狀態碼
這些狀態碼錶示服務器在處理請求時發生內部錯誤。這些錯誤可能是服務器本身的錯誤,而不是請求出錯。
* `500(服務器內部錯誤)` 服務器遇到錯誤,無法完成請求。
* `501(尚未實施)` 服務器不具備完成請求的功能。例如,服務器無法識別請求方法時則會返回此代碼。
* `502(錯誤網關)` 服務器作爲網關或代理,從上游服務器收到無效響應。
* `503(服務不可用)` 服務器目前無法使用(由於超載或停機維護)。通常,這只是暫時狀態。
* `504(網關超時)` 服務器作爲網關或代理,但是沒有及時從上游服務器收到請求。
* `505(HTTP 版本不受支持)` 服務器不支持請求中所用的 HTTP 協議版本。