程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式師世界 >> 編程語言 >  >> 更多編程語言 >> Python

0基礎跟我學python---進階篇(1)

編輯:Python


哈喽!大家好,我是「奇點」,江湖人稱 singularity。剛工作幾年,想和大家一同進步
一位上進心十足的【Java ToB端大廠領域博主】!
喜歡java和python,平時比較懶,能用程序解決的堅決不手動解決

如果有對【java】感興趣的【小可愛】,歡迎關注我

️️️感謝各位大可愛小可愛!️️️
————————————————

如果覺得本文對你有幫助,歡迎點贊,歡迎關注我,如果有補充歡迎評論交流,我將努力創作更多更好的文章。

前3片python文章將python的基本知識講解完了,詳細學習完之後,我們就能夠寫python代碼了。如果不熟悉的可以看一下我前面的文章,熟悉的可以跟我學習一下進階篇。

 對python 0基礎的同學可以看一下我的上篇文章,再來學習這篇文章,大佬可以直接跳過。

0基礎跟我學python(1)https://blog.csdn.net/qq_29235677/article/details/125967844

0基礎跟我學python(2)https://blog.csdn.net/qq_29235677/article/details/126033880

        0基礎跟我學python(3)https://blog.csdn.net/qq_29235677/article/details/126096024

我們今天學習一下python的進階篇,學習一下python的CGI編程 和網絡編程

目錄

️ 1.CGI編程

(1)定義

網頁浏覽

(2)CGI架構圖

(3)Web服務器支持及配置

第一個CGI程序

️ 2.網絡編程

(1)socket()函數

參數

️(2)Socket 對象(內建)方法

服務端

創建一個TCP連接的服務端和客戶端

(3)Python內置的urllib模塊

urllib.request

模擬頭部信息

urllib.error

urllib.parse

urllib.robotparser

(4)requests模塊 

安裝requests

GET請求

POST請求


️ 1.CGI編程

(1)定義

CGI(Common Gateway Interface) 是WWW技術中最重要的技術之一,有著不可替代的重要地位。CGI是外部應用程序(CGI程序)與Web服務器之間的接口標准,是在CGI程序和Web服務器之間傳遞信息的過程。CGI規范允許Web服務器執行外部程序,並將它們的輸出發送給Web浏覽器,CGI將Web的一組簡單的靜態超媒體文檔變成一個完整的新的交互式媒體。

      Common Gateway Interface,簡稱CGI。在物理上是一段程序,運行在服務器上,提供同客戶端HTML頁面的接口。這樣說大概還不好理解。

那麼我們看一個實際例子:

       現在的個人主頁上大部分都有一個留言本。留言本的工作是這樣的:先由用戶在客戶端輸入一些信息,如評論之類的東西。接著用戶按一下“發布或提交”(到目前為止工作都在客戶端),浏覽器把這些信息傳送到服務器的CGI目錄下特定的CGI程序中,於是CGI程序在服務器上按照預定的方法進行處理。在本例中就是把用戶提交的信息存入指定的文件中。然後CGI程序給客戶端發送一個信息,表示請求的任務已經結束。此時用戶在浏覽器裡將看到“留言結束”的字樣。整個過程結束。

CGI 目前由NCSA維護,NCSA定義CGI如下:

 CGI(Common Gateway Interface),通用網關接口,它是一段程序,運行在服務器上如:HTTP服務器,提供同客戶端HTML頁面的接口。

絕大多數的CGI程序被用來解釋處理來自表單的輸入信息,並在服務器產生相應的處理,或將相應的信息反饋給浏覽器。CGI程序使網頁具有交互功能。

處理步驟

  • 1.浏覽器通過HTML表單或超鏈接請求指向一個CGI應用程序的URL。
  • 2.服務器收發到請求。
  • 3.服務器執行指定CGI應用程序。
  • 4.CGI應用程序執行所需要的操作,通常是基於浏覽者輸入的內容。
  • 5.CGI應用程序把結果格式化為網絡服務器和浏覽器能夠理解的文檔(通常是HTML網頁)。
  • 6.網絡服務器把結果返回到浏覽器中。

