python爬蟲requests&BeautifulSoup

requests模塊介紹

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

對於requests模塊,使用很簡單,通常咱們會用到兩個函數:python

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

以上兩個函數分別對應http協議中的"GET"方法與"POST"方法,除了這二者,還有如"PUT"、"DELETE"等方法,在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,返回Responsejson

requests.Request

咱們在使用requests時通常不會直接建立Request對象,因此這裏咱們大體瞭解一下便可:api

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。cookie

requests.Response

咱們以前的requests.get、requests.post或是requests.request函數的返回對象就是一個requests.Response實例。對於Response類,咱們主要介紹幾個經常使用屬性與方法:session

  • 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)等方法,以後能夠慢慢了解。

相關文章
相關標籤/搜索