python:經常使用模塊 知識整理

 

time模塊javascript

time.time()     # 時間戳:1487130156.419527
time.strftime("%Y-%m-%d %X")     #格式化的時間字符串:'2017-02-15 11:40:53'
time.localtime()    #本地時區的struct_time
time.gmtime()     #UTC時區的struct_time

 

 

時間戳 與 struct_time對象的相互轉換html

time.localtime(1473525444.037215) #時間戳到struct_time對象
time.mktime(time.localtime())    #struct_time對象到時間戳

時間字符串 與 struct_time對象的相互轉換java

time.strptime('2007-12-1 2-3-4','%Y-%m-%d %H-%M-%S')   #字符串到struct_time對象 
time.strftime("%Y-%m-%d %X", time.localtime())    #struct_time 到字符串

datetime模塊
這個應該更強大的time模塊python

datetime與字符串的互相轉化linux

datetime.date 表明年月日,datetime.time表明時分秒,datetime.datetime表明年月日時分秒
時間加減
a = datetime.datetime.now()
datetime.datetime.now()-a > datetime.timedelta(days=30)


三者都具備差很少的函數。主要功能web

datetime.datetime.fromtimestamp(time.time()) #1)時間戳到datetime.datetime對象
datetime.timedelta:datetime.datetime.now() + datetime.timedelta(hours=3) #2)時間加減對象,當前時間+3小時
datetime.datetime.now().replace(minute=3,hour=2). #3)時間替換

sys模塊ajax

sys.path.append 
sys.stdout sys.stderr sys.stdin 三流
sys.modules[__name__] 得到本模塊

random模塊

正則表達式

random.random() #(0,1)----float 大於0且小於1之間的小數
random.randint(1,3) #[1,3] 大於等於1且小於等於3之間的整數
random.randrange(1,3) #[1,3) 大於等於1且小於3之間的整數
random.choice([1,'23',[4,5]])#1或者23或者[4,5]
random.sample([1,'23',[4,5]],2)#列表元素任意2個組合
random.uniform(1,3) #大於1小於3的小數,如1.927109612082716 
item=[1,3,5,7,9]
random.shuffle(item) #打亂item的順序,至關於"洗牌"

 

os模塊redis

os模塊是與操做系統交互的一個接口
os.urandom(32)   #得到32字節的隨機數,字節類型
os.getcwd()    #獲取當前工做目錄,即當前python腳本工做的目錄路徑
os.chdir("dirname")   # 改變當前腳本工做目錄;至關於shell下cd
os.makedirs('dirname1/dirname2')    #可生成多層遞歸目錄
os.removedirs('dirname1')   # 若目錄爲空,則刪除,並遞歸到下一級目錄,如若也爲空,則刪除,依此類推
os.mkdir('dirname')   # 生成單級目錄;至關於shell中mkdir dirname
os.rmdir('dirname')   # 刪除單級空目錄,若目錄不爲空則沒法刪除,報錯;至關於shell中rmdir dirname
os.listdir('dirname')   # 列出指定目錄下的全部文件和子目錄,包括隱藏文件,並以列表方式打印
os.remove(‘filepath’)     # 刪除一個文件
os.rename("oldname","newname")   # 重命名文件/目錄
os.stat('path/filename')  # 獲取文件/目錄信息
os.name     #輸出字符串指示當前使用平臺。win->'nt'; Linux->'posix'
os.system("bash command")   # 運行shell命令,直接顯示
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所指向的文件或者目錄的最後修改時間
os.path.getsize(path)   #返回path的大小
注意:os.path.getsize() 和 f.seek(0,2) f.tell() 和os.stat(path).st_size 的結果相同

os.walk('dir_path')    # 詳細用法。os.walk()經常使用於獲取非執行目錄的絕對路徑,os.path.abspath(),只是將文件名加上當前目錄路徑
如何得到一個路徑下面全部的文件路徑:算法

import os
path = r'C:\Users\Administrator\Desktop\file'
for dirpath,dirnames,filenames in os.walk(path):
    for filename in filenames:
    print(os.path.join(dirpath,filename))

optparse模塊
比sys.argv更好的參數處理

op = optparse.OptionParser()
op.add_option('-s','--server',dest='server')
op.add_option('-p','--port',dest='port')
options, args = op.parse_args() #傳入完成,作解析

注意:options不是字典 option['server']會報錯,取值應該是options.server
外部傳參例子:
python ftpserver.py -s 127.0.0.1 -p 8080
輸出:
options: {'server':'127.0.0.1','port':'8080'}
args :[] #沒有定義綁定的信息。

