1. 程式人生 > 實用技巧 >帶你瞭解python爬蟲requests模組&BeautifulSoup使用方式!

帶你瞭解python爬蟲requests模組&BeautifulSoup使用方式!

requests模組介紹

相對於python自帶的urllib模組,requests模組提供了相對更高層的api來進行網頁訪問的工作。

對於requests模組,使用很簡單,一般我們會用到兩個函式:

  • requests.get(url,params=None,**kwargs) 這裡的params是我們要傳入的query,它的格式是dict。
  • requests.post(url,data=None,**kwargs) 這裡的data就是我們要提交的表單data,也是直接傳入dict就好。

以上兩個函式分別對應http協議中的"GET"方法與"POST"方法,而除了這兩者,還有如"PUT"、"DELETE"、"HEAD"等方法,在requests模組中有一個統一的函式來發起不同“方法”的http請求報文:

  • requests.request(method,url,**kwargs) 可以看到該函式的第一個引數method的取值就是"GET"、"POST"等。
  • 該方法與上文提到的兩個方法,返回值都是requests.Response物件,後面我們會對該物件與requests.Request物件進行介紹
  • 較常用的關鍵字引數:params,data,headers,proxies,stream等。
  • 其實上文所介紹的兩個函式get和post,或是對應其他方法的函式,它們的實現就是使用request.requests函式的:
def get(url, params=None, **kwargs):
         kwargs.setdefault('allow_redirects', True)
         #這裡可見request.get的實質
         return request('get', url, params=params, **kwargs)

這裡來詳細介紹一下headers,proxies和stream關鍵字引數的用途:

  • headers引數就是http請求報文的頭部,它的格式是一個dict,其中最為常用的headers元素就是User-Agent,模仿瀏覽器訪問網頁。
  • proxies引數就是代理,它的格式也是一個dict,每一個鍵值對是這樣的形式:"協議":"ip:port"。
  • stream引數是相對前兩者較陌生的一個引數,該引數預設為False,意味著我們會一下子把網頁內容都下載,但如果主動設定為True的話,則不會立刻下載網頁內容,而是等到使用requests.Response的iter_content才會迭代地把資料下載並讀進記憶體中。

requests.Request&requests.Response

這兩個物件詳細對爬蟲有過了解的朋友們都很熟悉了,它們是在爬蟲邏輯中很關鍵的兩個物件,簡單來說:發出Request,返回Response

requests.Request

我們在使用requests時一般不會直接建立Request物件,所以這裡我們大致瞭解一下即可:

requests.Request(method=None, url=None, headers=None, data=None, params=None) 我們列出Request類構造時所需的一些常用引數,並且前文我們提到requests.get等函式的實質是requests.request函式,那麼其實研究該函式的原始碼:

def request(method, url, **kwargs):
    with sessions.Session() as session:
        #可以看到在request函式內呼叫了session.request方法
        return session.request(method=method, url=url, **kwargs)
        

#這個是session.request方法的定義
def request(self, method, url,
        params=None, data=None, headers=None, cookies=None, files=None,
        auth=None, timeout=None, allow_redirects=True, proxies=None,
        hooks=None, stream=None, verify=None, cert=None, json=None):
    
    #可以看到這裡其實使用傳入引數
    #建立了一個requests.Request例項
    req = Request(
        method=method.upper(),
        url=url,
        headers=headers,
        files=files,
        data=data or {},
        json=json,
        params=params or {},
        auth=auth,
        cookies=cookies,
        hooks=hooks,
    )
    #進一步處理,得到對應的PreparedRequest物件
    prep = self.prepare_request(req)

    proxies = proxies or {}

    settings = self.merge_environment_settings(
        prep.url, proxies, stream, verify, cert
    )

    # Send the request.
    send_kwargs = {
        'timeout': timeout,
        'allow_redirects': allow_redirects,
    }
    send_kwargs.update(settings)
    #這裡是真正的send Request,並返回一個Response物件
    resp = self.send(prep, **send_kwargs)
    return resp

由以上程式碼可知,其實requests.request方法的實質就是建立一個Request例項,在對其進行一定預處理後將其send,然後得到Response。

requests.Response

我們之前的requests.get、requests.post或是requests.request函式的返回物件就是一個requests.Response例項。對於Response類,我們主要介紹幾個常用屬性與方法:

  • Response.content 以bytes的形式得到返回Response的內容,其實也就是未解碼的html檔案
  • Response.text 文字形式的Response內容,也就是解碼了的html檔案,且如Response.encoding屬性為None的話,那麼會以chardet去猜測bytes內容的編碼方式。當然我們也可以在access這個屬性前人為指定一種編碼方式。
  • Response.encoding 指定以何種方式來解碼,Response內容的編碼完全基於HTTP報頭,遵循RFC2616檔案。
  • Response.url 即Response的url
  • Response.status_code 相應的狀態碼,如成功的話該值就是200
  • Response.request 得到對應於這個Response的Request物件,其實是(PreparedRequest),通過這個request物件我們可以得到當時訪問時的url、method、headers等屬性。
  • Response.iter_content(chunk_size=1),該函式返回一個generator,其中的chunk_size決定我們每次下載並讀進記憶體中多少個位元組,一般使用方法為for item in Response.iter_content(256)這樣的for迴圈遍歷即可。

BeautifulSoup

BeautifulSoup是一個可以從HTML或XML檔案中提取資料的Python庫,通常我們使用requests得到html檔案(Response.text),然後我們再使用BeautifulSoup來處理。從而提取到我們需要的資訊。

