Python 爬蟲十六式 - 第六式:JQuery的假兄弟-pyquery

PyQuery:一個相似jquery的python庫

學習一時爽,一直學習一直爽css

  Hello,你們好,我是 Connor,一個個從無到有的技術小白。上一次咱們說到了 BeautifulSoup 美味的湯,BeautifulSoup 很適合剛剛接觸爬蟲的新手使用。雖然 BeautifulSoup 好用,可是也有它的侷限性。今天咱們來說一講 PyQuery,讓咱們以 JQuery的方式來快速提取咱們想要的內容。廢話很少說,讓咱們開始吧。html

1. PyQuery 的簡介

  pyquery 容許您在 xml 文檔上進行 jquery 查詢。API 儘量與 jquery 相似。pyquery 使用lxml 進行快速 xml 和 html 操做。固然這並不能用於生成 JavaScript 代碼或者與 JavaScript 進行代碼交互。因此,若是你想在 Python 上運行 JavaScript 代碼,那麼 pyquery 不是一個好的選擇。python


2. PyQuery 的簡單使用

  pyquery仍是很是容易上手的。如今,咱們如下面的這段 xml 代碼爲例,進行演示:jquery

html = """
<html>
    <head>
        <title>個人示例</title>
    </head>	
    <body>
        <div class="book">
       		<a class="book_title" id="book" href="abc.html">百鍊成鋼</a>
        	<p class="book_author" id="author" >王者之勢</p>
         	<p class="time" id="time">2019/01/13</p>
         </div>
    </body>
</html>
"""
複製代碼

  首先,咱們先將這段文檔變成 PyQuery 對象,pyquery的操做基本都是經過PyQuery 對象來進行的。你能夠這樣作:工具

In [2]: from pyquery import PyQuery

In [3]: doc = PyQuery(html)

In [4]: type(doc)
Out[4]: pyquery.pyquery.PyQuery
複製代碼

  使用 CSS 選擇器能夠快速地對節點進行選擇,CSS 選擇器是一種快速高效的選擇方式,它能夠在頁面中實現 一對一,一對多,多對一的多種控制,使用 CSS 選擇器無疑是一種快速便捷的提取方式,你只須要像JQuery同樣進行選擇能夠了:post

In [10]: print(doc(".book"))
<div class="book">
               <a class="book_title" id="book" href="abc.html">百鍊成鋼</a>
            <p class="book_author" id="author">王者之勢</p>
             <p class="time" id="time">2019/01/13</p>
         </div>
複製代碼

  能夠看到,只要像JQuery同樣進行選擇就能夠垂手可得的將咱們想要的東西就選擇出來了,並且不須要像Xpath同樣去找它的路徑學習


3. 使用 PyQuery 選擇單一節點

3.1 經過節點名稱進行選擇

  在 pyquery 中,你能夠經過節點名來對節點進行簡單的選擇,當某個節點在文檔中只出現一次的時候,這種方式是最簡單的,你無需考慮其餘因素的影響,就像這樣:url

In [11]: c = doc("a")

In [12]: print(c)
<a class="book_title" id="book" href="abc.html">百鍊成鋼</a>
複製代碼

  能夠看到,很輕鬆的就將咱們想要的節點選取出來了,可是不少時候某個節點有不少個,不多有單獨出現一次的狀況,這個時候咱們就須要經過別的方法來進行選擇了spa


3.2 經過屬性進行選擇

  你也能夠經過節點的屬性來選擇一個節點,當某個節點的某個屬性在文檔中是惟一的時候,這是最方便的作法。在上面的例子文檔中,有不少的節點都擁有惟一的屬性,因此,您能夠這樣作:code

In [13]: c = doc("#author")

In [14]: print(c)
<p class="book_author" id="author">王者之勢</p>
複製代碼

  咱們能夠看到,經過單獨的屬性是很容易選取出咱們想要的的內容的,這只是 id 屬性, 咱們也可使用 class 屬性來進行快速選擇,其寫法也和 JQuery 相同,這裏再也不演示。 可是當咱們遇到其餘的屬性的時候該怎麼辦?咱們能夠經過指明屬性的名稱和值來進行選擇, 就像這樣:

In [15]: c = doc('[href="abc.html"]')

In [16]: print(c)
<a class="book_title" id="book" href="abc.html">百鍊成鋼</a>
複製代碼

  就像這樣,咱們只是經過一個href屬性就選擇出了咱們想要的節點。固然,有些時候某個屬性也是衆多節點一塊兒使用的,這個時候你能夠結合咱們講的第一種方法,經過節點名稱來進行選擇,將節點與屬性進行結合,來進行選擇:

In [17]: c = doc('p[id="author"]')

In [18]: print(c)
<p class="book_author" id="author">王者之勢</p>
複製代碼

  經過上面的方法,仍是基本上很容易知足咱們的需求了,可是有些時候,當咱們有更高的需求的時候,咱們須要用到css的僞類選擇器,下面,咱們將介紹僞類選擇器:


3.3 經過僞類來進行選擇

  當某些節點擁有多個,或者與其它節點有太多重複屬性的時候,咱們就須要用到僞類選擇器,僞類選擇器出了可使用css自帶的僞類選擇器以外,pyquery 還提供了相似 JQuery 同樣的非標準僞類選擇器,這些僞類選擇器能夠幫助咱們快速的進行選擇:

In [19]: c = doc("p:first")

In [20]: print(c)
<p class="book_author" id="author">王者之勢</p>
複製代碼

  僞類選擇器支持幾乎全部的 CSS 標準僞類以及 JQuery 的非標準僞類:

CSS 標準僞類

選擇器 示例 示例說明
:checked input:checked 選擇全部選中的表單元素
:disabled input:disabled 選擇全部禁用的表單元素
:empty p:empty 選擇全部沒有子元素的p元素
:enabled input:enabled 選擇全部啓用的表單元素
:first-of-type p:first-of-type 選擇每一個父元素是p元素的第一個p子元素
:last-child p:last-child 選擇全部p元素的最後一個子元素
:last-of-type p:last-of-type 選擇每一個p元素是其母元素的最後一個p元素
:not(selector) :not(p) 選擇全部p之外的元素
:nth-child(n) p:nth-child(2) 選擇全部 p 元素的父元素的第二個子元素
:nth-last-child(n) p:nth-last-child(2) 選擇全部p元素倒數的第二個子元素
:nth-last-of-type(n) p:nth-last-of-type(2) 選擇全部p元素倒數的第二個爲p的子元素
:nth-of-type(n) p:nth-of-type(2) 選擇全部p元素第二個爲p的子元素
:only-of-type p:only-of-type 選擇全部僅有一個子元素爲p的元素
:only-child p:only-child 選擇全部僅有一個子元素的p元素
:root root 選擇文檔的根元素
:target #news:target 選擇當前活動#news元素(點擊URL包含錨的名字)
:link a:link 選擇全部未訪問連接
:visited a:visited 選擇全部訪問過的連接
:active a:active 選擇正在活動連接
:hover a:hover 把鼠標放在連接上的狀態
:focus input:focus 選擇元素輸入後具備焦點
:first-child p:first-child 選擇器匹配屬於任意元素的第一個子元素的

元素

:lang(language) p:lang(it)

元素的lang屬性選擇一個開始值

上表部分取自--菜鳥教程

JQuery 非標準僞類

選擇器 示例 示例說明
:first p:first 選擇第一個

元素

:last p:last 選擇最後一個

元素

:odd p:odd 選擇全部

元素中索引爲奇數的元素

:even p:even 選擇全部

元素中索引爲偶數的元素

:eq(index) p:eq(0) 選擇全部

元素中索引爲0的元素

:lt(index) p:lt(3) 選擇全部

元素中索引小於3的元素

:gt(index) p:gt(2) 選擇全部

元素中索引大於2的元素

:header :header 選擇全部的H1-H6的元素
:hidden p:hidden 選取全部

元素中包含有隱藏屬性的元素

:contains(text) p:contains(王者) 選擇全部

元素中內容包含有‘王者’的元素

:has(selector) div:has(p) 選擇全部帶有

元素的

元素
:input :input 選擇全部的<input>元素
:(type)type指input的類型 :submit 選擇全部type爲submit的<input>元素
input的類型包括
button submit reset text checkbox image hidden file

  經過上列的僞類你能夠更快更方便的對節點進行選擇,固然 pyquery 並不僅有這些功能,它還有更多的功能:


4. 使用 PyQuery 選擇多個節點

  當咱們使用 PyQuery 進行選擇的時候,不免會遇到某個節點都是使用同一種方式來進行封裝的,他們的描述方式都是相同的,亦或者咱們想要批量的選取某個東西的時候,他們的封裝形式是相同的,這樣很難進行單一的選取。或者說單一選取太麻煩了。此時咱們就須要考慮選擇後的遍歷問題了。由於一個東西若是不能遍歷,對咱們取值有很大的困難,PyQuery 天然也是能夠進行遍歷的,可能你會這樣作:

In [21]: c = doc('p')

In [22]: for item in c:
    ...:     print(item)
    ...:
<Element p at 0x21395a4b448>
<Element p at 0x21395a12888>
複製代碼

  你會發現,經過這種方式打印出來的只是一個內存地址,並無實際的東西。當咱們須要遍歷 PyQuery 選擇出來的東西的時候,咱們須要使用 items() 方法。經過這種方法能夠將選擇的多個內容區分開來:

In [23]: c = doc('p').items()

In [24]: for item in c:
    ...:     print(item)
    ...:
<p class="book_author" id="author">王者之勢</p>

<p class="time" id="time">2019/01/13</p>

複製代碼

  經過 items() 方法就能夠打印出每一項的內容了。


5. PyQuery 的其它使用方法