網頁浏覽

為了更好的了解CGI是如何工作的,我們可以從在網頁上點擊一個鏈接或URL的流程:

  • 1、使用你的浏覽器訪問URL並連接到HTTP web 服務器。
  • 2、Web服務器接收到請求信息後會解析URL,並查找訪問的文件在服務器上是否存在,如果存在返回文件的內容,否則返回錯誤信息。
  • 3、浏覽器從服務器上接收信息,並顯示接收的文件或者錯誤信息。
  • CGI程序可以是Python腳本,PERL腳本,SHELL腳本,C或者C++程序等。asp,php,jsp

CGI程序可以是Python腳本,PERL腳本,SHELL腳本,C或者C++程序等。

(2)CGI架構圖

(3)Web服務器支持及配置

在你進行CGI編程前,確保您的Web服務器支持CGI及已經配置了CGI的處理程序。

Apache 支持CGI 配置:

設置好CGI目錄:

ScriptAlias /cgi-bin/ /var/www/cgi-bin/

所有的HTTP服務器執行CGI程序都保存在一個預先配置的目錄。這個目錄被稱為CGI目錄,並按照慣例,它被命名為/var/www/cgi-bin目錄。

CGI文件的擴展名為.cgi,python也可以使用.py擴展名。

默認情況下,Linux服務器配置運行的cgi-bin目錄中為/var/www。

如果你想指定其他運行CGI腳本的目錄,可以修改httpd.conf配置文件,如下所示:

<Directory "/var/www/cgi-bin">
AllowOverride None
Options +ExecCGI
Order allow,deny
Allow from all
</Directory>

在 AddHandler 中添加 .py 後綴,這樣我們就可以訪問 .py 結尾的 python 腳本文件:

AddHandler cgi-script .cgi .pl .py

 

第一個CGI程序

我們使用Python創建第一個CGI程序,文件名為hello.py,文件位於/var/www/cgi-bin目錄中,內容如下:

       

print ("Content-type:text/html")
print () # 空行,告訴服務器結束頭部
print ('<html>')
print ('<head>')
print ('<meta charset="utf-8">')
print ('<title>Hello Word - 我的第一個 CGI 程序!</title>')
print ('</head>')
print ('<body>')
print ('<h2>Hello Word! 我是來自菜鳥教程的第一CGI程序</h2>')
print ('</body>')
print ('</html>')

文件保存後修改 hello.py,修改文件權限為 755:

chmod 755 hello.py 

以上程序在浏覽器訪問顯示結果如下:

這個的hello.py腳本是一個簡單的Python腳本,腳本第一行的輸出內容"Content-type:text/html"發送到浏覽器並告知浏覽器顯示的內容類型為"text/html"。

用 print 輸出一個空行用於告訴服務器結束頭部信息。

 

️ 2.網絡編程

有過其他語言的編程經驗的話,網絡編程對於大家來說是再熟悉不過的了,同樣python也為我們提供了網絡編程的方式,接下來我們來看看python是怎麼給我們提供網絡編程的,都說python簡單,那我們看看到底有多麼簡單

 

Python 提供了兩個級別訪問的網絡服務。:

  • 低級別的網絡服務支持基本的 Socket,它提供了標准的 BSD Sockets API,可以訪問底層操作系統Socket接口的全部方法。
  • 高級別的網絡服務模塊 SocketServer, 它提供了服務器中心類,可以簡化網絡服務器的開發。

Socket又稱"套接字",應用程序通常通過"套接字"向網絡發出請求或者應答網絡請求,使主機間或者一台計算機上的進程間可以通訊。

(1)socket()函數

Python 中,我們用 socket() 函數來創建套接字,語法格式如下:

socket.socket([family[, type[, proto]]])

