一木.溪橋學爬蟲-03:請求模組urllib、 urllib.request、urllib.parse.urlencode、urllib.parse.quote(str)、.unquote()
阿新 • • 發佈:2021-02-05
一木.溪橋 在Logic Education跟Jerry學爬蟲
07期:Python 爬蟲 一木.溪橋學爬蟲-03:請求模組urllib、 urllib.request、urllib.parse.urlencode、urllib.parse.quote(str)、parse.unquote()
日期:2021年1月26日
學習目標:
學習內容:
爬蟲請求模組
urllib
為什麼學習 urllib?
- 有的一些比較老的爬蟲專案用的是urllib
- 有時我們在做一些爬蟲的時候往往需要requests + urllib 一起使用
- 是python內建的模組
- urllib在某些方面還是非常強大
urllib的快速入門
-
eg. 下載網上的一張圖片
# 方法1--open, close import requests url = 'https://dss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1603365312,' \ '3218205429&fm=26&gp=0.jpg' req = requests.get(url) fn = open('code.png', 'wb') # 檔案命名為code.png,wb 寫入二進位制資料 fn.write(req.content) # content中間存的是位元組碼(此處圖片儲存的就是二進位制資料),而text中存的是Beautifulsoup根據猜測的編碼方式將content內容編碼成字串。 fn.close()
# 方法2--with open, 可以不用close() import requests url = 'https://dss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1603365312,' \ '3218205429&fm=26&gp=0.jpg' req = requests.get(url) with open('code2.png', 'wb') as file_obj: file_obj.write(req.content)
# 方法3-- 用python內建模組 urllib 中的 request 方法 from urllib import request url = 'https://dss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1603365312,' \ '3218205429&fm=26&gp=0.jpg' request.urlretrieve(url, 'code3.jpg') # url網址,檔名code3.jpg
urllib.request 模組
版本
-
python2 :urllib2、urllib
-
python3 :把urllib和urllib2合併
常用的方法:
- urllib.request.urlopen(“網址”) 作用 :向網站發起一個請求並獲取響應
- 位元組流 = response.read()
- 字串 = response.read().decode(“utf-8”)
- urllib.request.Request"網址",headers=“字典”) urlopen()不支援重構User-Agent
響應物件
- read() 讀取伺服器響應的內容
- getcode() 返回HTTP的響應碼
- geturl() 返回實際資料的URL(防止重定向問題)
import urllib.request
url = 'https://www.baidu.com/'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'
} # User-Agent模擬瀏覽器
# 1 建立請求物件urllib.request.Request() (構造user-agent 反反爬)
req = urllib.request.Request(url, headers=headers)
# 2 獲取響應物件urllib.request.urlopen()
res = urllib.request.urlopen(req)
# 3 讀取響應物件中內容 read().decode('utf-8') bytes --> str
html = res.read().decode('utf-8') # 拿到原始資料
print(html) # 列印原始資料
print(res.getcode()) # 返回狀態碼
print(res.geturl()) # 返回請求的網址(防止重定向問題)
**總結:**urllib.request用法
- 1 建立請求物件 urllib.request.Request() 構建user-agent
- 2 發起請求獲取響應物件 urllib.request.urlopen()
- 3 讀取響應物件的內容 read().decode(‘utf-8’) bytes --> str
常用方法
- urlencode(字典)
- quote(字串) (這個裡面的引數是個字串)
- urllib.parse模組
請求方式
- GET 特點 :查詢引數在URL地址中顯示
- POST
- 在Request方法中新增data引數 urllib.request.Request(url,data=data,headers=headers)
- data :表單資料以bytes型別提交,不能是str
urllib.parse.urlencode
請求中有漢字的處理方法1~3
- 方法1:先urllib.parse.urlencode(dict字典) 轉換成了%+十六進位制,再去拼接。
import urllib.request
import urllib.parse
url = 'https://www.baidu.com/s?wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B'
# wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B
url2 = 'https://www.baidu.com/s?wd=海賊王'
# 3個%是一個漢字
# 如果我請求的url地址中出現了中文字樣,我們的思路就是把中文轉換成%+十六進位制的樣式
# res = urllib.request.urlopen(url2) # 報錯
# 第一種方式 urllib.parse.urlencode(dict字典) 轉換成了%+十六進位制
r = {'wd': '海賊王'} # 字典格式
result = urllib.parse.urlencode(r)
print(result) # wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B
print(type(result)) # <class 'str'>
# 拼接:
url3 = 'https://www.baidu.com/s?' + result
print(url3) # https://www.baidu.com/s?wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B
urllib.parse.quote(str)
-
方法2: urllib.parse.quote(str)
import urllib.request import urllib.parse url = 'https://www.baidu.com/s?wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B' # %E6%B5%B7%E8%B4%BC%E7%8E%8B url2 = 'https://www.baidu.com/s?wd=海賊王' # 第二種方式 urllib.parse.quote(str) r = '海賊王' result = urllib.parse.quote(r) print(result) # %E6%B5%B7%E8%B4%BC%E7%8E%8B url4 = 'https://www.baidu.com/s?wd=' + result # 拼接: print(url4) # https://www.baidu.com/s?wd=%E6%B5%B7%E8%B4%BC%E7%8E%8B
url 裡面的資料包含有 %+十六進位制 parse.unquote()
-
下載王者榮耀桌布
-
反爬的小細節
如果以後遇到了 url 裡面的資料包含有 %+十六進位制 這樣的url我們是無法進行一個正常的請求,解決辦法 通過 parse.unquote() 來進行處理
from urllib import parse from urllib import request img = parse.unquote('http%3A%2F%2Fshp%2Eqpic%2Ecn%2Fishow%2F2735012617%2F1611652313%5F84828260%5F14368%5FsProdImgNo%5F2%2Ejpg%2F200') print(img) # 轉換後的圖片地址, http://shp.qpic.cn/ishow/2735012617/1611652313_84828260_14368_sProdImgNo_2.jpg/200 request.urlretrieve(img, 'code3.jpg') # 圖片下載, img網址,檔名code3.jpg
練習1:在百度輸入您要搜尋的內容,例如:美女 結果儲存成一個html檔案
# 需求:在百度輸入您要搜尋的內容,例如:美女 結果儲存成一個html檔案 import urllib.request import urllib.parse headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/87.0.4280.141 Safari/537.36' } # 常規的格式:https://www.baidu.com/s?wd=%E5%A6%B9%E5%AD%90 key = input('請輸入您要搜尋的內容:') base_url = 'https://www.baidu.com/s?' wd = {'wd': key} result = urllib.parse.urlencode(wd) # 把中文轉換成%+十六進位制的樣式 url = base_url + result # 拼接url # print(url) # 構建請求物件 req = urllib.request.Request(url, headers=headers) # 獲取響應物件 res = urllib.request.urlopen(req) # 讀取響應的資料 html = res.read().decode('utf-8') # 儲存資料 with open('搜尋.html', 'w', encoding='utf-8') as file_obj: file_obj.write(html)
練習2:爬取貼吧中想要的主題
# 爬取貼吧中想要的主題 import urllib.request import urllib.parse # https://tieba.baidu.com/f?kw=%E5%AD%A6%E7%94%9F&pn=0 headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/' '87.0.4280.141 Safari/537.36' } # 貼吧的主題 name = input('請輸入您要爬取的貼吧主題:') # 爬取的起始頁和終止頁 begin = int(input('請輸入起始頁:')) end = int(input('請輸入終止頁:')) # 對name進行處理 kw = {'kw': name} result = urllib.parse.urlencode(kw) # 拼接目標url kw=%E5%AD%A6%E7%94%9F 是要動態的去替換的 pn值 (page - 1) * 50 # range()函式的特點 range(5) range(0,5) range(0,5,1) list(range(5)) 0 1 2 3 4 for i in range(begin, end+1): pn = (i - 1) * 50 base_url = 'https://tieba.baidu.com/f?' url = base_url + result + '&pn=' + str(pn) # 發起請求獲得響應 req = urllib.request.Request(url, headers=headers) res = urllib.request.urlopen(req) html = res.read().decode('utf-8') # 寫入檔案 filename = '第' + str(i) + '頁.html' with open(filename, 'w', encoding='utf-8') as f: print('正在爬取第%d頁' %i) f.write(html)
RUN: 請輸入您要爬取的貼吧主題:美女 請輸入起始頁:1 請輸入終止頁:3 正在爬取第1頁 正在爬取第2頁 正在爬取第3頁
練習3:以函式形式,爬取貼吧中想要的主題
import urllib.request import urllib.parse # 讀取頁面 def readPage(url): headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/' '87.0.4280.141 Safari/537.36' } req = urllib.request.Request(url, headers=headers) res = urllib.request.urlopen(req) html = res.read().decode('utf-8') return html # 寫入檔案 def writePage(filename, html): with open(filename, 'w', encoding='utf-8') as f: f.write(html) print('寫入成功') # 主函式 1 呼叫前2個函式 2 其它的邏輯放到main()函式中 def main(): name = input('請輸入您要爬取的貼吧主題:') begin = int(input('請輸入起始頁:')) end = int(input('請輸入終止頁:')) kw = {'kw': name} result = urllib.parse.urlencode(kw) for i in range(begin, end + 1): pn = (i - 1) * 50 base_url = 'https://tieba.baidu.com/f?' url = base_url + result + '&pn=' + str(pn) # 呼叫函式 html = readPage(url) filename = '第' + str(i) + '頁.html' writePage(filename, html) if __name__ == '__main__': main()
RUN: 請輸入您要爬取的貼吧主題:美女 請輸入起始頁:1 請輸入終止頁:4 寫入成功 寫入成功 寫入成功 寫入成功
End !
Best wishes for you!