• 當前位置:首頁 > IT技術 > 編程語言 > 正文

    Python系列之Urllib
    2022-04-19 11:07:29

    1.背景

    1.1 初識爬蟲

    網絡爬蟲,是一種按照一定規則,自動抓取互聯網信息的程序或者腳本,其本質是模擬瀏覽器打開網頁,獲取網頁中我們想要的數據。常用的百度、谷歌的搜索引擎也是一個爬蟲,把互聯網中的數據搜集組合起來便于用戶檢索。

    1.2 合法性

    網絡爬蟲領域當前還屬于拓荒階段, “ 允許哪些行為 ” 這種基本秩序還處于建設之中。如果抓取的數據屬于個人使用或科研范疇,基本不存在問題; 如果數據屬于商業盈利范疇,就要就事而論,可能違法,可能不違法。

    1.3 robots協議

    Robots協議(也稱為爬蟲協議、機器人協議等)的全稱是“網絡爬蟲排除標準”(Robots Exclusion Protocol),內容網站通過Robots協議告訴搜索引擎怎樣更高效的索引到結果頁并提供給用戶。它規定了網站里的哪些內容可以抓取,哪些不可以抓取,大部分網站都會有一個robots協議,一般存在網站的根目錄下,命名為robots.txt,以知乎為例,https://www.zhihu.com/robots.txt

    image-20210918100651103

    但robots協議終究是業內的一個約定,到底如何做還得看使用者。在使用爬蟲時,應稍微克制一下行為,而不是使勁的薅,看看12306都慘成啥樣了,被各種搶票軟件,各路爬蟲瘋狂輸出……

    2.要求

    2.1 當前開發環境

    • 操作系統:Window 10

    • python版本:3.8

    • 編輯器:pycharm

    • 庫管理:Anconda

    以上是我電腦的配置,python版本起碼3+;編輯器不限制,看自己喜歡;Anconda是真的好用,早用早享受

    2.2 編程基礎

    • 要有一定的前端知識,會HTML,CSS,JS的基礎用法

    • 懂得Python的基礎語法

    3.快速上手Urllib

    Urllib是python內置的一個http請求庫,不需要額外的安裝。只需要關注請求的鏈接,參數,提供了強大的解析功能

    Urllib庫有四個模塊:request,error, parse, robotparser

    1. request:發起請求(重要)

    2. error:處理錯誤

    3. parse:解析RUL或目錄等

    4. robotparser(不怎么用):解析網站的robot.txt

    3.1 request模塊

    方法介紹:

    1.請求方法
    urllib.request.urlopen(url, data=None, [timeout, ]*)
    url:地址,可以是字符串,也可以是一個Request對象
    data:請求參數
    timeout:設置超時

    一個簡單的get請求:

    """
    # 爬蟲就是模擬用戶,向服務器發起請求,服務器會返回對應數據
    # 數據抓包,使用chrome,盡量不要使用國產瀏覽器
    # F12打開界面,點擊network,刷新,會顯示網頁的請求,常見的請求有GET, POST, PUT, DELETE, HEAD, OPTIONS, TRACE,其中GET 和 POST 最常用
    # GET請求把請求參數都暴露在URL上
    # POST請求的參數放在request body,一般會對密碼進行加密
    # 請求頭:用來模擬一個真實用戶
    # 相應狀態碼:200表示成功
    """
    ?
    ?
    # 引入請求模塊
    import urllib.request
    # 發起請求,設置超時為1s
    response = urllib.request.urlopen('http://www.baidu.com', timeout = 1)
    # 使用read()讀取整個頁面內容,使用decode('utf-8')對獲取的內容進行編碼
    print(response.read().decode('utf-8'))
    print(response.status) # 狀態碼,判斷是否成功,200
    print(response.getheaders()) ??????# 響應頭 得到的一個元組組成的列表
    print(response.getheader('Server')) ??#得到特定的響應頭

    ?

    推薦一個測試網站,用于提交各種請求:http://httpbin.org/,該網站的更多的用法自行搜索

    一個簡單的post請求

    import urllib.parse
    import urllib.request
    # data需要的是字節流編碼格式的內容,此時請求方式為post
    data = bytes(urllib.parse.urlencode({"name": "WenAn"}), encoding= 'utf-8')
    response = urllib.request.urlopen('http://httpbin.org/post', data= data)
    print(response.read().decode('utf-8'))

    ?

    Request對象

    瀏覽器發起請求時都會有請求頭header,爬蟲想要爬取信息時,添加header,讓服務器以為你是瀏覽器,而不是一個爬蟲。urlopen無法添加其他參數,因此我們需要聲明一個request對象來添加header

    如何獲取Header:

    隨便打開一個網頁(以chrome為例),快捷鍵F12或者右鍵打開開發者頁面,點擊network,刷新頁面,再隨便點擊一個鏈接

    image-20210920154949003

    image-20210920155109952

    Request介紹

    urllib.request.Request(url, data=None, headers={}, method=None)
    headers: 定義請求頭
    method:默認為get,當傳入參數時為post

    例子:

    import urllib.request
    import urllib.parse
    ?
    url = 'http://httpbin.org/post'
    # 添加請求頭
    headers = {'user-agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36(KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36', 'Host':'httpbin.org'}
    dict = {
    ? ?'name':'WenAn'
    }
    data = bytes(urllib.parse.urlencode(dict), encoding = 'utf-8')
    request = urllib.request.Request(url, data=data, headers=headers, method='POST')
    response = urllib.request.urlopen(request)
    print(response.read().decode('utf-8'))

    3.2Error 模塊

    Error模塊下有三個異常類:

    • URLError

      • 處理程序在遇到問題時會引發此異常(或其派生的異常)

      • 只有一個reason屬性

    • HTTPError

      • 是URLError的一個子類,有更多的屬性,如code, reason,headers

      • 適用于處理特殊 HTTP 錯誤例如作為認證請求的時候。

    • ContentTooShortError

      • 此異常會在 urlretrieve() 函數檢測到已下載的數據量小于期待的數據量(由 Content-Length 頭給定)時被引發。 content 屬性中將存放已下載(可能被截斷)的數據。

    例子1.

    from urllib import request, error
    try:
    ? ?# 打開百度里面的a.html頁面,因為它根本不存在,所以會拋出異常
    ? ?response = request.urlopen('http://www.baidu.com/a.html')
    except error.URLError as e:
    ? ?print(e.reason) #Not Found

    例子2.

    # 一樣的例子,只不過把URLError換成了HTTPError
    from urllib import request, error
    try:
    ? ?response = request.urlopen('http://www.baidu.com/a.html')
    except error.HTTPError as e:
    ? ?print(e.reason)
    ? ?print(e.code)
    ? ?print(e.headers)
    ?
    # 輸出結果
    """
    Not Found
    ?
    404
    ?
    Content-Length: 204
    Connection: keep-alive
    Content-Type: text/html; charset=iso-8859-1
    Date: Sat, 18 Sep 2021 14:18:51 GMT
    Keep-Alive: timeout=4
    Proxy-Connection: keep-alive
    Server: Apache
    """

    3.3Parse 模塊

    parse模塊定義了url的標準接口,實現url的各種抽取,解析,合并,編碼,解碼

    urlencode()介紹---參數編碼

    它將字典構形式的參數序列化為url編碼后的字符串,在前面的request模塊有用到

    import urllib.parse
    dict = {
    ? ?'name':'WenAn',
    ? ?'age': 20
    }
    params = urllib.parse.urlencode(dict)
    print(params)
    # name=WenAn&age=20

    quote()介紹---中文RUL編解碼

    import urllib.parse
    params = '憨憨沒了心'
    base_url = 'https://www.baidu.com/s?wd='
    url = base_url + urllib.parse.quote(params)
    print(url)
    # https://www.baidu.com/s?wd=%E6%86%A8%E6%86%A8%E6%B2%A1%E4%BA%86%E5%BF%83

    # 使用unquote()對中文解碼
    url1 = 'https://www.baidu.com/s?wd=%E6%86%A8%E6%86%A8%E6%B2%A1%E4%BA%86%E5%BF%83'
    print(urllib.parse.unquote(url1))
    # https://www.baidu.com/s?wd=憨憨沒了心

    urlparse()介紹—-URL分段

    urllib.parse.urlparse(urlstring, scheme='', allow_fragments=True)
    urlstring:待解析的url
    scheme='':假如解析的url沒有協議,可以設置默認的協議,如果url有協議,設置此參數無效
    allow_fragments=True:是否忽略錨點、片斷標識符,如'#' ,默認為True表示不忽略,為False表示忽略

    例子1.

    from urllib.parse import urlparse
    a = urlparse("https://docs.python.org/zh-cn/3/library/urllib.parse.html")
    print(a)
    # 返回一個數組,是url的拼接部分,可以訪問具體的值
    # ParseResult(scheme='https', netloc='docs.python.org', path='/zh-cn/3/library/urllib.parse.html', params='', query='', fragment='')

    print(a.scheme)
    print(a.netloc)
    print(a.path)
    print(a.params)
    print(a.query)
    print(a.fragment)
    """
    scheme:表示協議
    netloc:域名
    path:路徑
    params:參數
    query:查詢條件,一般都是get請求的url
    fragment:錨點,用于直接定位頁面的下拉位置,跳轉到網頁的指定位置
    """

    urlunparse()介紹----URL構造

    import urllib.parse
    url_params = ('http', 'baidu.com', '/a', '', '', '')
    url = urllib.parse.urlunparse(url_params)
    print(url)

    #http://baidu.com/a

    urljoin()介紹----URL拼接

    # 給一個基礎url,給一個后綴url,進行拼接
    from urllib import parse
    base_url = 'http://www.cwi.nl/%7Eguido/Python.html'
    sub_url = 'FAQ.html'
    url = parse.urljoin(base_url, sub_url)
    print(url)
    # http://www.cwi.nl/%7Eguido/FAQ.html

    4.高級應用

    4.1 Opener

    opener是 urllib.request.OpenerDirector 的實例,如上文提到的urlopen便是一個已經構建好的特殊opener,但urlopen()僅提供了最基本的功能,如不支持代理,cookie等

    自定義Opener的流程

    • 使用相關的 Handler處理器來創建特定功能的處理器對象

    • 通過 urllib.request.build_opener()方法使用處理器對象,創建自定義opener對象

    • 使用自定義的opener對象,調用open()方法發送請求

    關于全局Opener

    如果要求程序里面的所有請求都使用自定義的opener,使用urllib.request.install_opener()

    import urllib.request
    # 創建handler
    http_handler = urllib.request.HTTPHandler()
    # 創建opener
    opener = urllib.request.build_opener(http_handler)
    # 創建Request對象
    request = urllib.request.Request('https://www.python.org/')

    # 局部opener,只能使用.open()來訪問
    # response = opener.open(request)


    # 全局opener,之后調用urlopen,都將使用這個自定義opener
    urllib.request.install_opener(opener)
    response = urllib.request.urlopen(request)

    print(response.read().decode('utf8'))

    ?

    ?

    4.2 代理設置

    代理原理

    正常流程:本機請求訪問一個網站,把請求發給Web服務器,Web服務器把相應數據傳回。

    使用代理:本機和服務器之間出現了第三方,本機向代理服務器發出請求,代理服務器向Web服務器發出請求,相應數據通過代理服務器轉發回到本機

    區別:Web服務器識別出的IP只是代理服務器的IP,而不是本機的IP,從而實現了IP偽裝


    ?

    使用代理IP,可以更方便的爬取數據。很多網站會在某個時間段內檢查某個IP的訪問次數,如果訪問次數過高出現異常,便會封禁該IP,禁止其訪問網站。使用代理便可以每隔一個時間段換一個代理,如果某個IP被禁了,換個IP便可繼續爬取數據。

    這里推薦幾個提供免費代理服務的網站:

    更多的IP自己去網上搜索,誰也不能保證這些免費ip能用到啥時候

    import urllib.request

    # 創建handler
    proxy_handler = urllib.request.ProxyHandler({
    'http': '218.78.22.146:443',
    'http': '223.100.166.3',
    'http': '113.254.178.224',
    'http': '115.29.170.58',
    'http': '117.94.222.233'
    })
    # 創建opener
    opener = urllib.request.build_opener(proxy_handler)
    header = {
    "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/93.0.4577.82 Safari/537.36"
    }
    request = urllib.request.Request('https://www.httpbin.org/get', headers=header)

    # 配置全局opener
    urllib.request.install_opener(opener)
    response = urllib.request.urlopen(request)
    print(response.read().decode('utf-8'))

    4.3 Cookie

    Cookie是網站為了識別用戶身份而存儲在用戶本地端的數據,該數據通常經過加密。

    Cookie 主要用于以下三個方面:

    • 會話狀態管理(如用戶登錄狀態、購物車、游戲分數或其它需要記錄的信息)

    • 個性化設置(如用戶自定義設置、主題等)

    • 瀏覽器行為跟蹤(如跟蹤分析用戶行為等)

    cookielib庫

    該模塊主要功能是提供可存儲cookie的對象。使用此模塊捕獲cookie并在后續連接請求時重新發送,還可以用來處理包含cookie數據的文件。

    這個模塊主要提供了這幾個對象,CookieJar,FileCookieJar,MozillaCookieJar,LWPCookieJar。

    • CookieJar:對象存儲在內存中

    • FileCookieJar,MozillaCookieJar,LWPCookieJar:存儲在文件中,生成對應格式的cookie文件,一般使用某兩種

    獲取Cookie

    import http.cookiejar
    import urllib.request
    # 創建cookie對象
    cookie = http.cookiejar.CookieJar()
    handler = urllib.request.HTTPCookieProcessor(cookie)
    opener = urllib.request.build_opener(handler)
    response = opener.open('http://www.baidu.com')
    # 在獲取response后cookie會被自動賦值
    for i in cookie:
    print(i.name+"="+i.value)

    保存Cookie到本地

    import http.cookiejar
    import urllib.request

    filename = 'cookie.txt'
    # cookie = http.cookiejar.MozillaCookieJar(filename)
    cookie = http.cookiejar.LWPCookieJar(filename)
    handler = urllib.request.HTTPCookieProcessor(cookie)
    opener = urllib.request.build_opener(handler)
    # 獲取response后cookie會被自動賦值
    response = opener.open('http://www.baidu.com')
    # 保存cookie.txt文件
    cookie.save(ignore_discard=True, ignore_expires=True)

    讀取Cookie文件

    import urllib.request
    import http.cookiejar

    # cookie對象要和生產cookie文件的對象保持一致,是LWP還是Mozilla
    # cookie = http.cookiejar.MozillaCookieJar
    cookie = http.cookiejar.LWPCookieJar()
    cookie.load('cookie.txt', ignore_expires=True, ignore_discard=True)
    handler = urllib.request.HTTPCookieProcessor(cookie)
    opener = urllib.request.build_opener(handler)
    response = opener.open("http://www.baidu.com")
    print(response.read().decode('utf-8'))

    以上便是urllib的常用內容

    附上urllib參考文檔:https://docs.python.org/zh-cn/3/library/urllib.html

    個人博客:wenancoding.com

    本文摘自 :https://www.cnblogs.com/

    開通會員,享受整站包年服務
    国产呦精品一区二区三区网站|久久www免费人咸|精品无码人妻一区二区|久99久热只有精品国产15|中文字幕亚洲无线码