參數

  • family: 套接字家族可以是 AF_UNIX 或者 AF_INET
  • type: 套接字類型可以根據是面向連接的還是非連接分為SOCK_STREAMSOCK_DGRAM
  • protocol: 一般不填默認為0.

️(2)Socket 對象(內建)方法

函數描述服務器端套接字s.bind()綁定地址(host,port)到套接字, 在AF_INET下,以元組(host,port)的形式表示地址。s.listen()開始TCP監聽。backlog指定在拒絕連接之前,操作系統可以掛起的最大連接數量。該值至少為1,大部分應用程序設為5就可以了。s.accept()被動接受TCP客戶端連接,(阻塞式)等待連接的到來客戶端套接字s.connect()主動初始化TCP服務器連接,。一般address的格式為元組(hostname,port),如果連接出錯,返回socket.error錯誤。s.connect_ex()connect()函數的擴展版本,出錯時返回出錯碼,而不是拋出異常公共用途的套接字函數s.recv()接收TCP數據,數據以字符串形式返回,bufsize指定要接收的最大數據量。flag提供有關消息的其他信息,通常可以忽略。s.send()發送TCP數據,將string中的數據發送到連接的套接字。返回值是要發送的字節數量,該數量可能小於string的字節大小。s.sendall()完整發送TCP數據,完整發送TCP數據。將string中的數據發送到連接的套接字,但在返回之前會嘗試發送所有數據。成功返回None,失敗則拋出異常。s.recvfrom()接收UDP數據,與recv()類似,但返回值是(data,address)。其中data是包含接收數據的字符串,address是發送數據的套接字地址。s.sendto()發送UDP數據,將數據發送到套接字,address是形式為(ipaddr,port)的元組,指定遠程地址。返回值是發送的字節數。s.close()關閉套接字s.getpeername()返回連接套接字的遠程地址。返回值通常是元組(ipaddr,port)。s.getsockname()返回套接字自己的地址。通常是一個元組(ipaddr,port)s.setsockopt(level,optname,value)設置給定套接字選項的值。s.getsockopt(level,optname[.buflen])返回套接字選項的值。s.settimeout(timeout)設置套接字操作的超時期,timeout是一個浮點數,單位是秒。值為None表示沒有超時期。一般,超時期應該在剛創建套接字時設置,因為它們可能用於連接的操作(如connect())s.gettimeout()返回當前超時期的值,單位是秒,如果沒有設置超時期,則返回None。s.fileno()返回套接字的文件描述符。s.setblocking(flag)如果 flag 為 False,則將套接字設為非阻塞模式,否則將套接字設為阻塞模式(默認值)。非阻塞模式下,如果調用 recv() 沒有發現任何數據,或 send() 調用無法立即發送數據,那麼將引起 socket.error 異常。s.makefile()創建一個與該套接字相關連的文件

看樣子確實很簡單,提供了很多內置的方法供我們調用,接下來舉個

服務端

我們使用 socket 模塊的 socket 函數來創建一個 socket 對象。socket 對象可以通過調用其他函數來設置一個 socket 服務。

現在我們可以通過調用 bind(hostname, port) 函數來指定服務的 port(端口)

接著,我們調用 socket 對象的 accept 方法。該方法等待客戶端的連接,並返回 connection 對象,表示已連接到客戶端。

完整代碼如下:

創建一個TCP連接的服務端和客戶端

服務端:

import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("127.0.0.1", 8888))
server.listen(5) # 最大並發
print("服務端已經啟動,等待客戶端連接")
client, address = server.accept() # 創建新的線程
"""
連接的客戶端 (<socket.socket fd=4,
family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM,
proto=0,
laddr=('127.0.0.1', 8888),
raddr=('127.0.0.1', 50290)>,('127.0.0.1', 50290))
"""
print("已經建立連接")
data = client.recv(1024)
print("接收到客戶端的數據", data.decode("utf-8"))
print("請輸入回復的內容")
client.send(input().encode("utf-8"))
# print("連接的客戶端", client)
server.close()

客戶端