如何使用BeautifulSoup

from bs4 import BeautifulSoup
#其中html是返回的網頁文字,也就是response.text
#而lxml是BeautifulSoup使用的文件解析器,需要我們
#已經預先pip install好lxml這個模組,或者我們也可
#使用python自帶的html.parser,不過它的速度較慢些
#而soup就是一個BeautifulSoup物件,它承載了一個
#由html文件內部各個元素所形成的樹形結構。
soup=BeautifulSoup(html,"lxml")
#以下就是幾個最簡單基本的使用
#直接以屬性引用的方式得到html文件中的第一個a標籤
print(soup.a)
#進一步得到html文件中第一個a標籤的中的字串部分(如果存在的話)
print(soup.a.string)
#拿到html文件中第一個a標籤的href屬性的值
print(soup.a["href"])

以上大致介紹了BeautifulSoup的簡單實用,接下來我們進行更詳細地分析:

BeautifulSoup將HTML文件轉換成一個複雜的樹形結構,該樹形結構中的每個節點都是Python物件,所有物件可分為4種:Tag、NavigableString、BeautifulSoup、Comment。

  • Tag物件對應的就是html文件中的標籤,它有很多屬性與方法,這裡先介紹它最重要的兩個屬性:1.tag.name返回的就是該tag標籤的名字(比如tag對應a標籤,那麼tag.name返回的就是"a")。2.tag.attrs以字典的形式返回該標籤所有的屬性,如{"herf":"www.baidu.com"}。而我們想拿到屬性值就可以用tag.attrs["href"],不過上文也看到了,這裡其實可以直接簡寫為tag["href"]。
  • NavigableString物件它其實就是我們使用soup.a.string時真正返回的物件,它是對python自帶的string物件進行了一個包裝,我們可以就把它當作string使用,不需要在意其它。
  • BeautifulSoup物件它對應我們文件的全部內容,也就是上文的soup物件,大部分時間我們可以把它當作tag物件一樣來使用方法,不過它沒有attrs屬性,並且它的name屬性的值只為:["document"]。
  • Comment物件它對應html文件中的註釋標籤:<!-- 此處寫註釋 -->,該標籤很特別的是它不會被瀏覽器顯示,只是一個對程式設計師註釋的作用。該物件在實際應用中很少使用,這裡不作更進一步的介紹。

接下來我們要來對tag物件以及BeautifulSoup物件在使用method上進行更進一步的介紹:

而所謂的method使用,我們著眼的就是在得到的BeautifulSoup物件的樹形結構中對所需要的資訊進行搜尋的工作。

這樣的搜尋工作根據對節點本身資訊節點之間在樹形結構中的關係的應用不同而分為兩種

第一種,由節點本身資訊對節點進行搜尋:

所謂tag.a其實就是tag.find("a"),該方法的具體函式頭如下
find(name,attrs,recursive,string,**kwargs)
name就是標籤名,它的值是一個“過濾器”。
attrs就是該name對應標籤的屬性,同樣值也是一個“過濾器”。
recursive是一個bool值,預設為True。它的意思是搜尋當前tag的所有子孫節點,如果為False,則只搜尋當前tag的直接子節點
string就是該name對應的string值,也是一個“過濾器”。
**kwargs一般使用不用理會。

當然上面的tag.a或是tag.find("a")都只能得到tag下的第一個a標籤,
這太侷限了,如果我們想要的是後面的第三個a標籤呢?於是就有了
tag.find_all("a")方法,返回一個列表,來得到所有的a標籤,簡寫為tag("a")。
find_all(name,attrs,recursive,string,**kwargs)
引數的意義和find函式一樣

下面我們來講解一下這個所謂的“過濾器”到底是什麼東西
具體的程式碼實現有點繁瑣,總之我們可以把它理解為一種
物件,我們允許這個物件有多種值。
(1)字串值 最簡單的就是傳入字串值,如之前的tag.a
(2)正則表示式值 即re.compile(r"\d+")這樣的形式
(3)列表值 如name=["a","div"],則find只會返回其中的後者,
find_all會返回一個列表,包含tag下的所有a和div標籤。
(4)True 意思不做過濾,對於find是返回tag下符合要求的標籤的第一個,對於find_all是返回所有。比如name=True,那麼就不對name
過濾,對其他attrs或string繼續篩選過濾。

第二種,根據節點所在樹形結構中的關係對其它節點進行搜尋:

直接子節點:
tag.childern和tag.contents是tag物件的兩個屬性,注意不是對應標籤的屬性!!!它們返回當前tag節點在樹形結構中的直接子節點。
tag.childern返回一個生成器
tag.contents返回一個列表

子孫節點:
tag.descendants返回一個生成器,對它進行遍歷可以得到當前tag節點的所有子孫節點的迴圈遍歷結果。

直接父節點:
tag.parent獲取當前tag的直接父節點

所以父節點:
tag.parents返回一個生成器,可以獲取當前tag的所有父輩節點

next的兄弟節點:
tag.next_sibling和tag.next_siblings,返回值型別不用贅述。

previous的兄弟節點:
tag.previous_sibling和tag.previous_siblings,同樣返回型別不用贅述。

以上大概就是BeautifulSoup在搜尋資訊時所需的知識,其它如兩種方式結合的tag.find_parent(name,attrs,recursive,string,**kwargs)等方法,之後可以慢慢了解。

想要原始碼或者更多內容點選這裡即可獲取

此文轉載文,著作權歸作者所有,如有侵權聯絡小編刪除!

原文地址:https://www.tuicool.com/articles/uAbyimr