5.1 text() 方法

  當咱們獲取到指定的節點的時候,有時候咱們須要獲取他的文本內容,這個時候就須要的使用 text() 方法了,這個方法能夠取出當前 PyQuery 對象中的文本內容,例如:

In [25]: c = doc('#author')

In [26]: print(c.text())
王者之勢
複製代碼

5.2 attr() 方法

  有些時候咱們不僅是須要提取文本內容,有時候咱們也須要提取節點中的屬性內容,例如 href,這個時候咱們就須要使用到 attr() 方法,經過該方法來進行屬性內容的提取:

In [13]: tags = doc('a').attr('href')
    ...: print(tags)
abc.html
複製代碼

5.3 html() 方法

  若是你所選擇的當前節點還有子節點,那麼你能夠經過 html() 方法將當前節點下的全部子元素選擇出來,固然,你也能夠對它進行更改,改變當前節點下的內容:

In [27]: c = doc('div')

In [28]: print(c.html())

               <a class="book_title" id="book" href="abc.html">百鍊成鋼</a>
            <p class="book_author" id="author">王者之勢</p>
             <p class="time" id="time">2019/01/13</p>
複製代碼

  或者你能夠經過向html()方法中給參數的方法來改變當前節點下的子節點內容:

In [29]: c = doc('div')

In [30]: print(c.html('abcdefghijklmnopqrstuvwxyz'))
<div class="book">abcdefghijklmnopqrstuvwxyz</div>
複製代碼

5.4 find() 方法

  在找到某一節點的內容以後,你還能夠經過 find() 方法來在當前基礎上進行二次查找甚至是屢次查找,find() 的使用方法和正常的查找方式是相同的:

In [31]: c = doc('div').find('#author')

In [32]: print(c)
<p class="book_author" id="author">王者之勢</p>
複製代碼

5.5 children() 方法

  經過 children() 方法能夠快速的選取出某個節點下的全部子節點,該方法一樣適用於屢次查找,該方法的使用方法和 find() 方法相似:

In [33]: c = doc('div').children('p')

In [34]: print(c)
<p class="book_author" id="author">王者之勢</p>
             <p class="time" id="time">2019/01/13</p>
複製代碼

  當 children() 方法不給參數的時候會默認查找出全部的子節點,請按需使用。


5.6 has_class() 方法

  有時候咱們尋找某一節點須要用到 class 但每次都單獨去取該屬性再進行判斷有些太麻煩了,PyQuery 爲咱們提供了 has_class() 方法,該方法能夠快速的對節點是否擁有指定 class 屬性進行判斷:

In [35]: tags = doc.find('a').has_class('book_title')
    ...: print(tags)
True
複製代碼

5.7 is_() 方法

  有的時候咱們並不能只驗證 class 屬性,還有其餘的屬性須要咱們進行驗證,或者使用其它屬性來進行驗證會更加的方便,這個時候咱們就須要使用 is_() 方法。這個方法能夠匹配節點中的任意屬性:

In [12]: tags = doc('p').eq(0).is_('[id="author"]')
    ...: print(tags)
True
複製代碼

5.9 對上述方法的總結

  總的來講,我以爲 pyquery 其實並無像想像中的那麼好用,使用起來手感和 Xpath 差不了多少,甚至我我的認爲 Xpaht 更加好用一些,其實若是你仔細地看 pyquery 的源碼你就會發現,其實它也使用了 Xpaht ,比較諷刺吧,可是 pyquery 確實是在 Xpath 的基礎上又作出了很大的改進,好比 僞類選擇器 這在必定狀況下確實是要比 Xpath 要好用的多,因此其實解析並無什麼難易,看你是否找對了適合的工具,就比如是否找到了適合腳的鞋子。找對了工具,事半功倍,找錯了工具,事倍功半。但願你可以靈活運用。


下期預告

  Xpath 也講了,BeautifulSoup也講了,甚至PyQuery你也講了,怎麼就是不講 re 正則呢??彆着急,重頭戲老是在最後出場,下一次咱們就來說述,如何用 re 正則來獲取咱們想要的內容。敬請期待下期-- Python爬蟲十六式 - 第七式:正則的藝術

  好了,這就是今天的內容了,不知道你今天又學會了多少內容。我是 Connor,一個從無到有的技術小白,願你能在前進的道路上與我一同前行!

學習一時爽,一直學習一直爽!


系列文章鏈接:

Python 爬蟲十六式 - 第一式:HTTP協議 >>>
Python 爬蟲十六式 - 第二式:urllib 與 urllib3 >>>
Python 爬蟲十六式 - 第三式:Requests的用法 >>>
Python 爬蟲十六式 - 第四式: 使用Xpath提取網頁內容 >>>
Python 爬蟲十六式 - 第五式:BeautifulSoup,美味的湯 >>>
Python 爬蟲十六式 - 第七式:正則的藝術 >>>
Python 爬蟲十六式 - 第八式:實例解析-全書網 >>>

相關文章
相關標籤/搜索