import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("127.0.0.1", 8888))
print("客戶端已經建立連接")
print("客戶端已經建立連接,請輸入要發送的內容")
client.send(input().encode("utf-8"))
data = client.recv(1024)
print("接收到服務端的響應", data.decode("utf-8"))
client.close()

服務端的結果

服務端已經啟動,等待客戶端連接
已經建立連接
接收到客戶端的數據 1
請輸入回復的內容

 客戶端的結果

客戶端已經建立連接
客戶端已經建立連接,請輸入要發送的內容
1
接收到服務端的響應 2

 上面實現的的TCP連接是不是很簡單,接下來說一下UDP的方式

服務端:

import socket
# print(type({"a":"a"}))
# socket.SOCK_DGRAM UDP
# socket.SOCK_STREAM TCP
# 創建服務端
server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server.bind(("127.0.0.1", 8888))
print("UDP服務端啟動...")
"""
常用socket.AF_INET 多個協議層編解碼,消耗cpu,要網卡收到網卡帶寬消耗 ----->跨網傳輸
socket.AF_UNIX不用網卡,在內核完成,也不用不同協議的編碼 節省cpu不受帶寬限制 --->本地
"""
while True:
data, client = server.recvfrom(1024)
print("接收到消息", data.decode("utf-8"))
server.sendto("你好這是服務端".encode("utf-8"), client) # 回復消息

客戶端:

import socket
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client.sendto(input().encode("utf-8"), ("127.0.0.1", 8888))
data, server = client.recvfrom(1024)
print("收到的消息是", data.decode("utf-8"))
client.close()

客戶端輸入9之後的結果

9
收到的消息是 你好這是服務端 

服務端的結果

UDP服務端啟動...
接收到消息 9

(3)Python內置的urllib模塊

Python urllib 庫用於操作網頁 URL,並對網頁的內容進行抓取處理。

本文主要介紹 Python3 的 urllib。

urllib 包 包含以下幾個模塊:

  • urllib.request - 打開和讀取 URL。
  • urllib.error - 包含 urllib.request 拋出的異常。
  • urllib.parse - 解析 URL。
  • urllib.robotparser - 解析 robots.txt 文件。

urllib.request

urllib.request 定義了一些打開 URL 的函數和類,包含授權驗證、重定向、浏覽器 cookies等。

urllib.request 可以模擬浏覽器的一個請求發起過程。

我們可以使用 urllib.request 的 urlopen 方法來打開一個 URL,語法格式如下:

urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
  • url:url 地址。
  • data:發送到服務器的其他數據對象,默認為 None。
  • timeout:設置訪問超時時間。
  • cafile 和 capath:cafile 為 CA 證書, capath 為 CA 證書的路徑,使用 HTTPS 需要用到。
  • cadefault:已經被棄用。
  • context:ssl.SSLContext類型,用來指定 SSL 設置。
from urllib.request import urlopen
myURL = urlopen("https://www.runoob.com/")
print(myURL.read())

以上代碼使用 urlopen 打開一個 URL,然後使用 read() 函數獲取網頁的 HTML 實體代碼。

read() 是讀取整個網頁內容,我們可以指定讀取的長度:

from urllib.request import urlopen
myURL = urlopen("https://www.runoob.com/")
print(myURL.read(300))

 

除了 read() 函數外,還包含以下兩個讀取網頁內容的函數:

  • readline() - 讀取文件的一行內容

from urllib.request import urlopen
myURL = urlopen("https://www.runoob.com/")
print(myURL.readline()) #讀取一行內容
  • readlines() - 讀取文件的全部內容,它會把讀取的內容賦值給一個列表變量。
from urllib.request import urlopen
myURL = urlopen("https://www.runoob.com/")
lines = myURL.readlines()
for line in lines:
print(line) 

和文件處理的讀法是相似的

我們在對網頁進行抓取時,經常需要判斷網頁是否可以正常訪問,這裡我們就可以使用 getcode() 函數獲取網頁狀態碼,返回 200 說明網頁正常,返回 404 說明網頁不存在:

import urllib.request
myURL1 = urllib.request.urlopen("https://www.runoob.com/")
print(myURL1.getcode()) # 200
try:
myURL2 = urllib.request.urlopen("https://www.runoob.com/no.html")
except urllib.error.HTTPError as e:
if e.code == 404:
print(404) # 404

如果要將抓取的網頁保存到本地,可以使用 Python3 File write() 方法 函數:

from urllib.request import urlopen
myURL = urlopen("https://www.runoob.com/")
f = open("runoob_urllib_test.html", "wb")
content = myURL.read() # 讀取網頁內容
f.write(content)
f.close()

URL 的編碼與解碼可以使用 urllib.request.quote() 與 urllib.request.unquote() 方法:

import urllib.request
encode_url = urllib.request.quote("https://www.runoob.com/") # 編碼
print(encode_url)
unencode_url = urllib.request.unquote(encode_url) # 解碼
print(unencode_url)

 

https%3A//www.runoob.com/
https://www.runoob.com/

模擬頭部信息

我們抓取網頁一般需要對 headers(網頁頭信息)進行模擬,這時候需要使用到 urllib.request.Request 類:

class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
  • url:url 地址。
  • data:發送到服務器的其他數據對象,默認為 None。
  • headers:HTTP 請求的頭部信息,字典格式。
  • origin_req_host:請求的主機地址,IP 或域名。
  • unverifiable:很少用整個參數,用於設置網頁是否需要驗證,默認是False。。
  • method:請求方法, 如 GET、POST、DELETE、PUT等。

 

import urllib.request
import urllib.parse
url = 'https://www.runoob.com/?s=' # 菜鳥教程搜索頁面
keyword = 'Python 教程'
key_code = urllib.request.quote(keyword) # 對請求進行編碼
url_all = url+key_code
header = {
'User-Agent':'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
} #頭部信息
request = urllib.request.Request(url_all,headers=header)
reponse = urllib.request.urlopen(request).read()
fh = open("./urllib_test_runoob_search.html","wb") # 將文件寫入到當前目錄中
fh.write(reponse)
fh.close()

打開 urllib_test_runoob_search.html 文件(可以使用浏覽器打開),內容如下:

 

表單 POST 傳遞數據,我們先創建一個表單,代碼如下,我這裡使用了 PHP 代碼來獲取表單的數據:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鳥教程(runoob.com) urllib POST 測試</title>
</head>
<body>
<form action="" method="post" name="myForm">
Name: <input type="text" name="name"><br>
Tag: <input type="text" name="tag"><br>
<input type="submit" value="提交">
</form>
<hr>
<?php
// 使用 PHP 來獲取表單提交的數據,你可以換成其他的
if(isset($_POST['name']) && $_POST['tag'] ) {
echo $_POST["name"] . ', ' . $_POST['tag'];
}
?>
</body>
</html>

 

import urllib.request
import urllib.parse
url = 'https://www.runoob.com/try/py3/py3_urllib_test.php' # 提交到表單頁面
data = {'name':'RUNOOB', 'tag' : '菜鳥教程'} # 提交數據
header = {
'User-Agent':'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
} #頭部信息
data = urllib.parse.urlencode(data).encode('utf8') # 對參數進行編碼,解碼使用 urllib.parse.urldecode
request=urllib.request.Request(url, data, header) # 請求處理
reponse=urllib.request.urlopen(request).read() # 讀取結果
fh = open("./urllib_test_post_runoob.html","wb") # 將文件寫入到當前目錄中
fh.write(reponse)
fh.close()

urllib.error

 

urllib.error 模塊為 urllib.request 所引發的異常定義了異常類,基礎異常類是 URLError。

urllib.error 包含了兩個方法,URLError 和 HTTPError。

URLError 是 OSError 的一個子類,用於處理程序在遇到問題時會引發此異常(或其派生的異常),包含的屬性 reason 為引發異常的原因。

