get請求和post請求的區別、使用Request模塊進行get請求和post請求、上傳圖片的post請求、爬蟲登陸Cookies、使用Session登錄、爬蟲下載文件的幾種方式

get請求和post請求的區別:

超文本傳輸協議(HTTP)的設計目的是保證客戶機與服務器之間的通信。HTTP 的工作方式是客戶機與服務器之間的請求-應答協議。web 瀏覽器可能是客戶端,而計算機上的網絡應用程序也可能作爲服務器端。

Http定義了與服務器交互的不同方法,最基本的方法有4種,分別是GET,POST,PUT,DELETE。

URL全稱是資源描述符,一個URL地址用於描述一個網絡上的資源,而HTTP中的GET,POST,PUT,DELETE就對應着對這個資源的查,改,增,刪4個操作。

我們最常用的是GET和POST請求。GET一般用於獲取/查詢資源信息,而POST一般用於更新資源信息。即GET是向服務器發索取數據的一種請求,而POST是向服務器提交數據的一種請求 。

GET請求:

使用GET方法時,查詢字符串(鍵值對)被附加在URL地址後面一起發送到服務器。

如:

/test/demo_form.jsp?name1=value1&name2=value2 #後面name1及之後內容是查詢字符串

POST請求:

使用POST方法時,查詢字符串在POST信息中單獨存在,和HTTP請求一起發送到服務器。

如:

POST/test/demo_form.jsp HTTP/1.1

Host:w3schools.com

name1=value1&name2=value2 # 這是查詢字符串

GET和POST的區別:

 

GET

POST

點擊返回/刷新按鈕

沒有影響

數據會重新發送(瀏覽器將會提示用戶“數據被從新提交”)

添加書籤

可以

不可以

緩存

可以

不可以

編碼類型(Encoding type)

application/x-www-form-urlencoded

application/x-www-form-urlencoded or multipart/form-data. 請爲二進制數據使用multipart編碼

歷史記錄

沒有

長度限制

沒有

數據類型限制

只允許ASCII字符類型

沒有限制。允許二進制數據

安全性

查詢字符串會顯示在地址欄的URL中,不安全,請不要使用GET請求提交敏感數據

因爲數據不會顯示在地址欄中,也不會緩存下來或保存在瀏覽記錄中,所以看POST求情比GET請求安全,但也不是最安全的方式。如需要傳送敏感數據,請使用加密方式傳輸

可見性

查詢字符串顯示在地址欄的URL中,可見

查詢字符串不會顯示在地址欄中,不可見

上面這些並不是HTTP的GET和POST兩者請求的本質區別,這些區別是建立在HTML標準對於HTTP協議的用法的約定之上的。

注意:

GET和POST與數據如何傳遞沒有關係:

GET和POST是由HTTP協議定義的。在HTTP協議中,使用哪個Method與應用層的數據如何傳輸是沒有相互關係的。HTTP沒有要求,如果Method是POST數據就要放在BODY中。也沒有要求,如果Method是GET,數據(參數)就一定要放在URL中而不能放在BODY中。實際上這種做法只是HTML標準對HTTP協議的用法的約定。現代的Web Server都是支持GET中包含BODY這樣的請求,雖然這種請求不可能從瀏覽器發出。

HTTP協議對GET和POST都沒有對長度的限制:

HTTP協議明確地指出HTTP頭和Body都沒有長度的要求。對於URL長度上的限制,有兩方面的原因:

某些瀏覽器的限制;

服務器的限制:多數服務器出於安全、穩定方面的考慮,會給URL長度加限制,但是這個限制是針對所有HTTP請求的,與GET、POST沒有關係。

安全不安全和GET、POST沒有關係:

這個不用多解釋,無論GET還是POST都有辦法抓包破解信息。

使用Request模塊進行get請求和post請求:

Python 的自帶模塊 urllib, 可以用來提交get請求,下載網頁內容。但我們平常使用的網頁更多的是使用get請求和post請求,對於這兩種請求,我們就要使用requests模塊來處理了。

get和post的應用場景:

post請求:賬號登錄;搜索內容;上傳圖片;上傳文件;往服務器傳數據等。

get請求:正常打開網頁,往服務器傳數據。

使用requests模塊進行get請求:

如我們想模擬一下百度的搜索。首先觀察一下,比如我們在百度搜索框中寫上 “莫煩python”, 我們發現它彈出了一串這麼長的網址:https://www.baidu.com/s?wd=%E8%8E%AB%E7%83%A6python&ie=UTF-8

 

我們可以發現,把com後面改成/s?wd=莫煩python,搜索結果仍然相同。

因此, “/s?wd=莫煩python” 這就是我們進行個性化搜索需要的關鍵信息。

我們把網址分成兩個部分,前面固定不變的部分是“http://www.baidu.com/s?”,後面變化的部分定義成參數param。通過對參數賦不同的值,然後把參數傳入,形成新的個性化搜索網址,然後把網址傳入 然後傳入 requests.get() 功能,我們就可以實現個性化搜索。webbrowser模塊用來打開一個你的默認瀏覽器, 觀看你是否在百度的搜索頁面。

import requests
import webbrowser

# webbrowser模塊是爲了讓你看到這個請求過程和結果

param = {"wd": "莫煩Python"}
# 個性化搜索所需信息
r = requests.get('http://www.baidu.com/s', params=param)
# 組合形成個性化搜索的網址,並傳入requests.get()方法中
print(r)
# r接收到的requests.get()返回值200表示正常打開網頁
print(r.url)
# 打印出我們get的網頁地址
webbrowser.open(r.url)
# 瀏覽器打開這個地址

運行結果如下:

<Response [200]>
http://www.baidu.com/s?wd=%E8%8E%AB%E7%83%A6Python

Process finished with exit code 0

使用requests模塊進行post請求:

在這個網頁http://pythonscraping.com/pages/files/form.html中,我們可以提交姓名,然後網頁會返回一個包含你提交內容的信息,如:

注意這裏只是一個展示,實際上大多數情況下,你post過去的信息是交給服務器內部處理的,不是用來顯示在網址上的。

觀察網頁的源代碼:

<h2>Tell me your name!</h2>
<form method="post" action="processing.php">
First name: <input type="text" name="firstname"><br>
Last name: <input type="text" name="lastname"><br>
<input type="submit" value="Submit" id="submit">
</form>

然後發現我們填入姓名的地方原來是在一個 <form> 裏面。這個 <form> 裏面有幾個<input>  tag, 我們可以看到有兩個 <input> 裏面的值 name="firstname" 和 name="lastname",這兩個就是我們要 post 提交上去的信息。

我們填好姓名, 選擇 Network, 勾選 Preserve log, 再點擊 “submit”, 我們可以觀察到我們提交的post請求。

該.php文件中內容如下:

General

Request URL:http://pythonscraping.com/pages/files/processing.php
Request Method:POST
Status Code:200 OK
Remote Address:198.27.68.184:80
Referrer Policy:no-referrer-when-downgrade
Response Headers

Connection:Keep-Alive
Content-Type:text/html; charset=UTF-8
Date:Mon, 24 Sep 2018 07:40:03 GMT
Keep-Alive:timeout=5, max=100
Server:Apache
Transfer-Encoding:chunked
Request Headers

Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding:gzip, deflate
Accept-Language:zh-CN,zh;q=0.9
Cache-Control:max-age=0
Connection:keep-alive
Content-Length:26
Content-Type:application/x-www-form-urlencoded
Host:pythonscraping.com
Origin:http://pythonscraping.com
Referer:http://pythonscraping.com/pages/files/form.html
Upgrade-Insecure-Requests:1
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36
Form Data

firstname:111
lastname:222

