要說(shuō)python優(yōu)雅在何處,與其他語(yǔ)言相比最為明顯的,那一定是網(wǎng)絡(luò)操作了。python可以讓我們用最少的語(yǔ)句寫出功能強(qiáng)大的程序,網(wǎng)絡(luò)操作有相當(dāng)多的開源庫(kù)可以使用,而不用像其他語(yǔ)言一樣,步驟繁瑣。接下來(lái)從低到高介紹python網(wǎng)絡(luò)編程
- socket網(wǎng)絡(luò)編程接口
- 基本概念
可以這樣來(lái)理解socket,完成一段網(wǎng)絡(luò)通信需要五個(gè)元素,協(xié)議族,協(xié)議類型,協(xié)議,目標(biāo)ip地址,目標(biāo)端口號(hào),這是由TCP/IP網(wǎng)絡(luò)結(jié)構(gòu)決定的。socket作為一種數(shù)據(jù)結(jié)構(gòu),將以上五個(gè)信息組合起來(lái),稱為套接字。根據(jù)面向連接與非連接,套接字類型分為Datagram與Stream兩種類型。Datagram套接字使用UDP協(xié)議,向目標(biāo)地址發(fā)送數(shù)據(jù)包,不保證可靠送達(dá),Stream使用TCP協(xié)議,是可靠的、具有差錯(cuò)與流量控制的傳輸協(xié)議,也就是說(shuō),stream類型的套接字傳輸信息,具有較好的可靠性,而Datagram類型的套接字具有更高的實(shí)時(shí)性。 - 初始化流式套接字的步驟
- 服務(wù)端
- 使用socket函數(shù)創(chuàng)建套接字
- 綁定到指定的ip地址
- 監(jiān)聽客戶端連接
- 獲取客戶端連接后,使用返回的套接字收發(fā)數(shù)據(jù)
- 通信結(jié)束,關(guān)閉套接字
- 客戶端
- 創(chuàng)建套接字
- 連接指定ip地址
- 連接成功后收發(fā)數(shù)據(jù)
- 關(guān)閉套接字
-
常用套接字函數(shù)
- 例程
- 時(shí)間戳服務(wù)器
#!/usr/bin/env python import socket from time import ctime host='127.0.0.1' port=8000 bufsize=1024 addr=(host, port) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(addr) sock.listen(5) while True: print 'waiting for connection...' clisock, cliaddr = sock.accept() print 'connected from', cliaddr print 'peername:', clisock.getpeername() data = clisock.recv(bufsize) if not data: break clisock.send('[%s] %s' % (ctime(), data)) clisock.close() sock.close() - 客戶端
#!/usr/bin/env python from time import ctime import socket host='127.0.0.1' port=8000 addr=(host, port) bufsize=1024 while True: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(addr) data = raw_input(u'>') if not data: break sock.send(data) data = sock.recv(bufsize) print data #!/usr/bin/env python from time import ctime import socket host='127.0.0.1' port=8000 addr=(host, port) bufsize=1024 while True: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect(addr) data = raw_input(u'>') if not data: break sock.send(data) data = sock.recv(bufsize) print data sock.close() sock.close()
- 時(shí)間戳服務(wù)器
- 服務(wù)端
- 基本概念
- 網(wǎng)絡(luò)http操作,使用urllib、urllib2、requests
- 一般來(lái)說(shuō),進(jìn)行網(wǎng)絡(luò)操作時(shí)可以使用以上三個(gè)模塊任意一種,但是就功能上來(lái)說(shuō),requests較為強(qiáng)大,對(duì)底層模塊進(jìn)行了封裝,使用更為簡(jiǎn)便,我們重點(diǎn)來(lái)討論一下requests
- http請(qǐng)求有幾種類型,最常用的是get與post,get請(qǐng)求向指定的資源請(qǐng)求數(shù)據(jù),GET 請(qǐng)求可被緩存,GET 請(qǐng)求保留在瀏覽器歷史記錄中,GET 請(qǐng)求可被收藏為書簽,GET 請(qǐng)求不應(yīng)在處理敏感數(shù)據(jù)時(shí)使用,GET 請(qǐng)求有長(zhǎng)度限制,GET 請(qǐng)求只應(yīng)當(dāng)用于取回?cái)?shù)據(jù)。post請(qǐng)求向指定的資源提交數(shù)據(jù),POST 請(qǐng)求不會(huì)被緩存,POST 請(qǐng)求不會(huì)保留在瀏覽器歷史記錄中,POST 不能被收藏為書簽,POST 請(qǐng)求對(duì)數(shù)據(jù)長(zhǎng)度沒(méi)有要求。還有一個(gè)區(qū)別是,使用get請(qǐng)求時(shí),參數(shù)直接顯示在url中,安全性不高,而post請(qǐng)求將參數(shù)包含在請(qǐng)求體中。
- 使用requests
- 發(fā)出get與post請(qǐng)求
In [8]: res = requests.get('http://www.baidu.com') In [9]: res2 = requests.post('http://www.baidu.com') - 設(shè)置請(qǐng)求參數(shù),通過(guò)params參數(shù)設(shè)置請(qǐng)求參數(shù),需要傳進(jìn)一個(gè)字典,且值為none的鍵不會(huì)出現(xiàn)在url中
In [10]: para = {'username':'xiaozhi','password':'testpass'} In [11]: res3 = requests.get('http://www.baidu.com',params=para) In [12]: res3.url Out[12]: u'http://www.baidu.com/?username=xiaozhi&password=testpass' - 為post請(qǐng)求傳遞數(shù)據(jù)使用data參數(shù)
In [3]: data = {'key':'value'} In [4]: res = requests.post('http://httpbin.org/post', data=data)In [38]: payload = (('key1', 'value1'), ('key1', 'value2')) In [39]: r = requests.post('http://httpbin.org/post', data=payload) - 獲取響應(yīng)內(nèi)容
字符串內(nèi)容
查看與設(shè)置內(nèi)容編碼In [5]: res.text Out[5]: u'{"args":{},"data":"","files":{},"form":{"key":"value"},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"close","Content-Length":"9","Content-Type":"application/x-www-form-urlencoded","Host":"httpbin.org","User-Agent":"python-requests/2.18.4"},"json":null,"origin":"113.140.11.6","url":"http://httpbin.org/post"}\n'
使用content屬性可以查看返回內(nèi)容的字節(jié)內(nèi)容,python會(huì)自動(dòng)為我們解碼gzip壓縮的數(shù)據(jù)In [8]: res.encoding In [9]: res.encoding='utf-8'
json對(duì)象In [15]: res.content Out[15]: '{"args":{},"data":"","files":{},"form":{"key":"value"},"headers":{"Accept":"*/*","Accept-Encoding":"gzip, deflate","Connection":"close","Content-Length":"9","Content-Type":"application/x-www-form-urlencoded","Host":"httpbin.org","User-Agent":"python-requests/2.18.4"},"json":null,"origin":"113.140.11.6","url":"http://httpbin.org/post"}\n'
查看返回狀態(tài)碼In [16]: res.json() Out[16]: {u'args': {}, u'data': u'', u'files': {}, u'form': {u'key': u'value'}, u'headers': {u'Accept': u'*/*', u'Accept-Encoding': u'gzip, deflate', u'Connection': u'close', u'Content-Length': u'9', u'Content-Type': u'application/x-www-form-urlencoded', u'Host': u'httpbin.org', u'User-Agent': u'python-requests/2.18.4'}, u'json': None, u'origin': u'113.140.11.6', u'url': u'http://httpbin.org/post'}
原始數(shù)據(jù)res.status_code
查看返回的http頭部In [31]: res = requests.get('https://api.github.com/events', stream=True) In [32]: with open('temp.txt', 'wb') as fd: ...: for chunk in res.iter_content(512): ...: fd.write(chunk)
使用headers參數(shù)定制請(qǐng)求頭In [44]: r.headers Out[44]: {'Content-Length': '351', 'Via': '1.1 vegur', 'Server': 'gunicorn/19.8.1', 'Connection': 'keep-alive', 'Access-Control-Allow-Credentials': 'true', 'Date': 'Thu, 24 May 2018 12:13:11 GMT', 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json'}
返回對(duì)象的cookies屬性保存了會(huì)話cookie,當(dāng)需要重用cookies時(shí),將cookie對(duì)象作為參數(shù)傳遞給請(qǐng)求的cookies參數(shù)In [33]: headers = {'user-agent':'myapp'} In [34]: res = requests.get('http://www.baidu.com', headers=headers)
使用cookie模擬登陸豆瓣網(wǎng)站res = requests.get(url,cookies=res.cookies)
使用proxies參數(shù)設(shè)置代理,訪問(wèn)googlecookies = {} In [57]: raw_cookies='bid=-aa9Pl9eMB0; _pk_ref.100001.8cb4=%5B%22%22%2C%22%22%2C1527208498%2C%22http ...: s%3A%2F%2Fwww.baidu.com%2Flink%3Furl%3DFpVInsn4IT_ak-F56yaoXBUJPtBtueoUd3nVtc4NWZV4QBO8sdnc ...: vDJTEYLuefv5%26ck%3D1583.5.192.64.190.324.478.646%26shh%3Dwww.baidu.com%26wd%3D%26eqid%3D89 ...: b868ea00032e0c000000035b06b157%22%5D; _pk_id.100001.8cb4=83b586dcea10d0e5.1519446169.2.1527 ...: 209320.1519446169.; __utma=30149280.2141300691.1527208503.1527208503.1527208503.1; __utmz=3 ...: 0149280.1527208503.1.1.utmcsr=baidu|utmccn=(organic)|utmcmd=organic; ll="118371"; _pk_ses.1 ...: 00001.8cb4=*; __utmb=30149280.9.10.1527208503; __utmc=30149280; ps=y; push_noty_num=0; push ...: _doumail_num=0; __utmv=30149280.13784; ap=1; dbcl2="137847261:LmaeCQEh7Eo"; ck=x-vi; __utmt ...: =1' In [58]: for line in raw_cookies.split(';'): ...: key,value = line.split('=', 1) ...: cookies[key] = value In [64]: url = 'https://www.douban.com/people/xiaozhiAXX/' In [65]: res = requests.get(url,cookies=cookies) In [66]: res.status_code Out[66]: 200In [1]: import requests In [2]: proxy = {'http':'http://127.0.0.1:8118','https':'https://127.0.0.1:8118'} In [3]: res = requests.get('https://www.google.com', proxies=proxy) In [4]: res.status_code Out[4]: 200
- 發(fā)出get與post請(qǐng)求
- 網(wǎng)絡(luò)客戶端
- 電子郵件
python發(fā)送電子郵件時(shí),使用標(biāo)準(zhǔn)庫(kù)中的smtplib和email,smptlib中有一個(gè)SMTP類,需要發(fā)送郵件時(shí),初始化該類返回smtpserver對(duì)象,使用login登陸MUA,使用sendmail方法發(fā)送郵件,郵件的正文用email.mime.text.MIMEText對(duì)象進(jìn)行描述
簡(jiǎn)單電子郵件發(fā)送程序from email.mime.text import MIMEText msg = MIMEText('hello message','plain', 'utf-8') from_addr = 'yourPhone@163.com' to_addr = 'yourQQ@qq.com' sub_msg = 'hello' smtp_server = 'smtp.163.com' import smtplib # 初始化smtp對(duì)象,傳入服務(wù)器地址與端口號(hào) server = smtplib.SMTP(smtp_server,25) # 設(shè)置調(diào)試模式可以讓我們看到發(fā)送郵件過(guò)程中的信息 server.set_debuglevel(1) # 登陸MUA,使用賬戶與授權(quán)碼登陸 server.login(from_addr, 'yourpassword') msg['From'] = from_addr msg['To'] = to_addr msg['Subject'] = 'important message' server.sendmail(from_addr, [to_addr], msg.as_string())郵件被放入垃圾郵件中,如下
發(fā)送帶附件的電子郵件
from email.mime.text import MIMEText from smtplib import SMTP from email.mime.multipart import MIMEMultipart from_addr = '18392136027@163.com' to_addr = '1786614260@qq.com' smtp_server = 'smtp.163.com' smtp_port = 25 subject_msg = 'subject' mul_msg = MIMEMultipart() mul_msg['From'] = from_addr mul_msg['To'] = to_addr mul_msg['Subject'] = subject_msg msg = MIMEText('\n\rimportant message\n\r', 'plain', 'utf-8') mul_msg.attach(msg) att1 = MIMEText(open('program.txt','rb').read(), 'base64', 'utf-8') att1['Content-Type'] = 'application/octet-stream' att1["Content-Disposition"] = 'attachment;filename="program.txt"' mul_msg.attach(att1) smtp = SMTP(smtp_server, smtp_port) smtp.login(from_addr, 'youpass') smtp.set_debuglevel(1) smtp.sendmail(from_addr, to_addr, mul_msg.as_string()) smtp.close()
使用第三方開源庫(kù)yagmail發(fā)送電子郵件
使用pop3協(xié)議用網(wǎng)易郵箱發(fā)送郵件時(shí),容易被網(wǎng)易識(shí)別為垃圾郵件,可以使用qq郵箱import yagmail yag = yagmail.SMTP(user='youQQ@qq.com', password='you pass', host='smtp.qq.com', port=25) contents = ['import message','program.txt'] yag.send(to='dest', subject='subject', contents=contents)
- 電子郵件