HTTPError 是 URLError 的一個子類,用於處理特殊 HTTP 錯誤例如作為認證請求的時候,包含的屬性 code 為 HTTP 的狀態碼, reason 為引發異常的原因,headers 為導致 HTTPError 的特定 HTTP 請求的 HTTP 響應頭。

對不存在的網頁抓取並處理異常:

import urllib.request
import urllib.error
myURL1 = urllib.request.urlopen("https://www.runoob.com/")
print(myURL1.getcode()) # 200
try:
myURL2 = urllib.request.urlopen("https://www.runoob.com/no.html")
except urllib.error.HTTPError as e:
if e.code == 404:
print(404) # 404

urllib.parse

urllib.parse 用於解析 URL,格式如下:

urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)

urlstring 為 字符串的 url 地址,scheme 為協議類型,

allow_fragments 參數為 false,則無法識別片段標識符。相反,它們被解析為路徑,參數或查詢組件的一部分,並 fragment 在返回值中設置為空字符串。

from urllib.parse import urlparse
o = urlparse("https://www.runoob.com/?s=python+%E6%95%99%E7%A8%8B")
print(o)
ParseResult(scheme='https', netloc='www.runoob.com', path='/', params='', query='s=python+%E6%95%99%E7%A8%8B', fragment='') 

從結果可以看出,內容是一個元組,包含 6 個字符串:協議,位置,路徑,參數,查詢,判斷。

我們可以直接讀取協議內容:

from urllib.parse import urlparse
o = urlparse("https://www.runoob.com/?s=python+%E6%95%99%E7%A8%8B")
print(o.scheme)

 

https

完整內容

屬性

索引

值(如果不存在)

scheme

0

URL協議

scheme 參數

netloc

1

網絡位置部分

空字符串

path

2

分層路徑

空字符串

params

3

最後路徑元素的參數

空字符串

query

4

查詢組件

空字符串

fragment

5

片段識別

空字符串

username

用戶名

None

password

密碼

None

hostname

主機名(小寫)

None

port

端口號為整數(如果存在)

None

 

urllib.robotparser

urllib.robotparser 用於解析 robots.txt 文件。

robots.txt(統一小寫)是一種存放於網站根目錄下的 robots 協議,它通常用於告訴搜索引擎對網站的抓取規則。

urllib.robotparser 提供了 RobotFileParser 類,語法如下:

class urllib.robotparser.RobotFileParser(url='')

這個類提供了一些可以讀取、解析 robots.txt 文件的方法:

  • set_url(url) - 設置 robots.txt 文件的 URL。

  • read() - 讀取 robots.txt URL 並將其輸入解析器。

  • parse(lines) - 解析行參數。

  • can_fetch(useragent, url) - 如果允許 useragent 按照被解析 robots.txt 文件中的規則來獲取 url 則返回 True。

  • mtime() -返回最近一次獲取 robots.txt 文件的時間。 這適用於需要定期檢查 robots.txt 文件更新情況的長時間運行的網頁爬蟲。

  • modified() - 將最近一次獲取 robots.txt 文件的時間設置為當前時間。

  • crawl_delay(useragent) -為指定的 useragent 從 robots.txt 返回 Crawl-delay 形參。 如果此形參不存在或不適用於指定的 useragent 或者此形參的 robots.txt 條目存在語法錯誤,則返回 None。

  • request_rate(useragent) -以 named tuple RequestRate(requests, seconds) 的形式從 robots.txt 返回 Request-rate 形參的內容。 如果此形參不存在或不適用於指定的 useragent 或者此形參的 robots.txt 條目存在語法錯誤,則返回 None。

  • site_maps() - 以 list() 的形式從 robots.txt 返回 Sitemap 形參的內容。 如果此形參不存在或者此形參的 robots.txt 條目存在語法錯誤,則返回 None。