這些數據中包含了:

Request URL (post請求要用的 URL);

Request Method (post);

Form Data (post 去的信息),可以觀察到我們提交的111和222信息也在裏面。

現在我們用Python 來模擬這一次提交post請求登錄Cookies。

我們把 'firstname' 和 'lastname'信息組織成一個 python 字典,然後把這個字典傳入 requests.post()。

注意,:

這裏的 post 裏面的 url, 不是我們填表時的 url (http://pythonscraping.com/pages/files/form.html), 而是要把 Form 信息提交去的那個網頁, 也就是上圖中查看到的 Request URL (http://pythonscraping.com/files/processing.php)。

import requests

data = {'firstname': '莫煩', 'lastname': '周'}
r = requests.post('http://pythonscraping.com/pages/files/processing.php', data=data)
# 要post過去的data是上面定義的字典
print(r.text)

運行結果如下:

Hello there, 莫煩 周!

上傳圖片的post請求:

傳照片也是 post請求的一種。

http://pythonscraping.com/files/form2.html我們使用這個網頁來上傳照片。

網頁源代碼如下:


<h2>Upload a file!</h2>
<form action="../pages/files/processing2.php" method="post" enctype="multipart/form-data">
  Submit a jpg, png, or gif: <input type="file" name="uploadFile"><br>
  <input type="submit" value="Upload File">
</form>

我們可以發現有 <input> 對象裏是一個叫 uploadFile 的名字. 我們將這個名字記作爲key放入 python 的字典中。接着在字典中, 使用 open打開一個圖片文件, 當做要上傳的文件。把這個字典放入你的 post裏面的 files 參數,就能上傳你的圖片了, 網頁會返回一個頁面, 將你的圖片名顯示在上面。

如:

import requests

file = {'uploadFile': open('./1.png', 'rb')}
r = requests.post('http://pythonscraping.com/pages/files/processing2.php', files=file)
print(r.text)

運行結果如下:

uploads/1.png
The file 1.png has been uploaded.

爬蟲登陸Cookies:

我們使用這個網頁來模擬登陸:http://pythonscraping.com/pages/cookies/login.html

先手動試一下:

登陸後轉到下面這個網頁:

登陸賬號時,瀏覽器做了以下工作:

使用 post 方法登錄了上面畫紅線的url;

post 的時使用了Form data中的用戶名和密碼;

生成了一些 cookies。

什麼是cookies:

cookies就是用來保存你登陸這個網站的登陸信息,當我訪問這個網站中的不同頁面時,保存的cookies將被調用,服務器將知道我之前是否登錄,以哪個賬號登錄的,從而給我相應的權限。

cookies的傳遞:

用 requests.post + payload 的用戶信息發給網頁, 返回的 r 裏面會有生成的 cookies 信息. 接着我請求去登錄後的頁面時, 使用 request.get, 並將之前的 cookies 傳入到 get 請求. 這樣就能已登錄的名義訪問 get 的頁面。

如:

import requests

payload = {'username': 'morvan', 'password': 'password'}
r = requests.post('http://pythonscraping.com/pages/cookies/welcome.php', data=payload)
print(r.cookies.get_dict())
r = requests.get('http://pythonscraping.com/pages/cookies/welcome.php', cookies=r.cookies)
print(r.text)

運行結果如下:

{'loggedin': '1', 'username': 'morvan'}

<h2>Welcome to the Website!</h2>
You have logged in successfully! <br><a href="profile.php">Check out your profile!</a>

Process finished with exit code 0

使用Session登錄:

每次像上面這樣傳遞cookies很麻煩,requests中提供了一個很方便的功能就是Session,它可以自動幫我們傳遞這些cookies信息。創建完一個 session 過後, 我們直接只用 session 來 post 和 get。而且這次 get 的時候, 我們並沒有傳入 cookies. 但是實際上 session 內部就已經有了之前的 cookies 了。

如:

import requests

session = requests.Session()
payload = {'username': 'morvan', 'password': 'password'}
r = requests.post('http://pythonscraping.com/pages/cookies/welcome.php', data=payload)
print(r.cookies.get_dict())
r = requests.get('http://pythonscraping.com/pages/cookies/welcome.php')
print(r.text)

運行結果如下:

{'loggedin': '1', 'username': 'morvan'}

<h2>Welcome to the Website!</h2>
Whoops! You logged in wrong. Try again with any username, and the password "password"<br><a href="login.html">Log in here</a>

Process finished with exit code 0

爬蟲下載文件的幾種方式:

我們以這個鏈接爲例:https://morvanzhou.github.io/learning-steps/

打開該鏈接,鼠標移動到圖片上,右鍵審查元素,如下圖:

我們發現這張圖片被存放在/static/img/description/learning_step_flowchart.png" 這個網頁, 注意這個地址開頭是 /, 並不是完整的網址, 它是在 “https://morvanzhou.github.io/” 下面的網址。我們還要將其補全, 才能在網址欄中找到這個圖片地址。補全後爲:

https://morvanzhou.github.io/static/img/description/learning_step_flowchart.png

然後我們把這個圖片下載下來。

import os
from urllib.request import urlretrieve
import requests

os.makedirs('./img/', exist_ok=True)
# 創建一個空文件夾用於存放圖片
IMAGE_URL = "https://morvanzhou.github.io/static/img/description/learning_step_flowchart.png"
urlretrieve(IMAGE_URL, './img/image1.png')
# 用urlretrieve下載鏈接的內容,並放置和命名。
# 或者也可以用get方式下載文件
r = requests.get(IMAGE_URL)
with open('./img/image2.png', 'wb')as f:
	f.write(r.content)
# 打開文件並寫入方式
# 上面兩種是把文件完整地下載到內存後再寫入本地磁盤,如果
# 文件很大,下面一種方式支持邊下載邊寫入磁盤
r2 = requests.get(IMAGE_URL, stream=True)
with open('./img/image3.png', 'wb')as f:
	for chunk in r.iter_content(chunk_size=32):
		f.write(chunk)
# 每下載滿32B就寫入文件

運行截圖如下,三種方式均下載了文件。

練習:下載國家地理雜誌美圖

用於爬取的頁面:http://www.ngchina.com.cn/animals/

隨便查看了幾張圖的審查元素,發現它們都存在於img_list 的這種 <ul> 中。

我們只要找到帶有 img_list 的這種 <ul>, 然後在 <ul> 裏面找 <img>。然後提取 <img> 的 src 屬性, 裏面的就是圖片的網址。然後把它們下載下來即可。

from bs4 import BeautifulSoup
import requests

URL = "http://www.ngchina.com.cn/animals/"
html = requests.get(URL).text
# 獲取網頁全部代碼
soup = BeautifulSoup(html, 'lxml')
# 使用BeautifulSoup分析代碼,分解代碼爲各個部分
img_ul = soup.find_all('ul', {"class": "img_list"})
# 尋找代碼中所有ul中class爲img_list的部分
for ul in img_ul:
	imgs = ul.find_all('img')
	# 每一個ul中的所有img對象賦給imgs
	for img in imgs:
		url = img['src']
		# 每個img對象中的每一個img的鏈接提取出來
		r = requests.get(url, stream=True)
		# 下載該鏈接對應的圖片
		image_name = url.split('/')[-1]
		# 用鏈接/的最後一部分給圖片命名
		with open('./img/%s' % image_name, 'wb')as f:
			for chunk in r.iter_content(chunk_size=128):
				f.write(chunk)
			# 每下載128B就存入文件中
		print('Saved %s' % image_name)
	# 報告下載完成的圖片名

運行截圖如下,可以看到所有這種命名格式鏈接的圖片都被下載下來了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章