1. 程式人生 > 其它 >一木.溪橋學爬蟲-03:請求模組urllib、 urllib.request、urllib.parse.urlencode、urllib.parse.quote(str)、.unquote()

一木.溪橋學爬蟲-03:請求模組urllib、 urllib.request、urllib.parse.urlencode、urllib.parse.quote(str)、.unquote()

技術標籤:Python 爬蟲python

一木.溪橋 在Logic Education跟Jerry學爬蟲

07期:Python 爬蟲
一木.溪橋學爬蟲-03:請求模組urllib、 urllib.request、urllib.parse.urlencode、urllib.parse.quote(str)、parse.unquote()
日期:2021年1月26日

學習目標:

  • 請求模組urllib

  • urllib.request

  • urllib.parse.urlencode

  • urllib.parse.quote(str)

  • parse.unquote()


學習內容:

爬蟲請求模組

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!