Try   HackMD

安裝Requests

STEP1. 在終端機利用pip安裝

在終端機上打上指令

pip install requests

安裝完成後通常會是這樣的畫面:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

STEP2. 檢查是否安裝成功

在終端機上打上指令

python

接下來將requests模組import進來

import requests

如果沒有出現任何報錯基本上就是成功了,我們還可以試著打印看看安裝的requests版本

print(requests.__version__)

大致會出現的結果:(若安裝時沒有指定版本,打印出來的版本可能會跟我不一樣)

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

發送GET請求

我們可以requests模組來向特定網站發送請求,首先先從發送GET請求開始吧!

import requests as req      # requests名字太長了,以req縮寫方便使用

# url可以填上任何你想請求的網址,這裡我以我的網站為例
url = 'https://goldorange261.github.io/Note-web/'
r = req.get(url)            # 向網站發送GET請求,並將回應儲存在r這個變數中
print(r)

沒有意外的話執行結果如下(200就是請求成功的回應碼):

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

如果想知道網站到底回應了我們什麼的話,可以成這樣

print(r.text)

可以發現是回應了一個HTML檔案:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

如果我們想知道回應的表頭(Response Header)的話可以這樣寫

print(r.headers)

打印出來的結果如下:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

這邊注意一下Content-Type這欄,檔案類型為text/html,跟我們剛剛打印text所發現的事一樣

下載圖片

將要下載的圖片網址複製下來(這裡以我網站上的圖片為例)

import requests as req

url = 'https://goldorange261.github.io/Note-web/index/welcome.png'
r = req.get(url)
print(r.text)

如果像之前一樣直接打印出text的話就會出現一堆亂碼,這是因為圖片檔這種二進制檔案以文字的形式去讀取造成的,因此我們要稍微修改一下程式碼

print(r.content)

打印出來就不會是亂碼了:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

ℹ️諸如圖片、影片、PDF這種檔案,我們都可以使用r.content

不過這只是打印出來而已,並沒有儲存下來,所以要再補上這2行

# 因為要寫入2進制檔案所以模式要使用wb(write byte)
with open('Nacho.png', mode='wb') as file:
    file.write(r.content)

可以看到在當前路徑下確實將圖片給儲存下來了:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

測試請求

ℹ️可以用httpbin這個網站來測試自己發出去的請求

先來測試GET吧!

url = 'https://httpbin.org/get'
r = req.get(url)
print(r.text)

可以看到它回傳給我們的東西就是我們發送出去的請求:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

這樣就可以檢查我們到底發送了什麼東西給伺服器,args就是附帶的參數,因為我們剛剛沒有附帶參數,所以就是空的。header都是python自動幫我們附上的。origin就是我發送請求的這台電腦現在的IP,url就是發送到哪個網址

網址附帶參數

一般在瀏覽網頁時你可能會看到網址後面有個問號,舉個例子:

https://www.youtube.com/watch?v=GyhLj-YdJW4

這個YouTube影片的網址後面就有一個參數v,而這個參數所儲存的資料就是這個影片的ID

ℹ️如果有多個參數的話在網址中會以'&'隔開

如果我們要發送這種有附帶參數的網址,可以這樣做(這邊以httpbin來做測試):

url = 'https://httpbin.org/get'
params = {
    'id' : 'NaCHokAwaiI',
    'page' : '1011'
}
r = req.get(url, params=params)
print(r.text)

執行結果如下:

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

因為這次我們有傳輸參數所以args就不是空白而是剛剛傳入的參數,再觀察一下url的部分:"url": "https://httpbin.org/get?id=NaCHokAwaiI&page=1011",問號後面確實有我們附帶的參數

發送POST請求

直接將剛剛的程式碼稍加修改並觀察(get全部改成post)

import requests as req

url = 'https://httpbin.org/post'
params = {
    'id' : 'NaCHokAwaiI',
    'page' : '1011'
}
r = req.post(url, params=params)
print(r.text)

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

