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','') #判斷節下面是否有
用處:
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模塊
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