您當前的位置:首頁 > 收藏

Python3中PyQuery的使用方法

作者:由 Python程式設計師 發表于 收藏時間:2017-09-21

PyQuery的使用

在上一節我們介紹了BeautifulSoup的使用,它是一個非常強大的網頁解析庫,可有沒有覺得它的一些方法使用有點不適應?有沒有覺得它的CSS選擇器功能沒有那麼強大?

如果你對WEB有所涉及,如果你比較喜歡用CSS選擇器,如果你對jQuery有所瞭解,那麼這裡有一個更適合你的解析庫——PyQuery。

接下來我們就來感受一下PyQuery的強大之處。

初始化

像BeautifulSoup一樣,PyQuery初始化的時候也需要傳入HTML資料來源來初始化一個操作物件,它的初始化方式有多種,比如直接傳入字串,傳入URL,傳檔名。下面我們來詳細介紹一下。

字串初始化

html = ‘’‘

’‘’

from pyquery import PyQuery as pq

doc = pq(html)

print(doc(‘li’))

執行結果:

  • first item
  • second item
  • third item
  • fourth item
  • fifth item
  • 在這裡我們首先引入了PyQuery這個物件,取別名為pq,然後聲明瞭一個長HTML字串,當作引數傳遞給PyQuery,這樣就成功完成了初始化,然後接下來將初始化的物件傳入CSS選擇器,在這個例項中我們傳入li節點,這樣就可以選擇所有的li節點,列印輸出可以看到所有的li節點的HTML文字。

    URL初始化

    初始化的引數不僅可以以字串的形式傳遞,還可以傳入網頁的URL,在這裡只需要指定引數為url即可。

    from pyquery import PyQuery as pq

    doc = pq(url=‘http://cuiqingcai。com’)

    print(doc(‘title’))

    執行結果:

    靜覓丨崔慶才的個人部落格

    這樣的話PyQuery會首先請求這個URL,然後用得到的HTML內容完成初始化,其實就相當於我們用網頁的原始碼以字串的形式傳遞給PyQuery來初始化。

    它與下面的功能是相同的:

    from pyquery import PyQuery as pq

    import requests

    doc = pq(requests。get(‘http://cuiqingcai。com’)。text)

    print(doc(‘title’))

    檔案初始化

    當然除了傳遞一個URL,還可以傳遞本地的檔名,引數指定為filename即可。

    from pyquery import PyQuery as pq

    doc = pq(filename=‘demo。html’)

    print(doc(‘li’))

    當然在這裡需要有一個本地HTML檔案demo。html,內容是待解析的HTML字串。這樣它會首先讀取本地的檔案內容,然後用檔案內容以字串的形式傳遞給PyQuery來初始化。

    以上三種初始化方式均可,當然最常用的初始化方式還是以字串形式傳遞。

    基本CSS選擇器

    我們首先用一個例項來感受一下PyQuery的CSS選擇器的用法。

    html = ‘’‘

    ’‘’

    from pyquery import PyQuery as pq

    doc = pq(html)

    print(doc(‘#container 。list li’))

    print(type(doc(‘#container 。list li’)))

    執行結果:

  • first item
  • second item
  • third item
  • fourth item
  • fifth item
  • 在這裡我們初始化PyQuery物件之後,傳入了一個CSS選擇器,#container 。list li,意思是選取id為container的節點內部的class為list的節點內部的所有li節點。然後列印輸出,可以看到成功獲取到了符合條件的節點。

    然後我們將它的型別列印輸出,可以看到它的型別依然是PyQuery型別。

    查詢節點

    下面我們介紹一些常用的查詢函式,這些函式和jQuery中的函式用法也完全相同。

    子節點

    查詢子節點需要用到find()方法,傳入的引數是CSS選擇器,我們還是以上面的HTML為例。

    from pyquery import PyQuery as pq

    doc = pq(html)

    items = doc(‘。list’)

    print(type(items))

    print(items)

    lis = items。find(‘li’)

    print(type(lis))

    print(lis)

    執行結果:

  • first item
  • second item
  • third item
  • fourth item
  • fifth item
  • 首先我們選取了class為list的節點,然後我們呼叫了find()方法,傳入了CSS選擇器,選取其內部的li節點,最後都列印輸出即可觀察到對應的查詢結果,可以發現find()方法會將符合條件的所有節點選擇出來,結果的型別是PyQuery型別。

    其實find()的查詢範圍是節點的所有子孫節點,而如果我們只想查詢子節點,那可以用children()方法。

    lis = items。children()

    print(type(lis))

    print(lis)

    執行結果:

  • first item
  • second item
  • third item
  • fourth item
  • fifth item
  • 如果要篩選所有子節點中符合條件的節點,比如我們想篩選出子節點中class為active的節點,可以向children()方法傳入CSS選擇器。active。

    lis = items。children(‘。active’)

    print(lis)

    執行結果:

  • third item
  • fourth item
  • 可以看到輸出的結果已經做了篩選,留下了class為active的節點。

    父節點

    我們可以用parent()方法來獲取某個節點的父節點,我們用一個例項來感受一下:

    html = ‘’‘

    ’‘’

    from pyquery import PyQuery as pq

    doc = pq(html)

    items = doc(‘。list’)

    container = items。parent()

    print(type(container))

    print(container)

    執行結果:

    在這裡我們首先用。list選取了class為list的節點,然後呼叫了parent()方法,得到其父節點,型別依然是PyQuery型別。

    這裡的父節點是該節點的直接父節點,也就是說,它不會再去查詢父節點的父節點,即祖先節點。

    但是如果我們想獲取某個祖先節點怎麼辦呢?可以用parents()方法。

    from pyquery import PyQuery as pq

    doc = pq(html)

    items = doc(‘。list’)

    parents = items。parents()

    print(type(parents))

    print(parents)

    執行結果:

    在這裡我們呼叫了parents()方法,可以看到輸出結果有兩個,一個是class為wrap的節點,一個是id為container的節點,也就是說,parents()方法會返回所有的祖先節點。

    如果我們想要篩選某個祖先節點的話可以向parents()方法傳入CSS選擇器,這樣就會返回祖先節點中符合CSS選擇器的節點。

    parent = items。parents(‘。wrap’)

    print(parent)

    執行結果:

    可以看到輸出結果就少了一個節點,只保留了class為wrap的節點。

    兄弟節點

    在上面我們說明了子節點和父節點的用法,還有一種節點那就是兄弟節點,如果要獲取兄弟節點可以使用siblings()方法。我們還是以上面的HTML程式碼為例來感受一下:

    from pyquery import PyQuery as pq

    doc = pq(html)

    li = doc(‘。list 。item-0。active’)

    print(li。siblings())

    在這裡我們首先選擇了class為list的節點內部的class為item-0和active的節點,也就是第三個li節點。那麼很明顯它的兄弟節點有四個,那就是第一、二、四、五個li節點。

    執行結果:

  • second item
  • first item
  • fourth item
  • fifth item
  • 可以看到執行結果也正是我們剛才所說的四個兄弟節點。

    如果要篩選某個兄弟節點,我們依然可以向方法傳入CSS選擇器,這樣就會從所有兄弟節點中挑選出符合條件的節點了。

    from pyquery import PyQuery as pq

    doc = pq(html)

    li = doc(‘。list 。item-0。active’)

    print(li。siblings(‘。active’))

    在這裡我們篩選了class為active的節點,透過剛才的結果我們可以觀察到class為active的兄弟節點只有第四個li節點,所以結果應該是一個。

    執行結果:

  • fourth item
  • 遍歷

    我們剛才可以觀察到,PyQuery的選擇結果可能是多個節點,可能是單個節點,型別都是PyQuery型別,並沒有返回像BeautifulSoup一樣的列表。

    對於單個節點來說,我們可以直接列印輸出,也可直接轉成字串。

    from pyquery import PyQuery as pq

    doc = pq(html)

    li = doc(‘。item-0。active’)

    print(li)

    print(str(li))

    執行結果:

  • third item
  • third item
  • 對於多個節點的結果,我們就需要遍歷來獲取了,例如這裡我們把每一個li節點進行遍歷,,需要呼叫items()方法。

    from pyquery import PyQuery as pq

    doc = pq(html)

    lis = doc(‘li’)。items()

    print(type(lis))

    for li in lis:

    print(li, type(li))

    執行結果:

  • first item
  • second item
  • third item
  • fourth item
  • fifth item
  • 在這裡我們可以發現呼叫items()方法後,會得到一個生成器,遍歷一下,就可以逐個得到li節點物件了,它的型別也是PyQuery型別,所以每個li標籤還可以呼叫前面所說的方法進行選擇,比如繼續查詢子節點,尋找某個祖先節點等等,非常靈活。

    獲取資訊

    提取到節點之後,我們的最終目的當然是提取節點所包含的資訊了,比較重要的資訊有兩類,一是獲取屬性,二是獲取文字,下面我們分別進行說明。

    獲取屬性

    提取到某個PyQuery型別的節點之後,我們可以呼叫attr()方法來獲取屬性。

    html = ‘’‘

    ’‘’

    from pyquery import PyQuery as pq

    doc = pq(html)

    a = doc(‘。item-0。active a’)

    print(a, type(a))

    print(a。attr(‘href’))

    執行結果:

    third item

    link3。html

    ``

    在這裡我們首先選中了class為item-0和active的li節點內的a節點,它的型別可以看到是PyQuery型別。

    然後我們呼叫了attr()方法,然後傳入屬性的名稱,就可以得到這個屬性值了。

    也可以透過呼叫attr屬性來獲取屬性,用法如下:

    ```python

    print(a。attr。href)。md。blank。line。437。

    結果:

    link3。html

    結果是完全一樣的,在這裡我們沒有呼叫方法,而是呼叫了attr屬性,然後再呼叫屬性名,同樣可以得到屬性值。

    如果我們選中的是多個元素,然後呼叫attr()方法會出現怎樣的結果?我們用一個例項來測試一下。

    a = doc(‘a’)

    print(a, type(a))

    print(a。attr(‘href’))

    print(a。attr。href)

    執行結果:

    second itemthird itemfourth itemfifth item

    link2。html

    link2。html

    照理來說我們選中的a節點應該有四個,而且列印結果也是四個,但是當我們呼叫attr()方法時,返回的結果卻只是第一個。

    所以當返回結果包含多個節點時,呼叫attr()方法只會得到第一個節點的屬性。

    那麼遇到這種情況如果我們想獲取所有的a節點的屬性,就需要用到上文所說的遍歷了。

    from pyquery import PyQuery as pq

    doc = pq(html)

    a = doc(‘a’)

    for item in a。items():

    print(item。attr(‘href’))

    執行結果:

    link2。html

    link3。html

    link4。html

    link5。html

    所以,在進行屬性獲取的時候觀察一下返回節點是一個還是多個,如果是多個,則需要遍歷才能依次獲取每個節點的屬性。

    獲取文字

    獲取節點之後的另一個主要的操作就是獲取其內部的文字了,我們可以呼叫text()方法來獲取。

    html = ‘’‘

    ’‘’

    from pyquery import PyQuery as pq

    doc = pq(html)

    a = doc(‘。item-0。active a’)

    print(a)

    print(a。text())

    執行結果:

    third item

    third item

    我們首先選中了一個a節點,然後呼叫了text()方法,就可以獲取其內部的文字資訊了,它會忽略掉標籤內部包含的所有HTML,只返回純文字內容。

    但如果我們想要獲取這個節點內部的HTML文字,就可以用html()方法。

    from pyquery import PyQuery as pq

    doc = pq(html)

    li = doc(‘。item-0。active’)

    print(li)

    print(li。html())

    這裡我們選中了第三個li節點,然後呼叫了html()方法,它返回的結果應該是li標籤內的所有HTML文字。

    執行結果:

    third item

    這裡同樣有一個問題,如果我們選中的結果是多個節點,text()或html()會返回什麼內容?

    我們用一個例項來看一下:

    html = ‘’‘

    ’‘’

    from pyquery import PyQuery as pq

    doc = pq(html)

    li = doc(‘li’)

    print(li。html())

    print(li。text())

    print(type(li。text())

    執行結果:

    second item

    second item third item fourth item fifth item

    結果可能比較出乎意料,我們選中的是所有的li節點,可以發現html()方法返回的是第一個li節點的內部HTML文字,而text()則返回了所有的li節點內部純文字,中間用一個空格分割開,實際上是一個字串。

    所以這個地方值得注意,如果我們得到的結果是多個節點,如果要獲取每個節點的內部HTML文字,則需要遍歷每個節點,而text()方法不需要遍歷就可以獲取,它是將所有節點取文字之後合併成一個字串。

    節點操作

    PyQuery提供了一系列方法來對節點進行動態修改操作,比如為某個節點新增一個class,移除某個節點等等,這些操作有時候會為提取資訊帶來極大的便利。

    由於節點操作的方法太多,下面舉幾個典型的例子來說明它的用法。

    addClass、removeClass

    我們先用一個例項來感受一下:

    html = ‘’‘

    ’‘’

    from pyquery import PyQuery as pq

    doc = pq(html)

    li = doc(‘。item-0。active’)

    print(li)

    li。removeClass(‘active’)

    print(li)

    li。addClass(‘active’)

    print(li)

    首先我們選中了第三個li節點,然後呼叫了removeClass()方法,將li的active這個class移除,後來又呼叫了addClass()方法,又將class添加回來,每執行一次操作,就列印輸出一下當前li節點的內容。

    執行結果:

  • third item
  • third item
  • third item
  • 可以看到一共進行了三次輸出,第二次輸出li標籤的active這個class被移除了,第三次class又添加回來了。

    所以說我們addClass()、removeClass()這些方法可以動態地改變節點的class屬性。

    attr、text、html

    當然除了操作class這個屬性,也有attr()方法來專門針對屬性進行操作,也可以用text()、html()方法來改變節點內部的內容。

    我們用例項感受一下:

    html = ‘’‘

    ’‘’

    from pyquery import PyQuery as pq

    doc = pq(html)

    li = doc(‘。item-0。active’)

    print(li)

    li。attr(‘name’, ‘link’)

    print(li)

    li。text(‘changed item’)

    print(li)

    li。html(‘changed item’)

    print(li)

    在這裡我們首先選中了li標籤,然後呼叫attr()方法來修改屬性,第一個引數為屬性名,第二個引數為屬性值,然後我們呼叫了text()和html()方法來改變節點內部的內容。三次操作後分別又列印輸出當前li節點。

    執行結果:

  • third item
  • third item
  • changed item
  • changed item
  • 可以發現,呼叫attr()方法後,li節點多來一個原本不存在的屬性name,其值為link,呼叫text()方法,傳入文字之後,發現li節點內部的文字就全被改變為傳入的字串文字了。呼叫html()方法傳入HTML文字之後,li節點內部又改變為傳入的HTML文字。

    所以說,attr()方法如果只傳入第一個引數屬性名,則是獲取這個屬性值,如果傳入第二個引數,可以用來修改屬性值,text()和html()方法如果不傳引數是獲取節點內純文字和HTML文字,如果傳入引數則是進行賦值。

    remove

    remove顧名思義移除,remove()方法有時會為資訊的提取帶來非常大的便利。下面我們看一個例項:

    html = ‘’‘

    Hello, World

    This is a paragraph。

    ’‘’

    from pyquery import PyQuery as pq

    doc = pq(html)

    wrap = doc(‘。wrap’)

    print(wrap。text())

    在這裡有一段HTML文字,我們現在想提取Hello, World這個字串,而不要p節點內部的字串,這個怎樣來提取?

    在這裡我們直接先嚐試提取class為wrap的節點的內容,看看是不是我們想要的,執行結果如下:

    Hello, World This is a paragraph。

    然而這個結果還包含了內部的p節點的內容,也就是說text()把所有的純文字全提取出來了。如果我們想去掉p節點內部的文字,可以選擇再把p節點內的文字提取一遍,然後從整個結果中移除這個子串,但這個做法明顯比較繁瑣。

    那這是remove()方法就可以派上用場了,我們可以接著這麼做:

    wrap。find(‘p’)。remove()

    print(wrap。text())

    我們首先選中了p節點,然後呼叫了remove()方法將其移除,然後這時wrap內部就只剩下Hello, World這句話了,然後再利用text()方法提取即可。

    所以說,remove()方法可以刪除某些冗餘內容,來方便我們的提取。在適當的時候使用可以極大地提高效率。

    另外其實還有很多節點操作的方法,比如append()、empty()、prepend()等方法,他們和jQuery的用法是完全一致的,詳細的用法可以看到官方文件。

    http://

    pyquery。readthedocs。io/

    en/latest/api。html

    偽類選擇器

    CSS選擇器之所以強大,還有一個很重要的原因就是它支援多種多樣的偽類選擇器。例如選擇第一個節點、最後一個節點、奇偶數節點、包含某一文字的節點等等,我們用一個例項感受一下:

    html = ‘’‘

    ’‘’

    from pyquery import PyQuery as pq

    doc = pq(html)

    li = doc(‘li:first-child’)

    print(li)

    li = doc(‘li:last-child’)

    print(li)

    li = doc(‘li:nth-child(2)’)

    print(li)

    li = doc(‘li:gt(2)’)

    print(li)

    li = doc(‘li:nth-child(2n)’)

    print(li)

    li = doc(‘li:contains(second)’)

    print(li)

    在這裡我們使用了CSS3的偽類選擇器,依次選擇了第一個

  • 節點、最後一個
  • 節點、第二個
  • 節點、第三個
  • 之後的
  • 節點、偶數位置的
  • 節點、包含second文字的
  • 節點,功能十分強大。

    更多的CSS選擇器的用法可以參照

    http://www。

    w3school。com。cn/css/ind

    ex。asp

    到此為止PyQuery的常用用法就介紹完了,如果想檢視更多的內容可以參考一下PyQuery的官方文件http://pyquery。readthedocs。io,相信有了它,解析網頁不再是難事。

    作者:崔慶才 Python愛好者社群專欄作者 授權原創釋出,請勿轉載,謝謝。

    出處:Python3中PyQuery的使用方法

    配套影片教程:Python3爬蟲三大案例實戰分享:貓眼電影、今日頭條街拍美圖、淘寶美食 Python3爬蟲三大案例實戰分享

    公眾號:Python愛好者社群(微信ID:python_shequ)

    小編個人微信:tsdatajob ,來不急回覆的,可以加小編微信溝通,謝謝。

  • 標簽: 節點  li  print  HTML  item