---
# System prepended metadata

title: 【Python 網路爬蟲筆記】Requests Library - part 2
tags: [python, HTML, 程式設計, 網頁程式設計, Python, 爬蟲, web crawler, CSS, 網頁]

---

【Python 網路爬蟲筆記】Requests Library - part 2
===

目錄（Table of Contents）：

[TOC]

---

感謝你點進本篇文章！！我是 LukeTseng，一個熱愛資訊的無名創作者，由於近期大學開設大數據分析程式設計這門課程，裡面談到了爬蟲概念，讓我激起一些興趣，因而製作本系列筆記。

聲明：本篇筆記僅供個人學習用途，斟酌參考。

另外本篇筆記使用 VSCode 環境進行編寫，部分模組（函式庫）需自行下載。

## 安裝 Requests 函式庫

Colab 及 Anaconda 環境無須安裝，內建即有。

若不確定自己有裝的話，可以輸入 `pip list` 查看已安裝的所有模組。

使用指令 `pip install requests`。

![pip_list](https://hackmd.io/_uploads/HyBt063oxg.png)

像我已經安裝過了，再安裝一次他會跟你說 Requirement already satisfied，表示你裝過了。

![pip_install_requests](https://hackmd.io/_uploads/B1A9RThjxg.png)

另外一個測試有沒有安裝過該模組的方法，可以打開 VSCode 或其他環境，輸入以下指令並執行即可：

```python=
import requests
print(requests.__version__)
```

執行後會在最下面出現版本資訊。

![vscode_example](https://hackmd.io/_uploads/BJGAJA3jgg.png)

## Requests 基礎用法

使用前須引入模組 `import requests`。

打 `from requests import *` 之後就免在 method 前面打上繁瑣的 requests。

先來看個表：

| Methods | 敘述 |
| -------- | -------- |
| get(url, params, args) | 向指定 URL 發送 GET 請求 |
| post(url, data, json, args) | 向指定 URL 發送 POST 請求 |
| put(url, data, args) | 向指定 URL 發送 PUT 請求（將新資料取代目標資源） |
| delete(url, args) | 向指定 URL 發送 DELETE 請求 |
| head(url, args) | 向指定 URL 發送 HEAD 請求（僅取得 Headers 資訊，沒有 Body） |
| patch(url, data, args) | 向指定 URL 發送 PATCH 請求 |
| request(method, url, args) | 向指定 URL 發送指定方法的請求 |

> table from W3Schools：https://www.w3schools.com/python/module_requests.asp

我們先從最簡單的 get 請求開始做起，範例網址：https://luketsengtw.github.io/

```python=
import requests

url = 'https://luketsengtw.github.io/'

response = requests.get(url)

print(response)
```

Output：

```
<Response [200]>
```

最後輸出了 `<Response [200]>`，這個 200 是 Status Code，表示網站運作正常的意思。

那我們可以在後綴加上 `.text` 看看輸出的內容會是怎樣：

```python=
import requests

url = 'https://luketsengtw.github.io/'

response = requests.get(url)

print(response.text) # modify
```

Output：

![image](https://hackmd.io/_uploads/SyAckxpixl.png)

答案就是一長串，超級多的 HTML 內碼 XD。然後我們就成功爬取到這個網站的 HTML 資訊了。

像剛剛的 Status Code 也可以寫成方法單獨輸出（`.status_code`）：

```python=
import requests

url = 'https://luketsengtw.github.io/'

response = requests.get(url)

print(response.status_code)
```

Output：

```
200
```

既然講到了 `.status_code` 以及 `.text`，那我們就列個完整表給這些 Response 方法吧：

| Methods | 敘述 |
| -------- | -------- |
| .headers | 回傳 response headers 的字典 |
| .encoding | 回傳用於解碼 response.content 的編碼 |
| .elapsed | 回傳一個 timedelta 物件，其中包含從發送請求到回應到達所經過的時間 |
| .close() | 關閉與伺服器的連線 |
| .content | 以位元組（bytes）為單位回傳回應的內容 |
| .cookies | 回傳一個 CookieJar 物件，其中包含從伺服器發回的 cookie |
| .history | 回傳儲存請求（URL）歷史記錄的回應物件列表 |
| .is_permanent_redirect | 如果回應是永久重新導向的 url，則回傳 True，否則回傳 False |
| .is_redirect | 如果回應被重新導向，則回傳 True，否則回傳 False |
| .json() | 回傳結果的 JSON 物件（如果結果是以 JSON 格式寫入的，如果不是則會引發錯誤） |
| .url | 回傳回應的 URL |
| .text | 以 unicode 格式回傳回應的內容 |
| .request | 回傳請求此回應的請求物件 |
| .reason | 回傳與 status code 對應的文字 |
| .ok | 如果 status code < 400 且 >= 200，則回傳 True；否則，回傳 False |
| .links | 回傳 headers 連結 |

> table from GeeksForGeeks：https://www.geeksforgeeks.org/python/python-requests-tutorial/

### POST 發送

POST 請求方法類似於新增、更新操作，會隱密傳送資料給指定的資源。

註：`https://httpbin.org/post` 這個網址是用於測試用的。

```python=
import requests

# 發送基本 POST 請求
response = requests.post('https://httpbin.org/post', data={'key': 'value'})
print(f"狀態碼: {response.status_code}")
print(f"響應內容: {response.text}")
```

Output：

```
狀態碼: 200
響應內容: {
  "args": {},
  "data": "",
  "files": {},
  "form": {
    "key": "value"
  },
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate, zstd",
    "Content-Length": "9",
    "Content-Type": "application/x-www-form-urlencoded",
    "Host": "httpbin.org",
    "User-Agent": "python-requests/2.32.5",
    "X-Amzn-Trace-Id": "Root=1-68cf7a42-667a646642bff88525ef3450"
  },
  "json": null,
  "origin": "180.176.79.173",
  "url": "https://httpbin.org/post"
}
```

上述方式帶了一個參數 `data={'key' : 'value'}`，用 POST 請求方法發送給 `https://httpbin.org/post` 這個網址。

從響應內容中可以看到有我們剛剛輸入的參數：

```
"form": {
    "key": "value"
  },
```

POST 提交表單：

```python=
import requests

# 表單資料
form_data = {
    'username': 'XXX',
    'password': 'thisismypassword',
    'email': 'xxx@example.com'
}

# 發送表單資料
response = requests.post('https://httpbin.org/post', data=form_data)

# 檢查結果
if response.status_code == 200:
    print("表單提交成功！")
    print(response.text)
else:
    print(f"請求失敗，狀態碼: {response.status_code}")
```

Output：

```
表單提交成功！
{
  "args": {},
  "data": "",
  "files": {},
  "form": {
    "email": "xxx@example.com",
    "password": "thisismypassword",
    "username": "XXX"
  },
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate, zstd",
    "Content-Length": "62",
    "Content-Type": "application/x-www-form-urlencoded",
    "Host": "httpbin.org",
    "User-Agent": "python-requests/2.32.5",
    "X-Amzn-Trace-Id": "Root=1-68cf7be7-1dc37d90043a6d9606ce14bc"
  },
  "json": null,
  "origin": "180.176.79.173",
  "url": "https://httpbin.org/post"
}
```

### 避免亂碼

透過網站的標籤 `<meta charset="UTF-8">` 可以得知是使用何種編碼，這邊以我的個人網站做測試：https://luketsengtw.github.io/

如果亂碼可以先透過檢查工具查看是使用何種編碼，並使用方法 `.encoding` 去換編碼。

範例：

```python=
import requests
response = requests.get('https://luketsengtw.github.io/')
response.encoding = 'utf-8' # modify
print(response.text)
```

## API 爬取開放式資料

（政府資料開放平台）以下範例使用「YouBike2.0臺北市公共自行車即時資訊」進行爬取：https://data.gov.tw/dataset/137993

JSON 連結：https://tcgbusfs.blob.core.windows.net/dotapp/youbike/v2/youbike_immediate.json

```python=
import requests
response = requests.get('https://tcgbusfs.blob.core.windows.net/dotapp/youbike/v2/youbike_immediate.json')
print(response.json())
```

Output：

![image](https://hackmd.io/_uploads/B1ob2MTsle.png)

## HTTP 狀態碼

以下列了幾種常見的 HTTP 狀態碼（status code）：

| status code | 敘述 |
| -------- | -------- |
| 200 | OK / 網頁狀態正常（OK / Success） |
| 301 | 永久重新導向（網頁搬家）（Permanent Redirect） |
| 302 | 暫時性重新導向（Temporary Redirect） |
| 400 | 錯誤請求（Bad Request） |
| 401 | 未授權（Unauthorized Error） |
| 403 | 沒有權限進入（Forbidden） |
| 404 | 找不到網站（Not Found） |
| 500 | 內部伺服器錯誤（Internal Server Error） |
| 504 | 伺服器沒有回應（Gateway Timeout） |

詳細請見：https://zh.wikipedia.org/zh-tw/HTTP%E7%8A%B6%E6%80%81%E7%A0%81

範例：

```python=
import requests

response = requests.get('https://httpbin.org/get')

statusCode = response.status_code

print(f'Status Code : {statusCode}')

if statusCode == 200:
    print('Success to request')
    print(f'Content : {response.text[:100]}...')
elif statusCode == 404:
    print('Not Found')
elif statusCode >= 500:
    print('Server Error')
```

Output：

```
Status Code : 200
Success to request
Content : {
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip, deflate, zstd", ...
```

## 總結

### HTTP 請求方法

- GET：
    - GET 是最常用的 HTTP 方法，用於從伺服器獲取資料。
    - 基本語法：`requests.get(url)`，回傳的 Response 物件包含**狀態碼**和**內容**。
    - 如：請求網頁時會得到 `<Response [200]>`，其中 200 表示請求成功。
- POST：
    - POST 方法用於向伺服器傳送資料，常用於**表單提交**或 **API 呼叫**。
    - 可用 **data** 參數傳送表單資料，或 json 參數傳送 JSON 格式資料。
    - POST 請求會將資料隱密地傳送給指定資源，適合用於新增或更新操作。

### Response 物件屬性及方法

| Methods | 敘述 |
| -------- | -------- |
| .headers | 回傳 response headers 的字典 |
| .encoding | 回傳用於解碼 response.content 的編碼 |
| .elapsed | 回傳一個 timedelta 物件，其中包含從發送請求到回應到達所經過的時間 |
| .close() | 關閉與伺服器的連線 |
| .content | 以位元組（bytes）為單位回傳回應的內容 |
| .cookies | 回傳一個 CookieJar 物件，其中包含從伺服器發回的 cookie |
| .history | 回傳儲存請求（URL）歷史記錄的回應物件列表 |
| .is_permanent_redirect | 如果回應是永久重新導向的 url，則回傳 True，否則回傳 False |
| .is_redirect | 如果回應被重新導向，則回傳 True，否則回傳 False |
| .json() | 回傳結果的 JSON 物件（如果結果是以 JSON 格式寫入的，如果不是則會引發錯誤） |
| .url | 回傳回應的 URL |
| .text | 以 unicode 格式回傳回應的內容 |
| .request | 回傳請求此回應的請求物件 |
| .reason | 回傳與 status code 對應的文字 |
| .ok | 如果 status code < 400 且 >= 200，則回傳 True；否則，回傳 False |
| .links | 回傳 headers 連結 |

### 編碼處理

網頁爬取時常遇到編碼問題（可能出現亂碼），可透過檢查網頁 HTML 的 `<meta charset>` 標籤確認編碼格式。

使用 `response.encoding = 'utf-8'` 可手動設定編碼，避免中文亂碼問題。

### API 資料爬取

Requests 非常適合爬取開放式 API 資料。

以政府資料開放平台為例，其可直接請求 JSON API 端點，使用 `response.json()` 方法將回應轉換為 Python 字典格式，便於後續資料處理和分析。

### HTTP 狀態碼

HTTP 狀態碼（Status Code）為三位數字，用於指示請求（Requests）結果，常見的如下：

| status code | 敘述 |
| -------- | -------- |
| 200 | OK / 網頁狀態正常（OK / Success） |
| 301 | 永久重新導向（網頁搬家）（Permanent Redirect） |
| 302 | 暫時性重新導向（Temporary Redirect） |
| 400 | 錯誤請求（Bad Request） |
| 401 | 未授權（Unauthorized Error） |
| 403 | 沒有權限進入（Forbidden） |
| 404 | 找不到網站（Not Found） |
| 500 | 內部伺服器錯誤（Internal Server Error） |
| 504 | 伺服器沒有回應（Gateway Timeout） |

## Reference

[Requests 函式庫 - Python 網路爬蟲教學 | STEAM 教育學習網](https://steam.oxxostudio.tw/category/python/spider/requests.html)

[Python Requests post Method](https://www.w3schools.com/python/ref_requests_post.asp)

[response.status_code - Python requests - GeeksforGeeks](https://www.geeksforgeeks.org/python/response-status_code-python-requests/)

[Python Requests - GeeksforGeeks](https://www.geeksforgeeks.org/python/python-requests-tutorial/)

[Python Requests Module](https://www.w3schools.com/python/module_requests.asp)

[Requests: HTTP for Humans™ — Requests 2.32.5 documentation](https://requests.readthedocs.io/en/latest/)