shutil模塊
高級的 文件、文件夾、壓縮包 處理模塊

shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w')) #將文件內容拷貝到另外一個文件中:
shutil.copyfile('f1.log', 'f2.log') #拷貝文件,目標文件無需存在
shutil.copymode('f1.log', 'f2.log') #拷貝權限。內容、組、用戶均,不變目標文件必須存在
shutil.copystat('f1.log', 'f2.log') #拷貝狀態的信息,包括:mode bits, atime, mtime, flag,s目標文件必須存在
shutil.copy('f1.log', 'f2.log')    #拷貝文件和權限
shutil.copy2('f1.log', 'f2.log')    #拷貝文件和狀態信息
shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) #遞歸的去拷貝文件夾:目標目錄不能存在,注意對folder2目錄父級目錄要有可寫權限,ignore的意思是排除
shutil.rmtree('folder1'),#刪除非空文件夾 
shutil.move('folder1', 'folder3')   # 遞歸的去移動文件,它相似mv命令,其實就是重命名
ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data')     #建立壓縮包並返回文件路徑,例如:zip、tar:
    #將 /data下的文件打包放置 /tmp/目錄
#pyhton中含有對解壓操做的兩個模塊:zipfile,tarfile#

json模塊、pickle模塊
這兩個類都序列化用 
json強大在能夠在任何語言的數據交換。不能傳輸類,只能傳輸基本類型

json.dumps(xx) #轉化爲json字符串、參數能夠是字典、列表、元組、基本數據類型
json.loads(xx) #傳入json字符串,還原爲原來的數據,和eval不一樣的是,eval側重於語句,eval('1+1')能夠執行,json則能夠跨語言,

-----------------------------------------------------------------------------------------
json.dumps(books, default=lambda o: o.__dict__) . # 將對象轉化爲對象內部的字典,有遞歸效果

--------------------------------------------------------------------------------------------
#擴展json序列化引擎類,序列化datetime對象
class
CJsonEncoder(json.JSONEncoder): def default(self, obj): #if isinstance(obj, datetime): #return obj.strftime('%Y-%m-%d %H:%M:%S') if isinstance(obj, datetime.date): return obj.strftime('%Y-%m-%d %H:%M:%S') else: return json.JSONEncoder.default(self, obj) import json import datetime a = datetime.datetime.now() print(a) b = json.dumps(a,cls=CJsonEncoder) print(b)

 

附:django序列化(專門用於序列化django的models對象)

from django.core import serializers
ret = models.BookType.objects.all()
data = serializers.serialize("json", ret)    

pickle只能在python與python之間的交換,但什麼均可以支持,類,函數啊,函數只傳遞地址,不傳遞函數體,沒多大意義
注意: 使用pickle模塊,打開文件時須要'wb')模式,由於pickle.dumps(xx)#轉化爲字節 

shelve模塊
也是序列化模塊,操做爲{key:{}}形式

import shelve
f=shelve.open(r'sheve.txt')
f['stu1_info']={'name':'egon','age':18,'hobby':['piao','smoking','drinking']}
f['stu2_info']={'name':'gangdan','age':53}
f['school_info']={'website':'http://www.pypy.org','city':'beijing'}
print(f['stu1_info']['hobby'])
f.close()

 

hashlib模塊
hashlib在3.x裏代替了md5模塊和sha模塊,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法),該算法接受傳入的內容,通過運算獲得一串hash值
擴展:hash算法特色
  1.加密不可逆
  2.只要傳入的內容同樣,獲得的hash值必然同樣
  3,只要使用的hash算法不變,不管校驗的內容有多大,獲得的hash值長度是固定的

普通用法:

m=hashlib.md5()
m.update('helloalvin'.encode('utf8')) #只能傳入字節
m.hexdigest() #92a7e713c30abbb0319fa07da2a5c4af

注意:update內部有一個排他集合,會將全部分批傳入的數據一塊兒計算。因此若是要分開一個數據一個數據地加密,必定要從新初始化加密算法對象。

防止撞庫,對加密算法中添加自定義key再來作加密:

hash = hashlib.sha256('898oaFs09f'.encode('utf8')) #添加本身的key,而後初始化
hash.update('alvin'.encode('utf8'))
hash.hexdigest()#e79e68f070cdedcfe63eaf1a2e92c83b4cfb1b5c6bc452d214c1b7e77cdfd1c7

 

base64模塊
雙向可解的加密

base64.b64encode('123456'.encode('utf8'))
#'MTIzNDU2'
 base64.b64decode('MTIzNDU2'.encode('utf8'))
#'123456'

hmac
加入自定義祕鑰生成惟一字節流

secret_key = b'qazwsx123'
msg = os.urandom(32)
h=hmac.new(secret_key,msg) #使用隨機生成的msg對secret_key加密
digest=h.digest() #產生加密結果
hmac.compare_digest(digest,respone) #比較字節是否相等

 

configparser模塊
操做配置文件。
配置文件的格式
[section1]
k1 = v1
k2:v2
user=egon
age=18
is_admin=true
salary=31

[section2]
k1 = v1

config = configparser.ConfigParser()  #1.必須操做,建立對象

取值:

config.read('a.cfg')    #像文件同樣首先打開
res=config.sections() #查看全部的標題:['section1', 'section2']
options=config.options('section1')    #查看標題section1下所key=value的key組成的列表:
val=config.get('section1','user')     #取出指定section的指定鍵的值
#注意,get還有其餘‘子類’函數,適用於取出特定類型,就是簡化取出以後的類型轉換步驟

寫(改):

config.remove_section('section2')     #刪除整個節section2
config.remove_option('section1','k1')    #刪除節下面的指定鍵值對
config.add_section('egon')    #添加一個標題:
config.set('egon','name','egon')   #在標題egon下添加name=egon,age=18
config.write(open('a.cfg','a+'))   #寫入文件

判斷

 config.has_section('section1')   #判斷有指定節 
config.has_option('section1','')    #判斷節下面是否有


logging模塊
詳細解析伯樂問答詳細解析三

用處:
1)程序調試
2)瞭解軟件程序運行狀況,是否正常
3)軟件程序運行故障分析與問題定位
4)還能夠用來作用戶行爲分析,如:分析用戶的操做行爲、類型洗好、地域分佈以及其它更多的信息,由此能夠實現改進業務、提升商業利益。

功能有設置輸出日誌的等級、日誌保存路徑、日誌文件回滾等;
相比print,其能夠經過設置不一樣的日誌等級,在release版本中只輸出重要信息,而沒必要顯示大量的調試信息;

日誌級別

默認級別爲warning,默認打印到終端,低於級別的日誌不輸出
CRITICAL = 50 #FATAL = CRITICAL
ERROR = 40
WARNING = 30 #WARN = WARNING
INFO = 20
DEBUG = 10
NOTSET = 0 #不設置

配置

logging.basicConfig()函數中經過具體參數來更改logging模塊默認行爲。
#這是全局配置,針對全部logger有效
#而且這個配置比較低級,

#經常使用二者之一,有stream參數就不能設置filename,反過來也是
logging.basicConfig(level=logging.DEBUG,stream=std.__stdout__)
logging.basicConfig(level=10,filename='log.log')

Formatter,Handler,Logger,Filter對象

 

logger:產生日誌的對象
Filter:過濾日誌的對象,通常不用
Handler:接收日誌而後控制打印到不一樣的地方,FileHandler用來打印到文件中,StreamHandler用來打印到終端
Formatter對象:能夠定製不一樣的日誌格式對象,而後綁定給不一樣的Handler對象使用,以此來控制不一樣的Handler的日誌格式

#1.logger對象:負責產生日誌,而後交給Filter過濾,而後交給不一樣的Handler輸出
logger=logging.getLogger(__file__)

#二、Filter對象:不經常使用,略

#三、Handler對象:接收logger傳來的日誌,而後控制輸出
h1=logging.FileHandler('t1.log') #打印到文件
h3=logging.StreamHandler() #打印到終端

#四、Formatter對象:日誌格式
formmater1=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',datefmt='%Y-%m-%d %H:%M:%S %p',)
formmater3=logging.Formatter('%(name)s %(message)s',)

爲Handler對象綁定格式

h1.setFormatter(formmater1)
h3.setFormatter(formmater3)

將Handler關聯logger

logger.addHandler(h1)
logger.addHandler(h3)

設置等級

logger.setLevel(10)

logger.debug('debug')
logger.info('info')
logger.warning('warning')
logger.error('error')
logger.critical('critical')

 

自定義的logger類,用於輔助其餘類(self.logger=PluginLogger())

 
 
import logging
import os
from conf import setting


class Log(object):
__instance = None

