自学Python第十四天- 一些有用的模块:urllib、requests 网络编程基础,向爬虫靠拢
自學(xué)Python第十四天- 一些有用的模塊:urllib、requests 網(wǎng)絡(luò)編程基礎(chǔ),向爬蟲靠攏
- fake_useragent 庫
- 安裝 fake_useragent
- 使用
- urllib 庫
- urllib.request
- request 的簡(jiǎn)單使用
- urllib.request.urlopen 函數(shù)的參數(shù)
- 獲取 request 的狀態(tài)碼
- 使用 urllib.request 設(shè)置請(qǐng)求頭
- 發(fā)送帶數(shù)據(jù)的請(qǐng)求
- https 請(qǐng)求
- 使用代理服務(wù)器
- 下載數(shù)據(jù)文件
- urllib.error
- urllib.parse
- urllib.robotparser
- requests 庫
- 簡(jiǎn)單發(fā)送請(qǐng)求
- 關(guān)閉連接
- 處理編碼
- 設(shè)置請(qǐng)求頭
- 查看請(qǐng)求頭
- 發(fā)送 post 請(qǐng)求
- 發(fā)送附加參數(shù)的 get 請(qǐng)求
- 通用請(qǐng)求
- 使用cookie
- 處理反爬
- https 請(qǐng)求
- 使用代理
- 響應(yīng)對(duì)象的常用屬性和方法
- 下載二進(jìn)制文件
python 很大的一個(gè)優(yōu)點(diǎn)就是爬蟲編寫方便,當(dāng)然在寫爬蟲之前還需要網(wǎng)絡(luò)編程的基礎(chǔ),畢竟爬蟲是基于網(wǎng)絡(luò)的程序。
fake_useragent 庫
fake_useragent 是一個(gè)第三方庫,作用僅僅是更換請(qǐng)求頭中的 UserAgent ,偽裝瀏覽器。因?yàn)橛玫谋容^方便,發(fā)送的請(qǐng)求都會(huì)用到,所以寫在最前。
安裝 fake_useragent
使用 pip install fake-useragent 進(jìn)行安裝,使用 from fake_useragent import UserAgent 引入使用。
使用
使用 UserAgent 對(duì)象的各種方法能生成 useragent 信息,例如:
from fake_useragent import UserAgentuseragent_chrome = UserAgent().chrome # 模擬 chrome 瀏覽器生成 useragent 信息 useragent_random = UserAgent().random # 隨機(jī)模擬瀏覽器生成 useragent 信息使用需要注意的是,盡量及時(shí)更新 fake_useragent 庫
urllib 庫
python 進(jìn)行網(wǎng)絡(luò)編程,可以使用 python 的內(nèi)置庫: urllib 庫。urllib 庫分為以下幾個(gè)模塊:
- urllib.request :打開和讀取 URL
- urllib.error :包含 urllib.request 拋出的異常
- urllib.parse :解析 URL
- urllib.rebotparser :解析 robots.txt 文件
urllib.request
urllib.request 負(fù)責(zé)打開和讀取 URL,是 urllib 庫最重要也最常用的模塊。其定義了一些打開 URL 的函數(shù)和類,包含授權(quán)驗(yàn)證、重定向、瀏覽器 cookkies 等。它可以模擬瀏覽器的一個(gè)請(qǐng)求發(fā)起過程。
request 的簡(jiǎn)單使用
request 最簡(jiǎn)單的用法就是模擬瀏覽器發(fā)送一個(gè)請(qǐng)求,并獲取應(yīng)答。
from urllib.request import urlopenurl = 'https://www.baidu.com' # 設(shè)置請(qǐng)求地址 resp = urlopen(url) # 發(fā)送請(qǐng)求,并獲得應(yīng)答 print(resp.read().decode('utf-8') # 查看應(yīng)答信息,因?yàn)槟J(rèn)是以二進(jìn)制查看,所以需要解碼為 utf-8這樣就獲取到了應(yīng)答信息。輸出的是 html 文本,也可以寫到文件中使用瀏覽器打開。
with open('mybaidu.html', 'w', encoding='utf-8') as file:file.write(resp.read().decode('utf-8'))urllib.request.urlopen 函數(shù)的參數(shù)
urlopen 函數(shù)的全部參數(shù)如下:
urllib.request.urlopen(url, data=None, [timeout, ]*, cafile=None, capath=None, cadefault=False, context=None)
- url :url地址,此參數(shù)也是唯一一個(gè)必須參數(shù)
- data :發(fā)送到服務(wù)器的其他數(shù)據(jù)對(duì)象,默認(rèn) None
- timeout :訪問超時(shí)時(shí)間
- cafile 和 capath :CA證書的文件名和路徑,使用 HTTPS 需要用到
- context :ssl.SSLContext 類型,用來指定 SSL 設(shè)置
獲取 request 的狀態(tài)碼
發(fā)送請(qǐng)求后無論如何會(huì)收到一個(gè)狀態(tài)碼,這個(gè)狀態(tài)碼會(huì)表示該請(qǐng)求的響應(yīng)狀態(tài)。例如 200 成功、404 頁面未找到等。
import urllib.requestmyURL1 = urllib.request.urlopen("https://www.runoob.com/") print(myURL1.getcode()) # 200try:myURL2 = urllib.request.urlopen("https://www.runoob.com/no.html") except urllib.error.HTTPError as e:if e.code == 404:print(404) # 404具體的狀態(tài)碼和含義可以看這里:
HTTP請(qǐng)求狀態(tài)碼
使用 urllib.request 設(shè)置請(qǐng)求頭
我們抓取網(wǎng)頁一般需要對(duì) headers(網(wǎng)頁頭信息)進(jìn)行模擬,這時(shí)候需要使用到 urllib.request.Request 類:
class urllib.request.Request(url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None)
- url :url地址
- data :發(fā)送請(qǐng)求的其他數(shù)據(jù)對(duì)象
- headers :請(qǐng)求頭信息,字典格式
- origin_req_host :請(qǐng)求的主機(jī)地址,IP 或域名
- unverifiable :很少用整個(gè)參數(shù),用于設(shè)置網(wǎng)頁是否需要驗(yàn)證
- method :請(qǐng)求方法, 如 GET、POST、DELETE、PUT等
上面的例子是將請(qǐng)求頭以實(shí)參形式傳入,也可以使用 Request.add_header() 方法添加請(qǐng)求頭信息。
import urllib.requesturl = 'http://www.baidu.com/' req = urllib.request.Request(url) req.add_header("User-Agent",'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36') html = urllib.request.urlopen(req).read()發(fā)送帶數(shù)據(jù)的請(qǐng)求
因?yàn)?Request 類的數(shù)據(jù)信息必須是字節(jié)型的,所以需要使用 urllib.parse 進(jìn)行編碼
import urllib.request import urllib.parseurl = 'https://www.runoob.com/try/py3/py3_urllib_test.php' # 提交到表單頁面 data = {'name':'RUNOOB', 'tag' : '菜鳥教程'} # 提交數(shù)據(jù) header = {'User-Agent':'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36' } #頭部信息 data = urllib.parse.urlencode(data).encode('utf8') # 對(duì)參數(shù)進(jìn)行編碼,解碼使用 urllib.parse.urldecode request=urllib.request.Request(url, data, header) # 請(qǐng)求處理 response=urllib.request.urlopen(request).read() # 讀取結(jié)果 print(response.decode('utf-8'))https 請(qǐng)求
import ssl# 忽略安全認(rèn)證 context = ssl._create_unverified_context() # 添加到 context 參數(shù)中 resp = urllib.request.urlopen(request,context = context)使用代理服務(wù)器
使用代理服務(wù)器分為5步:設(shè)置代理、創(chuàng)建代理、應(yīng)用代理、創(chuàng)建 Request 對(duì)象、發(fā)送訪問請(qǐng)求:
import urllib.request# 設(shè)置代理 httpproxy_handler = urllib.request.ProxyHandler({'https': 'daili.com:8888'}) # 創(chuàng)建代理 opener = urllib.request.build_opener(httpproxy_handler) # 將代理應(yīng)用到全局 urllib.request.install_opener(opener) # 創(chuàng)建 request 對(duì)象 request = urllib.request.Request(url) # 發(fā)送請(qǐng)求 html = urllib.request.urlopen(request).read()下載數(shù)據(jù)文件
可以使用 urllib.request.urlretrieve() 方法下載一些數(shù)據(jù)文件,例如圖片等。
urllib.request.urlretrieve(url,filename)urllib.error
urllib.error 模塊為 urllib.request 所引發(fā)的異常定義了異常類,基礎(chǔ)異常類是 URLError。urllib.error 包含了兩個(gè)方法,URLError 和 HTTPError。
URLError 是 OSError 的一個(gè)子類,用于處理程序在遇到問題時(shí)會(huì)引發(fā)此異常(或其派生的異常),包含的屬性 reason 為引發(fā)異常的原因。
HTTPError 是 URLError 的一個(gè)子類,用于處理特殊 HTTP 錯(cuò)誤,例如作為認(rèn)證請(qǐng)求的時(shí)候,包含的屬性 code 為 HTTP 的狀態(tài)碼, reason 為引發(fā)異常的原因,headers 為導(dǎo)致 HTTPError 的特定 HTTP 請(qǐng)求的 HTTP 響應(yīng)頭。
例如對(duì)不存在的頁面抓取并處理異常:
import urllib.request import urllib.errormyURL1 = urllib.request.urlopen("https://www.runoob.com/") print(myURL1.getcode()) # 200try:myURL2 = urllib.request.urlopen("https://www.runoob.com/no.html") except urllib.error.HTTPError as e:if e.code == 404:print(404) # 404 import urllib.request import urllib.errordef download_with_retry(url,num_retries):print('下載中 ',url)try:# 下載網(wǎng)頁并獲取網(wǎng)頁的 html 內(nèi)容html = urllib.request.urlopen(url).read()except urllib.erroe.URLError as e:if hasattr(e, 'reason'):print('下載失敗')print('失敗原因:', e.reason)if hasattr(e, 'code'):print('服務(wù)器不能完成請(qǐng)求')print('錯(cuò)誤代碼:', e.code)if num_retries>0 and 500<=e.code<600:return download_with_retries(url,num_retries-1)return htmlurllib.parse
urllib.parse 用于解析 URL,格式如下:
urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)
- urlstring 為字符串的 url 地址
- scheme 為協(xié)議類型,
- allow_fragments 參數(shù)為 false,則無法識(shí)別片段標(biāo)識(shí)符。相反,它們被解析為路徑,參數(shù)或查詢組件的一部分,并 fragment 在返回值中設(shè)置為空字符串。
也可以使用 urllib.parse.urlencode() 方法將數(shù)據(jù)(中文)進(jìn)行編碼,例如使用 urllib.request.Request 對(duì)象發(fā)送帶數(shù)據(jù)的請(qǐng)求時(shí)的例子。
urllib.robotparser
urllib.robotparser 用于解析 robots.txt 文件。robots.txt(統(tǒng)一小寫)是一種存放于網(wǎng)站根目錄下的 robots 協(xié)議,它通常用于告訴搜索引擎對(duì)網(wǎng)站的抓取規(guī)則。
requests 庫
requests 庫也是 python 用于網(wǎng)絡(luò)編程的一個(gè)庫,由于是第三發(fā)庫,所以需要進(jìn)行安裝。
requests 庫的參考文檔
簡(jiǎn)單發(fā)送請(qǐng)求
import requestsurl = 'https://www.sogou.com/web?query=周杰倫' resp = requests.get(url) print(resp) # 執(zhí)行結(jié)果: <Response [200]> print(resp.text) # 執(zhí)行結(jié)果為頁面內(nèi)容關(guān)閉連接
請(qǐng)求頭中有一種設(shè)置:Connection: keep-alive ,如果不顯式的斷開連接,則會(huì)長時(shí)間占用TCP連接。通常可以發(fā)送一個(gè)請(qǐng)求報(bào)文,設(shè)置 Connection: close 。但是實(shí)際上其實(shí)可以直接對(duì)連接對(duì)象進(jìn)行關(guān)閉。
resp.close() # 關(guān)閉 resp 連接處理編碼
一般在響應(yīng)頭或者是請(qǐng)求到的 html 文檔中,會(huì)有文檔編碼 charset=utf-8 的注釋,表示此文檔使用哪種編碼。此時(shí)如果直接查看是亂碼的,可以設(shè)置編碼后再進(jìn)行查看
resp.encoding = 'utf-8' # 使用 utf-8 編碼 resp.encoding = resp.apparent_encoding # 使用自適應(yīng)編碼,在不知道具體編碼時(shí)候可以使用此項(xiàng),正確率很高設(shè)置請(qǐng)求頭
上一個(gè)例子中,訪問 https://www.sogou.com/web?query=周杰倫 時(shí)可以發(fā)現(xiàn),瀏覽器可以正常訪問,而 python 程序則不行。所以需要設(shè)置請(qǐng)求頭,模擬普通瀏覽器發(fā)送請(qǐng)求來訪問頁面。
requests 庫的請(qǐng)求頭寫在一個(gè)字典內(nèi),并且在發(fā)送請(qǐng)求時(shí)需要傳遞至方法實(shí)參。
import requestsurl = 'https://www.sogou.com/web?query=周杰倫' header = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36" } resp = requests.get(url, headers=header)print(resp.text)這里請(qǐng)求頭里的 User-Agent 信息可以使用瀏覽器調(diào)試工具獲取。
查看請(qǐng)求頭
在爬蟲測(cè)試中,如果被反爬了,則很大幾率是出在請(qǐng)求頭的 User-Agent 里。我們可以先查看下請(qǐng)求頭信息。
import requestsurl = 'https://www.sogou.com/web?query=周杰倫' resp = requests.get(url) print(resp.request.headers) # 輸出請(qǐng)求頭信息發(fā)送 post 請(qǐng)求
發(fā)送 post 請(qǐng)求使用 requests.post() 方法。發(fā)送的數(shù)據(jù)是以字典形式傳入實(shí)參。
import requestsurl = 'https://fanyi.baidu.com/sug' header = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36" } d = {'kw': 'dog'} resp = requests.post(url, headers=header, data=d) print(resp.json()) # 以 json 字符串形式輸出發(fā)送附加參數(shù)的 get 請(qǐng)求
get 請(qǐng)求的參數(shù)除了可以直接寫在 url 里,還可以使用附加方式發(fā)送:
import requestsurl = 'https://movie.douban.com/j/chart/top_list' header = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36" } param = {'type': '24','interval_id': '100:90','action': '','start': 0,'limit': 20 } resp = requests.get(url, headers=header, params=param)print(resp.request.url) print(resp.json())通用請(qǐng)求
可以使用 requests.request() 方法來發(fā)送任意類型的請(qǐng)求。
resp = requests.request(method, url, **kwargs)其中 method 和 url 為必填項(xiàng),**kwargs 是可選,可以加入參數(shù)、數(shù)據(jù)、json、請(qǐng)求頭、cookies、文件、代理信息 等。
使用cookie
有些網(wǎng)站的頁面請(qǐng)求需要 cookie 信息,一般 cookie 由瀏覽器存儲(chǔ)在本地,使用 session 獲取。使用 requests 進(jìn)行請(qǐng)求時(shí)每次均是一個(gè)新的請(qǐng)求,所以先建立 session 進(jìn)行登錄,然后登錄信息包括 cookie 就保存在了 session 中。
import requests# 建立會(huì)話 session = requests.session() # 登錄請(qǐng)求地址 url = 'https://passport.17k.com/ck/user/login' # 請(qǐng)求登錄會(huì)話(不需要返回值是因?yàn)榈卿浀男畔⒃赾ookie中,cookie信息保存在session里) session.post(url, data={'loginName': 'xxxxxxxxx', 'password': 'xxxxxx'}) # 獲取書架上的數(shù)據(jù)(使用session進(jìn)行請(qǐng)求,則可以使用保存的cookie信息) resp = session.get('https://user.17k.com/ck/author/shelf?page=1&appKey=xxxxxxxxx') print(resp.json())也可以使用在頭部信息中添加 cookie 的方式直接進(jìn)行請(qǐng)求
import requests# 也可以直接請(qǐng)求,在頭部信息中添加 cookie 信息 resp = session.get('https://user.17k.com/ck/author/shelf?page=1&appKey=2406394919', headers={"Cookie": "GUID=xxxxxxxxxxxxxxxxxxxxxxxxxxx; sajssdk_2015_cross_new_user=1; c_channel=0; c_csc=web; accessToken=avatarUrl%3Dhttps%253A%252F%252Fcdn.static.17k.com%252Fuser%252Favatar%25xxxxxxxxxxxxxxxxxx33034.jpg-88x8xxxxxxxxxxxxxxxxxid%3D97233034%26nickname%3D%25Exxxxxxxxxxxx25E5%25A4%25A7%25E4%25BA%25A8%26e%3D1672538270%26s%3Dd0bfe4952e8fe4e2; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2297233034%2xxxxxxxxxxxxxxxxxxx181cbf9d99daa9-009b458c304258-57b1a33-2073600-181cbf9d99e67c%22%2C%22prxxxxxxxxxxxxxxxe%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9xxxxxxxxxxxxxxerrer%22%3A%22%22%2C%22%24latest_referrer_host%22%3A%22%22%xxxxxxxxxxxxxxxxxx9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%xxxxxxxxxxxxxxx%22%7D%2C%22first_id%22%xxxxxxxxa388384-bf3dxxxxxxxxxxxxxxxxxx56%22%7D" }) print(resp.json())處理反爬
通常對(duì)于反爬,經(jīng)常使用的手段就是驗(yàn)證 User-Agent ,驗(yàn)證 cookie ,防盜鏈 ,和 url 加密。對(duì)于驗(yàn)證可以在請(qǐng)求頭部信息中增加響應(yīng)信息,防盜鏈可以在請(qǐng)求頭增加 Referer 信息,url 加密就需要進(jìn)行分析了。
這里以下載梨視頻的視頻文件舉例。通過分析頁面和源代碼可以發(fā)現(xiàn)視頻 url 是經(jīng)過了一個(gè)替換變形,那么獲取到響應(yīng)信息再替換回來就能得到正確的視頻信息。
# 1. 拿到contId # 2. 拿到videoStatus返回的json -> srcURL # 3. srcURL里面的內(nèi)容進(jìn)行修整 # 4. 下載視頻import requests# 視頻頁面地址 url = 'https://pearvideo.com/video_1759848' contId = url.split('_')[1] headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36","Referer": url # 防盜鏈:進(jìn)行溯源,即請(qǐng)求的上一級(jí)頁面 } # 視頻信息請(qǐng)求地址 videoStatusUrl = f'https://pearvideo.com/videoStatus.jsp?contId={contId}&mrd=0.5621134865680251' # 獲取相應(yīng)json resp = requests.get(videoStatusUrl, headers=headers) # 從json中獲取正確的視頻地址 dic = resp.json() srcUrl = dic['videoInfo']['videos']['srcUrl'] systemTime = dic['systemTime'] srcUrl = srcUrl.replace(systemTime, f'cont-{contId}') # 下載視頻 filename = './download/' + srcUrl.split('/')[-1] with open(filename, mode='wb') as f:f.write(requests.get(srcUrl).content)https 請(qǐng)求
resp = requests.get(url,verify=False) # 忽略安全認(rèn)證使用代理
requests 使用代理和 urllib 使用代理類似,將代理字典(包含協(xié)議、地址+端口)以實(shí)參形式傳入請(qǐng)求的形參 proxies 即可。
proxies = {"http": "39.130.150.44:80" # 舉個(gè)例子 } resp = requests.get(url, headers=head, proxies=proxy)響應(yīng)對(duì)象的常用屬性和方法
不管使用 get 還是 post 發(fā)送了請(qǐng)求后,會(huì)返回一個(gè) Response 對(duì)象,可以通過此對(duì)象的一些屬性和方法獲得我們想要的數(shù)據(jù):
r = requests.get('https://www.baidu.com')
- r.status_code :返回狀態(tài)碼
- r.reason :返回請(qǐng)求失敗原因(請(qǐng)求成功返回 OK)
- r.cookies :返回請(qǐng)求 cookies
- r.headers :返回響應(yīng)頭
- r.encoding :返回或設(shè)置響應(yīng)內(nèi)容的編碼
- r.content :返回響應(yīng)內(nèi)容(二進(jìn)制內(nèi)容)
- r.text :返回響應(yīng)內(nèi)容的文本(相當(dāng)于 r.content.decode(‘utf-8’))
- r.json() :將響應(yīng)內(nèi)容 json 化并返回
- r.request :返回發(fā)送的請(qǐng)求信息
下載二進(jìn)制文件
可以使用 r.content 直接獲取二進(jìn)制文件內(nèi)容
img_resp = requests.get(srcUrl) # 請(qǐng)求圖片 with open('img.jpg', mode='wb') as f:f.write(img_resp.content) # 寫入二進(jìn)制數(shù)據(jù)也可以使用二進(jìn)制流的方式獲取原始套接字響應(yīng)。使用分片能夠處理大文件,可以邊獲得二進(jìn)制響應(yīng)邊寫入文件。當(dāng)使用流下載時(shí),優(yōu)先推薦此種方法。
img_resp = requests.get(srcUrl, stream=True) with open('img.jpg', mode='wb') as f:for chunk in img_resp.iter_content(chunk_size): # chunk_size 是分片讀取的每一片的大小,單位字節(jié)f.write(chunk)總結(jié)
以上是生活随笔為你收集整理的自学Python第十四天- 一些有用的模块:urllib、requests 网络编程基础,向爬虫靠拢的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: More effective C++学习
- 下一篇: websocket python爬虫_p