https://www.toutiao.com/article/7199248407486153277/?log_from=030bdd62db76a_1676265605503 (HTML頁面的代碼) 談及到Python爬蟲,必不可少的就是requests模塊。前面內(nèi)容中我們也講到Python有豐富多彩的第三方模塊,那么requests就是其中一個,requests模塊是一個常用的訪問網(wǎng)絡(luò)的模塊。使用requests可以模擬瀏覽器的請求,比起之前用到的urllib,requests模塊的api更加便捷(requests的本質(zhì)也是對urllib3進行了封裝) 初識Requests 先來一段簡單的代碼,看下request的作用。 #爬取百度首頁的內(nèi)容import requests url = 'https://www.baidu.com/'response = requests.get(url)# 輸出響應(yīng)狀態(tài)碼print("狀態(tài)碼:{0}".format(response.status_code))# 輸出響應(yīng)字符編碼print("字符編碼:{0}".format(response.encoding))# 輸出響應(yīng)文本內(nèi)容print("響應(yīng)文本:{0}".format(response.text)) 然后運行一下可以看見程序的結(jié)果: 狀態(tài)碼:200 字符編碼:ISO-8859-1 響應(yīng)文本:<!DOCTYPE html><!--STATUS OK--><html> <head><meta http-equiv=content-type ontent=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1./5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>????o|??????????? ?°±??¥é??</title></head>……. 由于內(nèi)容比較長,就先放一部分結(jié)果。我們可以看到請求響應(yīng)狀態(tài)是200,正確響應(yīng)。 響應(yīng)的內(nèi)容就是百度網(wǎng)頁的HTML源碼,然后瀏覽器拿到接收到的源碼后,將其展示到頁面上。而當(dāng)我們用Python爬蟲瀏覽頁面的時候,只能看到的是網(wǎng)站的源碼,然后在其中獲取我們需要的信息。 在上圖上,我們可以發(fā)現(xiàn),其實除了英文,還有一些亂碼,亂碼是由于編碼格式造成的。一般情況下,網(wǎng)站都是使用兼容度高的UTF8編碼格式,而當(dāng)前的網(wǎng)頁是使用的ISO-8859-1,我們可以把拿到的response設(shè)置下編碼格式: #爬取百度首頁的內(nèi)容 #爬取百度首頁的內(nèi)容url = 'https://www.baidu.com/' response = requests.get(url) response.encoding = "UTF8" # 輸出響應(yīng)狀態(tài)碼 print("狀態(tài)碼:{0}".format(response.status_code)) # 輸出響應(yīng)字符編碼 print("字符編碼:{0}".format(response.encoding)) # 輸出響應(yīng)文本內(nèi)容 print("響應(yīng)文本:{0}".format(response.text)) 然后重新運行看下效果,結(jié)果如下圖,現(xiàn)在可以看到正常的編碼的網(wǎng)頁源碼。 狀態(tài)碼:200 字符編碼:UTF8 響應(yīng)文本:<!DOCTYPE html><!--STATUS OK--><html> <head><meta http-equiv=content-type content=text/html;charset=utf-8><meta http-equiv=X-UA-Compatible content=IE=Edge><meta content=always name=referrer><link rel=stylesheet type=text/css href=https://ss1./5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css><title>百度一下,你就知道</title></head>……. Requests模塊使用簡單,功能強大,完全可以實現(xiàn)常規(guī)簡單爬蟲的編寫,所以熟練使用Requests是獲取數(shù)據(jù)的核心基礎(chǔ),接下來我們了解一些常用的功能。 請求的方式上面示例中requests.get()是用的GET請求方式,而HTTP 請求可以使用多種請求方法,最常用的就是GET和POST請求。除此之外HEAD、OPTIONS、PUT、PATCH、DELETE、TRACE 和CONNECT ,一共9種請求方式。各個請求方式主要的差別如下表所示,其中Requests是支持前7種請求方式。
使用方式跟GET方式一樣,直接requests跟請求方式關(guān)鍵詞即可,如果發(fā)送一個POST請求: import requestsurl = 'https://www.baidu.com/'# post請求response = requests.post(url)# head請求response = requests.head(url)# put請求response = requests.put(url) 請求中傳參數(shù)通常情況下,我們使用requests獲取一個網(wǎng)頁的內(nèi)容,都會攜帶一些參數(shù),服務(wù)器會根據(jù)這些參數(shù)的不同做出不同的響應(yīng),爬蟲中最常使用的就是分頁參數(shù)。比如說,我們想查看某個頁面中第5頁的內(nèi)容,我們一般可以把頁碼參數(shù)設(shè)置為5加在請求連接中。那么怎么添加請求參數(shù)呢? 如果是GET請求,最直接的方法可以手動構(gòu)建,在鏈接后面添加參數(shù)。比如: import requests url = ' https://www.baidu.com/?pageNum=5&pageSize=10'response = requests.get(url) 當(dāng)然Requests 允許你使用 params 關(guān)鍵字參數(shù),以一個字符串字典來提供這些參數(shù)。拿上面的參數(shù)來說,代碼如下: import requests url = 'https://www.baidu.com'params = {'pageNum': '5', 'pageSize': '10'} response = requests.get(url, params=params) print("完整請求地址:{0}".format(response.url)) 而Requests最終的請求地址也是跟我們手動組裝的鏈接是一樣的,代碼運行結(jié)果如下: 完整請求地址:https://www.baidu.com/?pageNum=5&pageSize=10 注意:字典里的值為 None 的鍵都不會被添加到URL中。 除了GET請求,還有常用的POST請求。我們都知道POST請求安全性會比GET高,請求體不會直接添加在明文的鏈接中。一般網(wǎng)頁中表單數(shù)據(jù)的提交都是通過POST請求進行,所以我們也需要知道,requests怎么在POST請求中添加參數(shù)。 其實也可以跟GET請求一下,用一個字典來存放你需要提交的數(shù)據(jù)。同樣用上面的例子,也可以這樣做改成POST請求來處理: import requests url = 'https://www.baidu.com'params = {'pageNum': '5', 'pageSize': '10'} response = requests.post(url, data=params)print("完整請求地址:{0}".format(response.url)) 注意:跟GET請求不同的是,POST請求的參數(shù)名為data而不是params,雖然他們可以都是字典。 在這種需要提交表單的鏈接中,很多的還會采用Json來傳輸數(shù)據(jù),Json是一種輕量級的數(shù)據(jù)交換格式。而且在前后端分離的系統(tǒng)中,多數(shù)也是用Json作為數(shù)據(jù)交換方式。Requests也是支持json數(shù)據(jù)作為參數(shù)提交請求,如下所示: import requests #需要導(dǎo)入json模塊import json url = 'https://www.baidu.com'data = {'pageNum': '5', 'pageSize': '10'} json = json.dumps(data) response = requests.post(url, json= json) json模塊提供了Pyhon字典對象和Json對象的轉(zhuǎn)換方法,我們可以直接使用json.dumps()方法來轉(zhuǎn)換對象。我們也可以直接創(chuàng)建一個json對象。 import requests#需要導(dǎo)入json模塊import jsonurl = 'https://www.baidu.com'data = {“pageNum”: “5”, “pageSize” : “10”}response = requests.post(url, json= data) 上面我們手動創(chuàng)建的對象跟上之前的json.dumps(data)得到的結(jié)果是一樣的,感興趣的讀者可以試一下。在數(shù)據(jù)獲取中,多數(shù)情況我們獲取得到的是Json對象,需要將其轉(zhuǎn)換成Python對象來使用。 優(yōu)化請求頭在前面提到一個用來告訴服務(wù)器訪問者身份的參數(shù)——User-Agent,這就是Request請求頭中的一個參數(shù)。在上面所有的例子,我們并沒有設(shè)置一個請求頭,也沒有User-Agent也是可以正常訪問的。這是因為百度并沒有對請求頭做限制,如果在其他的網(wǎng)站中沒有User-Agent,服務(wù)器會認為這些請求是機器人發(fā)送的,為了保護自身的服務(wù)器安全,減少服務(wù)器壓力,會拒絕繼續(xù)響應(yīng)這些請求,并且返回一些非正常請求的提示。 我們換一個網(wǎng)站,請求一下豆瓣電影看看會得到什么結(jié)果。 #爬取豆瓣電影首頁的信息import requests url = 'https://movie.douban.com/'response = requests.get(url)# 輸出響應(yīng)狀態(tài)碼print("狀態(tài)碼:{0}".format(response.status_code))# 輸出響應(yīng)文本內(nèi)容print("響應(yīng)文本:{0}".format(response.text)) 輸出結(jié)果如下: 狀態(tài)碼:418響應(yīng)文本: 這就是因為豆瓣電影的服務(wù)器認為當(dāng)前請求不是正常的瀏覽器請求,所以拒絕響應(yīng)。那怎么讓服務(wù)器做出正確的響應(yīng)呢,給requests.get()方法上加上請求頭。我們可以模擬一個正常的瀏覽器,那瀏覽器的User-Agent是啥呢? 這個很好看。以谷歌瀏覽器為例子,先在瀏覽器打開豆瓣電影首頁(https://movie.douban.com),然后按F12,找到NetWork欄目,在按下F5刷新下,這時候瀏覽器會加載這一次訪問的所有內(nèi)容,我們找到Name值為movie.douban.com的請求,點開會發(fā)現(xiàn)后面是這次請求的詳情,如圖所示。 其中在Request Headers中的最后一個key-value就是我們要找的User-Agent,如圖中所示,它的值是Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:85.0) Gecko/20100101 Firefox/85.0 這一串的內(nèi)容意思說這是來自安裝64位的win10的85版本的火狐瀏覽器發(fā)出的請求。所以網(wǎng)站服務(wù)器才給出了正確的響應(yīng)。只要我們把這一串內(nèi)容加到Requests的請求上,那就可以得到正確的回應(yīng)。 代碼如下: #爬取豆瓣電影首頁的信息import requests url = 'https://movie.douban.com/'#設(shè)置請求頭headers = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'}#添加headers參數(shù)response = requests.get(url, headers=headers)# 輸出響應(yīng)狀態(tài)碼print("狀態(tài)碼:{0}".format(response.status_code))# 輸出響應(yīng)文本內(nèi)容print("響應(yīng)文本:{0}".format(response.text)) 現(xiàn)在我們重新run一下,看下是否能得到我們想要的結(jié)果。 狀態(tài)碼:200 響應(yīng)文本:<!DOCTYPE html><html lang="zh-CN" class="ua-windows ua-webkit"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><meta name="renderer" content="webkit"><meta name="referrer" content="always"><meta name="google-site-verification" content="ok0wCgT20tBBgo9_zat2iAcimtN4Ftf5ccsh092Xeyw" /><title>豆瓣電影</title>……… 這樣添加請求頭user-agent,服務(wù)器認為這次請求不是非法請求,做出了正確回應(yīng),得到了我們想要的結(jié)果。除了user-agent,在Request Headers中還有一些比較重要的參數(shù),比如說Cookie,Cookie是由服務(wù)器產(chǎn)生,發(fā)送給User-Agent,瀏覽器會將Cookie的key/value緩存起來,下次請求同一網(wǎng)站將會在Request Headers攜帶Cookie訪問服務(wù)器,以此來保持回話。Cookie也是在爬蟲編寫中一個很重要的參數(shù),后面遇到的時候會詳細說明。 分析響應(yīng)內(nèi)容在前面的操作中,我們已經(jīng)遇見了兩種狀態(tài)碼,200的狀態(tài)碼表示當(dāng)前請求是正常響應(yīng)的。不過這并不是判斷是否得到我們想要的內(nèi)容的判斷標(biāo)準(zhǔn),更主要的是看響應(yīng)的內(nèi)容。有時候還會需要響應(yīng)頭的一些內(nèi)容,響應(yīng)頭怎么查看呢,直接使用response.headers既可以查看: #打印響應(yīng)頭print(response.headers)#輸出結(jié)果:{'Date': 'Sun, 07 Feb 2021 15:54:36 GMT', 'Content-Type': 'text/html; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Keep-Alive': 'timeout=30', 'Vary': 'Accept-Encoding, Accept-Encoding', 'X-Xss-Protection': '1; mode=block', 'X-Douban-Mobileapp': '0', 'Expires': 'Sun, 1 Jan 2006 01:00:00 GMT', 'Pragma': 'no-cache', 'Cache-Control': 'must-revalidate, no-cache, private', 'Set-Cookie': 'll="108296"; path=/; domain=.douban.com; expires=Mon, 07-Feb-2022 15:54:36 GMT, bid=sinsxKkZRR4; Expires=Mon, 07-Feb-22 15:54:36 GMT; Domain=.douban.com; Path=/', 'X-DAE-App': 'movie', 'X-DAE-Instance': 'default', 'X-DOUBAN-NEWBID': 'sinsxKkZRR4', 'Server': 'dae', 'X-Content-Type-Options': 'nosniff', 'Content-Encoding': 'gzip'} 響應(yīng)headers也是一個字典格式的數(shù)據(jù),通過字典的訪問即可獲取值,比如: #打印響應(yīng)頭X-Content-Type-Options的值print(response.headers['X-Content-Type-Options'])#輸出結(jié)果:nosniff 不過更多的內(nèi)容還是需要在響應(yīng)體中,就是上面response.text的內(nèi)容。有時候不同網(wǎng)站的服務(wù)器可能會有很多的攔截驗證,返回的內(nèi)容可能并不是真正想要的內(nèi)容,這時候我們跟瀏覽器中的頁面內(nèi)容比對一下,確認是不是獲得了正確的響應(yīng)。 比較簡單的方法是,在瀏覽器中,右鍵頁面,點擊查看頁面源代碼,如果跟response.text的內(nèi)容基本一樣的話,說明我們的請求沒問題的,接下來的工作就是解析獲得到的內(nèi)容,它的類型是str對象,內(nèi)容就是HTML頁面的代碼。 在解析HTML之前,先簡單的了解一下HTML的知識,這樣會提高我們后面的數(shù)據(jù)采集和收集速度,下一節(jié)我們一起學(xué)習(xí)下HTML基本內(nèi)容 |
|