--- 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'} ```