>>> import urllib.robotparser
>>> rp = urllib.robotparser.RobotFileParser()
>>> rp.set_url("http://www.musi-cal.com/robots.txt")
>>> rp.read()
>>> rrate = rp.request_rate("*")
>>> rrate.requests
3
>>> rrate.seconds
20
>>> rp.crawl_delay("*")
6
>>> rp.can_fetch("*", "http://www.musi-cal.com/cgi-bin/search?city=San+Francisco")
False
>>> rp.can_fetch("*", "http://www.musi-cal.com/")
True

(4)requests模塊 

我們已經講解了Python內置的urllib模塊,用於訪問網絡資源。但是,它用起來比較麻煩,而且,缺少很多實用的高級功能。

更好的方案是使用requests。它是一個Python第三方庫,處理URL資源特別方便。

安裝requests

如果安裝了Anaconda,requests就已經可用了。否則,需要在命令行下通過pip安裝:

pip install requests

如果遇到Permission denied安裝失敗,請加上sudo重試。

GET請求

 

import requests
res = requests.get('http://www.baidu.com/')
res.encoding = 'utf-8'
print(res.status_code)
print(res.text)

200
<!DOCTYPE html>
<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=百度一下 class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>新聞</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>地圖</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>視頻</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>貼吧</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>登錄</a> </noscript> <script>document.write('<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u='+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ '" name="tj_login" class="lb">登錄</a>');</script> <a href=https://www.baidu.com/more/ name=tj_briicon class=bri >更多產品</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>關於百度</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>使用百度前必讀</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>意見反饋</a>&nbsp;京ICP證030173號&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>

對於帶參數的URL,傳入一個dict作為params參數:

r = requests.get('https://www.douban.com/search', params={'q': 'python', 'cat': '1001'})

無論響應是文本還是二進制內容,我們都可以用content屬性獲得bytes對象:

b'<!DOCTYPE html>\r\n<!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=http://s1.bdstatic.com/r/www/cache/bdorz/baidu.min.css><title>\xe7\x99\xbe\xe5\xba\xa6\xe4\xb8\x80\xe4\xb8\x8b\xef\xbc\x8c\xe4\xbd\xa0\xe5\xb0\xb1\xe7\x9f\xa5\xe9\x81\x93</title></head> <body link=#0000cc> <div id=wrapper> <div id=head> <div class=head_wrapper> <div class=s_form> <div class=s_form_wrapper> <div id=lg> <img hidefocus=true src=//www.baidu.com/img/bd_logo1.png width=270 height=129> </div> <form id=form name=f action=//www.baidu.com/s class=fm> <input type=hidden name=bdorz_come value=1> <input type=hidden name=ie value=utf-8> <input type=hidden name=f value=8> <input type=hidden name=rsv_bp value=1> <input type=hidden name=rsv_idx value=1> <input type=hidden name=tn value=baidu><span class="bg s_ipt_wr"><input id=kw name=wd class=s_ipt value maxlength=255 autocomplete=off autofocus></span><span class="bg s_btn_wr"><input type=submit id=su value=\xe7\x99\xbe\xe5\xba\xa6\xe4\xb8\x80\xe4\xb8\x8b class="bg s_btn"></span> </form> </div> </div> <div id=u1> <a href=http://news.baidu.com name=tj_trnews class=mnav>\xe6\x96\xb0\xe9\x97\xbb</a> <a href=http://www.hao123.com name=tj_trhao123 class=mnav>hao123</a> <a href=http://map.baidu.com name=tj_trmap class=mnav>\xe5\x9c\xb0\xe5\x9b\xbe</a> <a href=http://v.baidu.com name=tj_trvideo class=mnav>\xe8\xa7\x86\xe9\xa2\x91</a> <a href=http://tieba.baidu.com name=tj_trtieba class=mnav>\xe8\xb4\xb4\xe5\x90\xa7</a> <noscript> <a href=http://www.baidu.com/bdorz/login.gif?login&amp;tpl=mn&amp;u=http%3A%2F%2Fwww.baidu.com%2f%3fbdorz_come%3d1 name=tj_login class=lb>\xe7\x99\xbb\xe5\xbd\x95</a> </noscript> <script>document.write(\'<a href="http://www.baidu.com/bdorz/login.gif?login&tpl=mn&u=\'+ encodeURIComponent(window.location.href+ (window.location.search === "" ? "?" : "&")+ "bdorz_come=1")+ \'" name="tj_login" class="lb">\xe7\x99\xbb\xe5\xbd\x95</a>\');</script> <a href=https://www.baidu.com/more/ name=tj_briicon class=bri >\xe6\x9b\xb4\xe5\xa4\x9a\xe4\xba\xa7\xe5\x93\x81</a> </div> </div> </div> <div id=ftCon> <div id=ftConw> <p id=lh> <a href=http://home.baidu.com>\xe5\x85\xb3\xe4\xba\x8e\xe7\x99\xbe\xe5\xba\xa6</a> <a href=http://ir.baidu.com>About Baidu</a> </p> <p id=cp>&copy;2017&nbsp;Baidu&nbsp;<a href=http://www.baidu.com/duty/>\xe4\xbd\xbf\xe7\x94\xa8\xe7\x99\xbe\xe5\xba\xa6\xe5\x89\x8d\xe5\xbf\x85\xe8\xaf\xbb</a>&nbsp; <a href=http://jianyi.baidu.com/ class=cp-feedback>\xe6\x84\x8f\xe8\xa7\x81\xe5\x8f\x8d\xe9\xa6\x88</a>&nbsp;\xe4\xba\xacICP\xe8\xaf\x81030173\xe5\x8f\xb7&nbsp; <img src=//www.baidu.com/img/gs.gif> </p> </div> </div> </div> </body> </html>\r\n'

 requests的方便之處還在於,對於特定類型的響應,例如JSON,可以直接獲取:

r = requests.get('https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20%3D%202151330&format=json')

需要傳入HTTP Header時,我們傳入一個dict作為headers參數:

r = requests.get('https://www.douban.com/', headers={'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit'})

POST請求

要發送POST請求,只需要把get()方法變成post(),然後傳入data參數作為POST請求的數據:

r = requests.post('https://accounts.douban.com/login', data={'form_email': '[email protected]', 'form_password': '123456'})

requests默認使用application/x-www-form-urlencoded對POST數據編碼。如果要傳遞JSON數據,可以直接傳入json參數:

params = {'key': 'value'}
r = requests.post(url, json=params) # 內部自動序列化為JSON

類似的,上傳文件需要更復雜的編碼格式,但是requests把它簡化成files參數

upload_files = {'file': open('report.xls', 'rb')}
r = requests.post(url, files=upload_files)

在讀取文件時,注意務必使用'rb'即二進制模式讀取,這樣獲取的bytes長度才是文件的長度。

post()方法替換為put()delete()等,就可以以PUT或DELETE方式請求資源。

除了能輕松獲取響應內容外,requests對獲取HTTP響應的其他信息也非常簡單。例如,獲取響應頭:

r.headers
Content-Type': 'text/html; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Content-Encoding': 'gzip', ...}

 

r.headers['Content-Type']
'text/html; charset=utf-8'

 

 requests對Cookie做了特殊處理,使得我們不必解析Cookie就可以輕松獲取指定的Cookie:

r.cookies['ts']

結果 

'example_cookie_12345'

 要在請求中傳入Cookie,只需准備一個dict傳入cookies參數:

cs = {'token': '12345', 'status': 'working'}
r = requests.get(url, cookies=cs)

最後,要指定超時,傳入以秒為單位的timeout參數:

r = requests.get(url, timeout=2.5) # 2.5秒後超時

 

 用requests獲取URL資源,就是這麼簡單!短短兩行代碼就完成了get/post請求,真實太方便了,不得不說python對基本功能的封裝真實做的太好了。程序員能解放自己干點別的東西了

————————————————

如果覺得本文對你有幫助,歡迎點贊,歡迎關注我,如果有補充歡迎評論交流,我將努力創作更多更好的文章。


  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式師世界 All Rights Reserved