---
titles: Python(爬蟲)-HTTP
tags: 爬蟲、程式、AI共學社群
---
# Python(爬蟲)-HTTP
## HTTP協定(超文本傳輸協定)
### 什麼是 HTTP 協定
- 「HyperText Transfer Protocol(HTTP) 是⼀種⽤戶端瀏覽器和伺服端伺服器之間溝通的標準協定,規範了「客⼾端」與「伺服器端」兩者間如何傳輸資料。」
- 簡單來說就是:使⽤者端發送一個「Request 請求」,伺服器端根據請求回傳⼀個「Response 回覆」

## Request
- HTTP 將請求(Request)依據使用情境分成兩種方法:GET & POST。
- GET ⽅法將要傳送的資料以 Query String 的方式接在網址後面。(Query String 是⼀種Key-Vaule 的組成)
- POST ⽅法則是將傳送的資料寫在傳送的封包當中,從網址上看不到。
:::info
GET:將資料帶在網址上,利用 ?Key=Value 接在網址之後
POST:用 form 的⽅式帶資料
:::

- Request 分為 Headers 與 Content
- Header ⽤來帶「發送⽅」相關的資訊
- Body 帶需要傳送給伺服器的資料

## Response
- HTTP 的回應(Respone)常⾒有兩種格式,API 與 HTML View。兩者的差別是回傳的 HTTP 內容不同。
- API 通常會以 JSON 格式⽽成的字串,是提供給程式存取。
- HTML View 是包含 JS、CSS、HTML 三種語言所組成的網頁原始碼,會交由瀏覽器進⾏行處理。
:::success
API => 回傳格式符合特定資料結構的字串
HTML View => 回傳⼀段 html 網⾴原始碼
:::
- Response 分為 Headers 與 Content
- Header ⽤來帶「發送⽅」相關的資訊
- Body 則會帶回傳給瀏覽器的資料

- Response 中會回傳請求的結果
在 HTTP Response 當中,除了跟 Request ⼀樣會有 Headers 跟 Content 之外,還會多帶一個狀態表⽰這次請求的結果。

- 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,達到以直觀簡潔的⽅式存取資源。

- RESTful API 將 API 的設計與 HTTP Method 結合也就是說,不同的Method就是對同⼀件事情做不同的操作W

## 思考流程
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'}
```