要說python優(yōu)雅在何處惦银,與其他語言相比最為明顯的,那一定是網(wǎng)絡操作了末誓。python可以讓我們用最少的語句寫出功能強大的程序扯俱,網(wǎng)絡操作有相當多的開源庫可以使用,而不用像其他語言一樣喇澡,步驟繁瑣迅栅。接下來從低到高介紹python網(wǎng)絡編程
- socket網(wǎng)絡編程接口
- 基本概念
可以這樣來理解socket溉贿,完成一段網(wǎng)絡通信需要五個元素呼畸,協(xié)議族孔飒,協(xié)議類型撬碟,協(xié)議忆植,目標ip地址业扒,目標端口號兢交,這是由TCP/IP網(wǎng)絡結(jié)構(gòu)決定的漠畜。socket作為一種數(shù)據(jù)結(jié)構(gòu)秀睛,將以上五個信息組合起來尔当,稱為套接字。根據(jù)面向連接與非連接蹂安,套接字類型分為Datagram與Stream兩種類型椭迎。Datagram套接字使用UDP協(xié)議锐帜,向目標地址發(fā)送數(shù)據(jù)包,不保證可靠送達畜号,Stream使用TCP協(xié)議缴阎,是可靠的、具有差錯與流量控制的傳輸協(xié)議简软,也就是說蛮拔,stream類型的套接字傳輸信息,具有較好的可靠性痹升,而Datagram類型的套接字具有更高的實時性语泽。 - 初始化流式套接字的步驟
- 服務端
- 使用socket函數(shù)創(chuàng)建套接字
- 綁定到指定的ip地址
- 監(jiān)聽客戶端連接
- 獲取客戶端連接后,使用返回的套接字收發(fā)數(shù)據(jù)
- 通信結(jié)束视卢,關閉套接字
- 客戶端
- 創(chuàng)建套接字
- 連接指定ip地址
- 連接成功后收發(fā)數(shù)據(jù)
- 關閉套接字
-
常用套接字函數(shù)
- 例程
- 時間戳服務器
#!/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()
- 時間戳服務器
- 服務端
- 基本概念
- 網(wǎng)絡http操作踱卵,使用urllib、urllib2据过、requests
- 一般來說惋砂,進行網(wǎng)絡操作時可以使用以上三個模塊任意一種,但是就功能上來說绳锅,requests較為強大西饵,對底層模塊進行了封裝,使用更為簡便鳞芙,我們重點來討論一下requests
- http請求有幾種類型眷柔,最常用的是get與post,get請求向指定的資源請求數(shù)據(jù)原朝,GET 請求可被緩存驯嘱,GET 請求保留在瀏覽器歷史記錄中,GET 請求可被收藏為書簽喳坠,GET 請求不應在處理敏感數(shù)據(jù)時使用鞠评,GET 請求有長度限制,GET 請求只應當用于取回數(shù)據(jù)壕鹉。post請求向指定的資源提交數(shù)據(jù)剃幌,POST 請求不會被緩存,POST 請求不會保留在瀏覽器歷史記錄中晾浴,POST 不能被收藏為書簽负乡,POST 請求對數(shù)據(jù)長度沒有要求。還有一個區(qū)別是脊凰,使用get請求時抖棘,參數(shù)直接顯示在url中,安全性不高,而post請求將參數(shù)包含在請求體中钉答。
- 使用requests
- 發(fā)出get與post請求
In [8]: res = requests.get('http://www.baidu.com') In [9]: res2 = requests.post('http://www.baidu.com')
- 設置請求參數(shù),通過params參數(shù)設置請求參數(shù)杈抢,需要傳進一個字典数尿,且值為none的鍵不會出現(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請求傳遞數(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)
- 獲取響應內(nèi)容
字符串內(nèi)容
查看與設置內(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會自動為我們解碼gzip壓縮的數(shù)據(jù)In [8]: res.encoding In [9]: res.encoding='utf-8'
json對象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ù)定制請求頭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'}
返回對象的cookies屬性保存了會話cookie惶楼,當需要重用cookies時右蹦,將cookie對象作為參數(shù)傳遞給請求的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ù)設置代理,訪問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]: 200
In [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請求
- 網(wǎng)絡客戶端
- 電子郵件
python發(fā)送電子郵件時,使用標準庫中的smtplib和email歼捐,smptlib中有一個SMTP類何陆,需要發(fā)送郵件時,初始化該類返回smtpserver對象豹储,使用login登陸MUA贷盲,使用sendmail方法發(fā)送郵件,郵件的正文用email.mime.text.MIMEText對象進行描述
簡單電子郵件發(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對象剥扣,傳入服務器地址與端口號 server = smtplib.SMTP(smtp_server,25) # 設置調(diào)試模式可以讓我們看到發(fā)送郵件過程中的信息 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()
使用第三方開源庫yagmail發(fā)送電子郵件
使用pop3協(xié)議用網(wǎng)易郵箱發(fā)送郵件時钠怯,容易被網(wǎng)易識別為垃圾郵件佳魔,可以使用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)
- 電子郵件