def __init__(self):
self.error_log_path = setting.ERROR_LOG_PATH
self.run_log_path = setting.RUN_LOG_PATH
self.error_log = None
self.run_log = None
self.__init_error_log()
self.__init_error_log()

def __new__(cls, *args, **kwargs):
if not cls.__instance:
cls.__instance = object.__new__(cls, *args, **kwargs)
return cls.__instance

def __check_path_exists(self, file_path):
if not os.path.exists(file_path):
raise Exception('%s not exists' % file_path)

def __init_error_log(self):
self.__check_path_exists(self.error_log_path)
logger = logging.Logger('error_log', logging.ERROR)
h = logging.FileHandler(self.error_log_path, 'a', encoding='utf8')
fmt = logging.Formatter(fmt="%(asctime)s - %(levelname)s : %(message)s")
h.setFormatter(fmt)
logger.addHandler(h)
self.error_log = logger

def __init_run_log(self):
self.__check_path_exists(self.run_log_path)
logger = logging.Logger('run_log', logging.INFO)
h = logging.FileHandler(self.run_log_path, 'a', encoding='utf8')
fmt = logging.Formatter(fmt="%(asctime)s - %(levelname)s : %(message)s")
h.setFormatter(fmt)
logger.addHandler(h)
self.run_log = logger

def log(self, msg, status=True):
if status:
self.run_log.info(msg)
else:
self.error_log.error(msg)


logger = Log()
 

 

 

自定義配置
通常正規的開發,不會使用以上的對象進行配置。
logging標準模塊支持三種配置方式: dictConfig,fileConfig,listen。其中,dictConfig是經過一個字典進行配置Logger,Handler,Filter,Formatter;fileConfig則是經過一個文件進行配置;而listen則監聽一個網絡端口,經過接收網絡數據來進行配置。

瞭解logger的繼承,用於filter對象

logger1=logging.getLogger('abc') 
logger2=logging.getLogger('abc.freedom')
logger3=logging.getLogger('abc.freedom.child2')

經過父名.子名繼承,名字自定義,繼承後,父logger輸出時,子對象也會輸出一份相同的,但子對象也能夠本身另外輸出。

 

django的配置說明

'file': {
'level': 'INFO',
'class': 'logging.handlers.TimedRotatingFileHandler', # 用時間切割
'when': "D", #D 表示天
'interval': 1, #1 表示每1天,天天切割一第二天志文件
"backupCount": 3,
'formatter': 'default',
'filename': os.path.join(BASE_DIR, 'logs', 'dbops.log')
},

 


re模塊

正則表達式深刻用法
1.sub將指定字母替換爲大寫,若使用lambda函數形式,記得傳入的是匹配到的正則結構,要使用group提出

re.sub(r'(a)',lambda x:x.group(0).upper(),'caca')

2.使用|方式,要在()闊住,而且在闊號最前面加入?:

re.findall('compan(?:y|ies)','Too many companies have gone bankrupt, and the next one is my company')

3.正則函數通常有一個參數flags能夠傳入正則標誌,例如忽略大小寫,還有正則默認不匹配換行符,標誌設置爲re.S就適用於有換行的字 符串,注意的是換行符無需在正則裏寫出來

4.re.split,普通的字符串split只能按照一個傳入的字符串匹配,但這個可按照多個

re.split('[ab]','abcd') #['', '', 'cd'],先按'a'分割獲得''和'bcd',再對''和'bcd'分別按'b'分割
re.split('[ab]','acaccccbzzzafreedom')
['', 'c', 'cccc', 'zzz', 'freedom']

5.sub函數還有個count參數,指定替換多少次

re.sub('a','A','alex make love',1) Alex make love

6.re.compile能夠實現正則的重用,而且速度快於用字符串保存的正則

obj=re.compile('\d{2}')
obj.search('abc123eeee').group()) #12
obj.findall('abc123eeee')) #['12'],重用了obj

7.闊號後面配頻率符,少用。由於各類re的函數的處理都不一樣
看這個例子:(\d)+至關於(\d)(\d)(\d)(\d)...,是一系列分組

print(re.search('(\d)+','123').group()) #group的做用是將全部組拼接到一塊兒顯示出來
print(re.findall('(\d)+','123')) #findall結果是組內的結果,且是最後一個組的結果

8.group(0)是返回匹配到的所有,group(1)開始就是返回正則表達式闊號的值。默認group()即是group(0)

9.注意,match,從第一個字母查找,知足所編寫的正則後便返回。