可以發現跟GET比起來,POST多了datafilesformjson,這是因為POST主要的功能是要上傳資料到伺服器。接下來我們就試著上傳資料到伺服器吧!

form欄位

import requests as req

url = 'https://httpbin.org/post'
params = {
    'id' : 'NaCHokAwaiI',
    'page' : '1011'
}
data = {
    'name' : 'Nacho',
    'bd' : '10/11'
}
r = req.post(url, params=params, data=data)
print(r.text)

執行結果如下,由此可知我們的資料是被用表單的的形式上傳到伺服器的

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

json/data欄位

如果想改用json的格式上傳到伺服器的話,就將data改成json即可

r = req.post(url, params=params, json=data)

這樣一來我們的data就會出現在json那裡了,data欄位也不為空了

ℹ️data和json欄位的區別

  • json欄位是指請求中的JSON格式的數據,它會被自動解析為一個Python字典。
  • data欄位是指請求中的原始數據,它是一個字符串,不會被解析。
  • 如果請求的Content-Type是application/json,那麼json欄位和data欄位的值應該是一致的,只是格式不同。
  • 如果請求的Content-Type不是application/json,那麼json欄位可能會是None,因為無法解析非JSON格式的數據。

files欄位

files跟我們要上傳的檔案有關,這裡以我們先前下載下來的圖片為例

# 以二進制檔案的形式讀取Nacho.png並放入字典中
with open('Nacho.png', mode='rb') as file:
    image = { 'Nacho_image' : file.read() }

r = req.post(url, files=image)

# 因為回應太長了所以寫到log裡面看才不會被洗掉
with open('output.log', mode='w') as file:
    file.write(r.text)

圖片確實是在files裡面:

改變Resquest Header

注意一下以前我們所發送的請求,在User-Agent是不是都長這樣:"User-Agent": "python-requests/x.xx.x",基本上這樣就是很明白的在告訴伺服器我是爬蟲請擋掉我,因此我們要偽造這個User-Agent,讓它看起來像是由瀏覽器所發送的

首先打開瀏覽器按下F12並選到網路(Network)這個頁面裡面,然後重新整理網頁,找到User-Agent,最後複製下來

創建一個字典header,裡面有一個User-Agent的key,將剛剛複製下來的字串作為它的值

header = {
    'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.67'
}
r = req.post(url, headers=header)
print(r.text)

這樣User-Agent就成功偽造了:

基本驗證

httpbin也可以讓我們測試基本驗證,如下圖:

用法也非常簡單,可以自由設定使用者名稱和密碼:/basic-auth/{user}/{passwd}

我就簡單地設定了一組:

可以看到進入這個網頁之後會要我們輸入使用者名稱和密碼,如果輸入的使用者名稱或是密碼不正確,就會要求我們重新輸入直到輸入正確為止,認證成功後可以看到這個畫面

我們一樣也可以使用Python幫我們做基本認證的登入

url = 'https://httpbin.org/basic-auth/Nacho/1011'
r = req.get(url, auth=('Nacho', '1011'))
print(r.text)

這樣就認證成功了:

❓那如果沒有驗證成功/沒有驗證呢?

直接GET試試看:

r = req.get(url)
print(r)

得到了401(Unauthorized)的回應:

設定Timeout

我們可以將設定的請求設定Timeout,如果伺服器處理太久,就會報錯,這裡使用httpbin中的delay來模擬延遲很久的回應

# delay/{延遲秒數}
url = 'https://httpbin.org/delay/5'

# 如果報錯就輸出TIME OUT!!,否則輸出r 
try:
    r = req.get(url, timeout=3)
    print(r)
except:
    print('TIME OUT!!')

因為伺服器過了5秒才回應,但我們只能容忍3秒,於是就輸出了TIME OUT!!

那如果伺服器只花了2秒就回應的話:

url = 'https://httpbin.org/delay/2'

try:
    r = req.get(url, timeout=3)
    print(r)
except:
    print('TIME OUT!!')

這樣就OK了: