---
# System prepended metadata

title: Python(爬蟲)-HTTP
tags: [爬蟲、程式、AI共學社群]

---

---
titles: Python(爬蟲)-HTTP
tags: 爬蟲、程式、AI共學社群
---
# Python(爬蟲)-HTTP
## HTTP協定(超文本傳輸協定)
### 什麼是 HTTP 協定
- 「HyperText Transfer Protocol(HTTP) 是⼀種⽤戶端瀏覽器和伺服端伺服器之間溝通的標準協定，規範了「客⼾端」與「伺服器端」兩者間如何傳輸資料。」

- 簡單來說就是：使⽤者端發送一個「Request 請求」，伺服器端根據請求回傳⼀個「Response 回覆」

    ![](https://i.imgur.com/7DNLYky.png)

## Request
- HTTP 將請求（Request）依據使用情境分成兩種方法：GET & POST。
    - GET ⽅法將要傳送的資料以 Query String 的方式接在網址後面。(Query String 是⼀種Key-Vaule 的組成)
    - POST ⽅法則是將傳送的資料寫在傳送的封包當中，從網址上看不到。
    :::info
    GET：將資料帶在網址上，利用 ?Key=Value 接在網址之後
    POST：用 form 的⽅式帶資料
    :::
    ![](https://i.imgur.com/1X7xlXq.png)
- Request 分為 Headers 與 Content
    - Header ⽤來帶「發送⽅」相關的資訊
    - Body 帶需要傳送給伺服器的資料
    ![](https://i.imgur.com/8rnhYCB.png)

## Response
- HTTP 的回應（Respone）常⾒有兩種格式，API 與 HTML View。兩者的差別是回傳的 HTTP 內容不同。 
    - API 通常會以 JSON 格式⽽成的字串，是提供給程式存取。
    - HTML View 是包含 JS、CSS、HTML 三種語言所組成的網頁原始碼，會交由瀏覽器進⾏行處理。
    :::success
    API => 回傳格式符合特定資料結構的字串
    HTML View => 回傳⼀段 html 網⾴原始碼
    :::
- Response 分為 Headers 與 Content
    - Header ⽤來帶「發送⽅」相關的資訊
    - Body 則會帶回傳給瀏覽器的資料
    ![](https://i.imgur.com/ld9GNAH.png)
- Response 中會回傳請求的結果
    在 HTTP Response 當中，除了跟 Request ⼀樣會有 Headers 跟 Content 之外，還會多帶一個狀態表⽰這次請求的結果。
    ![](https://i.imgur.com/7zkGaDc.png)
- Response 狀況代碼
    Respone 定義了幾種不同的狀態，⽤來表⽰這次的請求結果
    
    | 代碼 | 狀態 |
    |:-:|:-:|
    |200 OK           |代表請求已成功被伺服器接收、理解、並接受|
    |3XX Redirection  |⽤來重新導向，後續的請求位址（重新導向⽬標）|
    |4XX Error        |⽤戶端看起來可能發⽣了錯誤，妨礙了伺服器的處理|
    |5XX Server Error |伺服器在處理請求的過程中有錯誤或者異常狀態發生|

## 目前 HTTP 協定版本
- HTTP/0.9
    - 於 1991 年發表(已廢止)
:::success
- 於 1990 年由 Tim Berners-Lee 提出最初的 HTTP 建議(www)
- 實作重點
    - 用戶端要求是以 ASCII 字元為主 (單位命令即可發出要求 -> GET/)
    - 用戶端要求會以一個換行字元(CRLF)來結束
    - 伺服器回應是以 ASCII 字元為主，回應內容為是 HTML文件
    - 每次執行完 Request / Response 就會自動關閉連線
- 主要特點
    - Client / Server 架構、Request / Response 協定
    - 跑在 TCP / IP 上的 ASCII 協定(要求/回應)
    - 被設計用來傳輸 HTML 文件
    - 每完成一次 ASCII 協定就會自動關閉連線 
:::
    
- HTTP/1.0
    - 於 1996 年 5 月發表(RFC 1945)
:::info
- 於 1991 到 1995 年之間，『瀏覽器』出現
- 不同部分
    - 用戶端要求是以 ASCII 字元為主，但可發送多行命令(含要求標頭)
        - 先送出要求方法，再送出要求標題，最後以一個額外的換行字元結束 
    - 伺服器回應是以 ASCII 字元為主，回應內容區分為
        - 狀態列
        - 回應標頭
        - 回應內文主體(不僅僅是 HTML 文件，可以是更多內容類型) 
    - 每完成一次 Request / Response 就會自動關閉 TCP / IP 連線
:::

- HTTP/1.1
    - 於 1997 年 1 月發表(RFC 1945)
    - 於 1999 年 6 月發布 HTTP/1.1 更新版本(RFC 2616)
    - 於 2014 年 6 月再次更新 HTTP/1.1 並將規格文件拆分成六份
:::warning
- 不同部分
    - 傳輸協議的效能改進(新增不少HTTP標頭定義)
        - 持續連線狀態
        - 切塊編碼傳輸
        - 位元範圍請求
        - 額外快取機制
        - 請求管線作業 
:::

- HTTP/2
    - 於 2015 年 5 月發表(RFC 7540)
    - 僅針對 HTTP/1.1 的 Message Syntax 部分做出強化

https://www.slideshare.net/WillHuangTW/hypertext-transfer-protocol-77109917

## API
### what's API
第⼆種資料的發布⽅式是 API 的存取接口，API 的全名叫應⽤程式介面（Application Programming Interface），表⽰程式與程式間的溝通⽅式或介面。換句句話說，就是資料⽅寫好⼀組程式，提供你可以用程式的⽅式與其串接資料。
### RESTFul API
- Representational State Transfer（REST），它是⼀種網路架構風格，他並不是⼀種標準。 RESTful API 是基於 REST 的概念，進⼀步結合 HTTP Method，達到以直觀簡潔的⽅式存取資源。
    ![](https://i.imgur.com/yA42Lmu.png)
- RESTful API 將 API 的設計與 HTTP Method 結合也就是說，不同的Method就是對同⼀件事情做不同的操作W
    ![](https://i.imgur.com/UUWhPAg.png)

## 思考流程
1. 發送 Request 到 API 接口
2. 取得回傳內容
3. 解析內容格式

## Request Library
Requests 提供了基本的 HTTP Request 與接收 Response 的兩個核⼼功能。Requests 的⽬標是使 HTTP 請求更簡單，更人性化。
```python=
import requests 
# 引入函式庫
r = requests.get('https://github.com/timeline.json') # 想要爬資料的⽬標網址
response = r.text 
# 模擬發送請求的動作
```
## 利用 Python 存取 API
### 比較範例中的「r.text」與「json.loads(r.text)」讀出來的內容有什麼差異
- r.text
```python=
import requests
r = requests.get('https://api.github.com/events')
r.text
```
```
rl":"https://api.github.com/users/mrlevitas/orgs","repos_url":"https://api.github.com/users/mrlevitas/repos","events_url":"https://api.github.com/users/mrlevitas/events{/privacy}","received_events_url":"https://api.github.com/users/mrlevitas/received_events","type":"User","site_admin":false},"repo":{"id":38845043,"node_id":"MDEwOlJlcG9zaXRvcnkzODg0NTA0Mw==","name":"Ruby-on-Rails-Codecademy-Exercises","full_name":"mrlevitas/Ruby-on-Rails-Codecademy-Exercises","private":false,"owner":{"login":"mrlevitas","id":1631401,"node_id":"MDQ6VXNlcjE2MzE0MDE=","avatar_url":"https://avatars0.githubusercontent.com/u/1631401?v=4","gravatar_id":"","url":"https://api.github.com/users/mrlevitas","html_url":"https://github.com/mrlevitas","followers_url":"https://api.github.com/users/mrlevitas/followers","following_url":"http
                    ...(以下省略)...
```
- json.loads(r.text)
```python=
import json
json.loads(r.text)
```
```
ls-Codecademy-Exercises/collaborators{/collaborator}',
      'teams_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/teams',
      'hooks_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/hooks',
      'issue_events_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/issues/events{/number}',
      'events_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/events',
      'assignees_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/assignees{/user}',
      'branches_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/branches{/branch}',
      'tags_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/tags',
      'blobs_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/git/blobs{/sha}',
      'git_tags_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/git/tags{/sha}',
      'git_refs_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/git/refs{/sha}',
      'trees_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/git/trees{/sha}',
      'statuses_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/statuses/{sha}',
      'languages_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/languages',
      'stargazers_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/stargazers',
      'contributors_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/contributors',
      'subscribers_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/subscribers',
      'subscription_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/subscription',
      'commits_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/commits{/sha}',
      'git_commits_url': 'https://api.github.com/repos/mrlevitas/Ruby-on-Rails-Codecademy-Exercises/git/commits{/sha}',
                    ...(以下省略)...
```
### 其他方法

- 方法一 
```python=
payload = {'key1': 'value1', 'key2': 'value2'}
r = requests.get("http://httpbin.org/get", params=payload)
json.loads(r.text)
```
```
{'args': {'key1': 'value1', 'key2': 'value2'},
 'headers': {'Accept': '*/*',
  'Accept-Encoding': 'gzip, deflate',
  'Host': 'httpbin.org',
  'User-Agent': 'python-requests/2.22.0'},
 'origin': '140.124.249.57, 140.124.249.57',
 'url': 'https://httpbin.org/get?key1=value1&key2=value2'}
```
- 方法二
```python=
r = requests.post('http://httpbin.org/post', data={'key':'value'})
json.loads(r.text)
```
```
{'args': {},
 'data': '',
 'files': {},
 'form': {'key': 'value'},
 'headers': {'Accept': '*/*',
  'Accept-Encoding': 'gzip, deflate',
  'Content-Length': '9',
  'Content-Type': 'application/x-www-form-urlencoded',
  'Host': 'httpbin.org',
  'User-Agent': 'python-requests/2.19.1'},
 'json': None,
 'origin': '123.195.194.127, 123.195.194.127',
 'url': 'https://httpbin.org/post'}
```