re.match(r'ddd','ddd32')
 <_sre.SRE_Match object; span=(0, 3), match='ddd'>

10.?:這個表明不捕獲分組
比較(X)和(?:X),前者是捕獲分組,後者不捕獲,區別在於正則表達式匹配輸入字符串以後所得到的匹配的(數)組當中沒有(?:X)匹配的部分;
好比

注意:這個是javascript
var m = "abcabc".match(/(?:a)(b)(c)/)
結果 ["abc", "b", "c"]

var m = "abcabc".match(/(a)(b)(c)/)
結果 ["abc", "a", "b", "c"]

11.正則若是有衝突的話,前面加上'\',而r前綴的做用是擬製\n \t之類的轉義字符,與衝突字符無關

In [30]: re.match(r'www\.','www.')
Out[30]: <_sre.SRE_Match object; span=(0, 4), match='www.'>

12.正則的(?=rex),匹配指定正則的‘前面部分’的‘預掃描’

 

#預掃描就是先走一遍,找到?=中的正則,而後返回匹配的結果。剩下的正則,仍是從‘預掃描’正則的前一個正則處理完的位置開始。
re.match(r'(?=123|456)(?=123abc)(?=123abcfree)123abcfree','123abcfree')  
Out[98]: <_sre.SRE_Match object; span=(0, 10), match='123abcfree'>  

#預匹配常常用於這樣的場景,例如:密碼須要包含大小寫字母,數字和下劃線

re.match(r'(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*_).*','fdfds2121_FSD')
Out[111]: <_sre.SRE_Match object; span=(0, 13), match='fdfds2121_FSD'>

 


uuid模塊

用於生成惟一標誌符
uuid1()——基於時間,由MAC地址、當前時間戳、隨機數生成。能夠保證全球範圍內的惟一性

 
functools模塊

Python裝飾器(decorator)在實現的時候,被裝飾後的函數其實已是另一個函數了(函數名等函數屬性會發生改變),爲了避免影響,Python的functools包中提供了一個叫wraps的decorator來消除這樣的反作用。寫一個decorator的時候,最好在實現以前加上functools的wrap,它能保留原有函數的名稱和docstring。

from functools import wraps
def hello(fn):
    @wraps(fn)
    def wrapper():
        print "hello, %s" % fn.__name__
        fn()
        print "goodby, %s" % fn.__name__
    return wrapper

 


subprocess模塊

打開一個子進程執行shell

res=subprocess.Popen('dir',shell=True,stdout=subprocess.PIPE)  #shell=True意味着用shell命令形式執行第一參數'dir',stdout參數指定將結果放到管道里面。
res.stdout.read() #從管道中讀出數據,數據爲二進制


res=subprocess.getoutput('ver') #直接獲取cmd命令的返回值

經常使用作法:將輸入流,輸出流,錯誤流都定義到管道

res=subprocess.Popen('ls',shell=True,stdout=subprocess.PIPE,stdin=subprocess.PIPE,stderr=subprocess.PIPE) # 注意,雖然說是這麼寫,可是實際上是不一樣的管道。

 

struct模塊
數據打包爲二進制bytes的模塊
例如,用使用四個字節表示2007這個數字。經常使用於拼接網絡傳輸的應用層協議頭
注意的是,由於經常使用於網路傳輸,網絡傳輸後不是解碼,仍是調用unpack取出

a=struct.pack('b',-1)
struct.unpack('b',a) #返回的是元祖

 


xlrd模塊
不是內置模塊,請pip install xlrd
操做excel文件,xlsx等

data = xlrd.open_workbook('demo.xls') #打開excel
data.sheet_names() #查看文件中包含sheet的名稱
#獲得第一個工做表,或者經過索引順序 或 工做表名稱
table = data.sheets()[0]
table = data.sheet_by_index(0)
table = data.sheet_by_name(u'Sheet1')
#獲取行數和列數
nrows = table.nrows
ncols = table.ncols
#獲取整行和整列的值(數組)
table.row_values(i)
table.col_values(i)
#循環行,獲得索引的列表
for rownum in range(table.nrows):
print table.row_values(rownum)
#單元格
cell_A1 = table.cell(0,0).value
cell_C4 = table.cell(2,3).value
#分別使用行列索引
cell_A1 = table.row(0)[0].value
cell_A2 = table.col(1)[0].value

 socket模塊

服務端套接字函數
s.bind()    綁定(主機,端口號)到套接字
s.listen()  開始TCP監聽
s.accept()  被動接受TCP客戶的鏈接,(阻塞式)等待鏈接的到來

客戶端套接字函數
s.connect()     主動初始化TCP服務器鏈接
s.connect_ex()  connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常

公共用途的套接字函數
s.recv()            接收TCP數據
s.send()            發送TCP數據(send在待發送數據量大於己端緩存區剩餘空間時,數據丟失,不會發完)
s.sendall()         發送完整的TCP數據(本質就是循環調用send,sendall在待發送數據量大於己端緩存區剩餘空間時,數據不丟失,循環調用send直到發完)
s.recvfrom()        接收UDP數據
s.sendto()          發送UDP數據
s.getpeername()     鏈接到當前套接字的遠端的地址
s.getsockname()     當前套接字的地址
s.getsockopt()      返回指定套接字的參數
s.setsockopt()      設置指定套接字的參數
s.close()           關閉套接字

面向鎖的套接字方法
s.setblocking()     設置套接字的阻塞與非阻塞模式
s.settimeout()      設置阻塞套接字操做的超時時間
s.gettimeout()      獲得阻塞套接字操做的超時時間


socketserver模塊

詳細解析 
socket實現併發的模塊
基於tcp的套接字,關鍵就是兩個循環,一個連接循環,一個通訊循環
socketserver模塊中分兩大類:server類(解決連接問題)和request類(解決通訊問題)
藉由繼承socketserver.BaseRequestHandler,並覆寫其handle方法實現併發服務器。即,每過來一個客戶端,就會實例化一個本身繼承的子類的對象與其通訊

class Myserver(socketserver.BaseRequestHandler):
    def handle(self):
        print(self.request) #conn
        print(self.client_address)#addr

while True:
    data = self.request.recv(1024)
    self.request.sendall(data.upper())

s = socketserver.ThreadingTCPServer(('127.0.0.1',8080),MyServer) #注意這裏第二參數爲自定義子類
s.serve_forever() #連接循環    

 urllib模塊
能夠經過url返回下載頁面的結果的函數

from urllib.request import urlopen 
    return urlopen(url).readlines() 

 
functools模塊

functools.partial(iter,li)  #偏函數,即綁定參數,第一個參數爲要操做的函數,第二參數爲操做函數的第一個參數。

 

select模塊

# select 模擬一個socket server,注意socket必須在非阻塞狀況下才能實現IO多路複用。
# 接下來經過例子瞭解select 是如何經過單進程實現同時處理多個非阻塞的socket鏈接的。
#server端


import select
import socket
import queue

server = socket.socket()
server.bind(('localhost',9000))
server.listen(1000)

server.setblocking(False)  # 設置成非阻塞模式,accept和recv都非阻塞
# 這裏若是直接 server.accept() ,若是沒有鏈接會報錯,因此有數據才調他們
# BlockIOError:[WinError 10035] 沒法當即完成一個非阻塞性套接字操做。
msg_dic = {}
inputs = [server,]  # 交給內核、select檢測的列表。
# 必須有一個值,讓select檢測,不然報錯提供無效參數。
# 沒有其餘鏈接以前,本身就是個socket,本身就是個鏈接,檢測本身。活動了說明有連接
outputs = []  # 你往裏面放什麼,下一次就出來了

while True:
    readable, writeable, exceptional = select.select(inputs, outputs, inputs)  # 定義檢測
    #新來鏈接                                        檢測列表         異常(斷開)
    # 異常的也是inputs是: 檢測那些鏈接的存在異常
    print(readable,writeable,exceptional)
    for r in readable:
        if r is server:  # 有數據,表明來了一個新鏈接
            conn, addr = server.accept()
            print("來了個新鏈接",addr)
            inputs.append(conn)  # 把鏈接加到檢測列表裏,若是這個鏈接活動了,就說明數據來了
            # inputs = [server.conn] # 【conn】只返回活動的鏈接,但怎麼肯定是誰活動了
            # 若是server活動,則來了新鏈接,conn活動則來數據
            msg_dic[conn] = queue.Queue()  # 初始化一個隊列,後面存要返回給這個客戶端的數據
        else:
            try :
                data = r.recv(1024)  # 注意這裏是r,而不是conn,多個鏈接的狀況
                print("收到數據",data)
                # r.send(data) # 不能直接發,若是客戶端不收,數據就沒了
                msg_dic[r].put(data)  # 往裏面放數據
                outputs.append(r)  # 放入返回的鏈接隊列裏
            except ConnectionResetError as e:
                print("客戶端斷開了",r)
                if r in outputs:
                    outputs.remove(r) #清理已斷開的鏈接
                inputs.remove(r) #清理已斷開的鏈接
                del msg_dic[r] ##清理已斷開的鏈接

    for w in writeable:  # 要返回給客戶端的鏈接列表
        data_to_client = msg_dic[w].get()  # 在字典裏取數據
        w.send(data_to_client)  # 返回給客戶端
        outputs.remove(w)  # 刪除這個數據,確保下次循環的時候不返回這個已經處理完的鏈接了。

    for e in exceptional:  # 若是鏈接斷開,刪除鏈接相關數據
        if e in outputs:
            outputs.remove(e)
        inputs.remove(e)
        del msg_dic[e]


#*************************client
import socket
client = socket.socket()

client.connect(('localhost', 9000))

while True:
    cmd = input('>>> ').strip()
    if len(cmd) == 0 : continue
    client.send(cmd.encode('utf-8'))
    data = client.recv(1024)
    print(data.decode())

client.close()

 

 

 

selectors模塊
封裝好的IO複用模塊(select,poll,epoll)

sel = selectors.DefaultSeletors() # 首先建立根據操做系統取一個最好的IO複用方式(前提是存在)
sel.reister(sock,selectors.EVENT_READ,myaccept) #也就要對sock和myaccept函數作一個綁定,只要sock有活動,直接調用myaccpet方法
sel.unregister(conn)解除conn綁定的函數
events = sel.select() # 得到激活狀態的事件
from socket import *
import selectors

sel=selectors.DefaultSelector()
def accept(server_fileobj,mask):
    conn,addr=server_fileobj.accept()
    sel.register(conn,selectors.EVENT_READ,read)

def read(conn,mask):
    try:
        data=conn.recv(1024)
        if not data:
            print('closing',conn)
            sel.unregister(conn)
            conn.close()
            return
        conn.send(data.upper()+b'_SB')
    except Exception:
        print('closing', conn)
        sel.unregister(conn)
        conn.close()



server_fileobj=socket(AF_INET,SOCK_STREAM)
server_fileobj.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
server_fileobj.bind(('127.0.0.1',8088))
server_fileobj.listen(5)
server_fileobj.setblocking(False) #設置socket的接口爲非阻塞
sel.register(server_fileobj,selectors.EVENT_READ,accept) #至關於網select的讀列表裏append了一個文件句柄server_fileobj,而且綁定了一個回調函數accept

while True:
    events = sel.select() # 得到激活狀態的事件
for key, mask in events:
    callback = key.data # 傳入函數
    callback(key.fileobj, mask) #mask暫時沒有意義

 

 

platform模塊

>>> platform.system() #返回系統名稱 'Windows'
 
#linux
>>> platform.system()
'Linux'

 

paramiko模塊
SSH遠程鏈接有兩種方式,一種是經過用戶名和密碼直接登陸,另外一種則是用過密鑰登陸

建立公鑰密鑰的方法

 

requests模塊

詳細

# 第三方模塊,pip install requests
# 能夠模仿瀏覽器請求web服務器

# get方式請求
requests.get(url='https://www.bilibili.com/video/av21534444/')
# 1.1 get方式帶參數
requset.get(url='https://www.bilibili.com/video/av21534444/?p=4&a=1')
# 1.2 get方式帶參數(藉由params參數,)
#注意的是params參數不管是get請求,仍是post請求,都是放在url的‘?’後面
requset.get(url='https://www.bilibili.com/video/av21534444/',params={'p':4,'a':1})

#得到數據
data =
requset.get(url='https://www.bilibili.com/video/av21534444/',params={'p':4,'a':1})
data.text # 整個html文本
data.json() # 將得到的數據進行json.load()後返回

# post方式 # 注意的是,會有csrf驗證阻止,須要使用如下裝飾器裝飾指定視圖 from django.views.decorators.csrf import csrf_exempt # 還有使用data參數是存放post數據,params是get數據 requset.post(url='https://www.bilibili.com/video/av21534444/',data={'p':4,'a':1})

# 還要注意的是data參數是一個字典,可是該字典的value值不能也是個字典(ajax請求也同樣),若是是,則會被轉化爲列表(只剩下鍵)。
# 要經過序列化的參數json,而且django的視圖,要從request.body中取。(額外知識:request.body只能用於post請求,由於get請求requset.body會沒有值而報錯)
requset.post(url='https://www.bilibili.com/video/av21534444/',json={'p':4,'a':{1:1,2:2}})


# 返回值

response = request.get(url='xxx')
response.content #字節
response.text #字符串

response.encoding = response.apparent_encoding #指定編碼爲其網頁指定的

# cookies
response.cookies.get_dict()
requset.get(url='xx',cookie={'xx':'xx'})


重要參數說明


 

BeautifulSoup模塊

詳細

# 幫助html,結構化爲對象
pip3 install beautifulsoup4
 from bs4 import BeautifulSoup

html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
asdf
    <div class="title">
        <b>The Dormouse's story總共</b>
        <h1>f</h1>
    </div>
<div class="story">Once upon a time there were three little sisters; and their names were
    <a  class="sister0" id="link1">Els<span>f</span>ie</a>,
    <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
    <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</div>
ad<br/>sf
<p class="story">...</p>
</body>
</html>
"""
 
soup = BeautifulSoup(html_doc, features="lxml")
# 找到第一個a標籤
tag1 = soup.find(name='a')
# 找到全部的a標籤
tag2 = soup.find_all(name='a')
# 找到id=link2的標籤
tag3 = soup.select('#link2')

經常使用方法屬性整理

使用BeautifulSoup提取文章簡介

from bs4 import BeautifulSoup
bs = BeautifulSoup(s,'html.parser')
bs.text

過濾XSS

# XSS的危害:至關於讓瀏覽器執行一堆可執行的腳本
    
from bs4 import BeautifulSoup
bs = BeautifulSoup(s,'html.parser')
for tag in bs.find_all(): #內部遞歸遍歷文檔樹
    if tag.name in ['script','link']:
        tag.decompose() #從文檔樹中刪除
article_detail=str(bs) #得到過濾後的html字符串

 

concurrent模塊

線程池和進程池

from concurrent.futures import ThreadPoolExecutor
pool = ThreadPoolExecutor(10)
for item in task['data']:
hostname = item['hostname']
pool.submit(self.run, hostname)
pool.shutdown(wait=True)

def run(self, hostname):
server_info = plugins.get_server_info(hostname)
server_json = Json.dumps(server_info.data)
self.post_asset(server_json, self.callback)

 

Gevent模塊

gevent開發指南

 

 

SMTP模塊(郵件模塊)

比較好的例子

redis 模塊

redis-py提供管道,管道能夠看做redis的批處理技術。 redis-py默認是設置一個值就要連接一次。但每次設置一個值都要鏈接一次,效率很是的低。 因此Redis提供管道技術能夠在服務端未響應時,客戶端能夠繼續向服務端發送請求,並最終一次性讀取全部服務端的響應。

import redis

#事務+一次發送多個命令:
conn = redis.Redis(host='47.94.172.250',port=6379,password='Luffy!4321')    
pipe = conn.pipeline(transaction=True)
pipe.multi()
pipe.set('k2','123')
pipe.hset('k3','n1',666)
pipe.lpush('k4','laonanhai')    
pipe.execute()
#經過yield建立一個生成器完成一點一點獲取(經過字典操做的源碼來的靈感)
# hscan_iter(切記:通常到公司之後,若是不知道數據到底有多少條,千萬不要用hgetall,而用這個)
  例如,取出一個key的全部val進行打印(1000w條,hash類型)
   方案一:一次取完(不可行)
  若是1000w條一次取完,內存爆炸
  方案二:一次取一個val(可行,浪費)
  每次取1個值都要來回收發,很是低效
  方案三:折中作法(迭代器作法,就是這個)
  一次發個100條,讀完再發
def list_iter(key, count=100): index = 0 while True: data_list = conn.lrange('k1', index, index + count - 1) if not data_list: return index += count for item in data_list: yield item  

 鏈接池
本質是維護一個已經和服務端鏈接成功的socket。之後再次發送數據時,直接從鏈接池中取一個socket,直接send數據便可。

 

#!/usr/bin/env python
# -*- coding:utf-8 -*-
 
import redis
 
pool = redis.ConnectionPool(host='10.211.55.4', port=6379)
 
r = redis.Redis(connection_pool=pool)
r.set('foo', 'Bar')
print r.get('foo')

 

redis的name能夠帶有通配符,delete不行但能夠傳入*列表來解包

注意:運維的禁忌,不能用keys(數據一多很麻煩),儘可能用scan_iter

相關文章
相關標籤/搜索