PyQuery:一個爬蟲界最簡潔優雅的庫

2021-02-24 戀習Python


簡潔的PyQuery庫

pyquery庫是jQuery的Python實現,能夠以jQuery的語法來操作解析 HTML 文檔,易用性和解析速度都很好。特別適合進行訪問和解析網頁數據。

PyQuery庫官方文檔 https://pythonhosted.org/pyquery/index.html

本文章節:

初始化為PyQuery對象

常用的CCS選擇器

偽類選擇器

查找標籤

獲取標籤信息

高級方法

一、初始化為PyQuery對象

html_string = """

<html lang="en">

<head>

簡單好用的

<title>PyQuery</title>

</head>

<body>

<ul id="container">

<li>Python</li>

<li>大法</li>

<li>好</li>

</ul>

</body>

</html>

"""

相當於BeautifulSoup庫的初識化方法,將html轉化為BeautifulSoup對象。

bsObj = BeautifulSoup(html, 'html.parser')

PyQuery庫也要有自己的初始化。

1.1 將字符串初始化

from pyquery import PyQuery

#初始化為PyQuery對象

doc = PyQuery(html_string)

print(type(doc))

print(doc)

Run

<class 'pyquery.pyquery.PyQuery'>

<html lang="en">

<head>

簡單好用的

<title>PyQuery</title>

</head>

<body>

<ul id="container">

<li class="object-1">Python</li>

<li class="object-2">大法</li>

<li class="object-3">好</li>

</ul>

</body>

</html>

1.2 將html文件初始化

#filename參數為html文件路徑

doc = PyQuery(filename = 'test.html')

print(type(doc))

print(doc)

1.3 對網站訪問並初始化

response = PyQuery(url = 'https://www.baidu.com')

print(type(response))

print(response)

Run

<class 'pyquery.pyquery.PyQuery'>

<html> <head><meta http-equiv="content-type" content="text/html;charset=utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=Edge"/><meta content="always" name="referrer"/><link rel="stylesheet" type="text/css" href="https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css"/><title>百度一下,你就知道</title></head> <body link="#0000cc"> <div id="wrapper"> <div id="head"> <div class="head_wrapper"> <div class="s_form"> <div class="s_form_wrapper"> <div id="lg"> <img hidefocus="true" src="//www.baidu.com/img/bd_logo1.png" width="270" height="129"/> </div> <form id="form" name="f" action="//www.baidu.com/s" class="fm"> <input type="hidden" name="bdorz_come" value="1"/> <input type="hidden" name="ie" value="utf-8"/> <input type="hidden" name="f" value="8"/> <input type="hidden" name="rsv_bp" value="1"/> <input type="hidden" name="rsv_idx" value="1"/> <input type="hidden" name="tn" value="baidu"/><span class="bg s_ipt_wr"><input id="kw" name="wd" class="s_ipt" value="" maxlength="255" autocomplete="off" autofocus="autofocus"/></span><span class="bg s_btn_wr"><input type="submit" id="su" value="百度一下" class="bg s_btn" autofocus=""/></span> </form> </div> </div> <div id="u1"> <a href="http://news.baidu.com" name="tj_trnews" class="mnav">新闻</a> <a href="https://www.hao123.com" name="tj_trhao123" class="mnav">hao123</a> <a href="http://map.baidu.com" name="tj_trmap" class="mnav">地图</a> <a href="http://v.baidu.com" name="tj_trvideo" class="mnav">视频</a> <a href="http://tieba.baidu.com" name="tj_trtieba" class="mnav">贴吧</a> <noscript> <a 。。。。<div id="ftCon"> <div id="ftConw"> <p id="lh"> <a href="http://home.baidu.com">关于百度</a> <a href="http://ir.baidu.com">About Baidu</a> </p> <p id="cp">©2017 Baidu <a href="http://www.baidu.com/duty/">使用百度前必读</a>  <a href="http://jianyi.baidu.com/" class="cp-feedback">意见反馈</a> äº¬ICP证030173号  <img src="//www.baidu.com/img/gs.gif"/> </p> </div> </div> </div> </body> </html>

上面的字符串出現亂碼,所以需要設置使用encoding參數

response = PyQuery(url = 'https://www.baidu.com', encoding='utf-8')

print(type(response))

print(response)

<class 'pyquery.pyquery.PyQuery'>

<html> <head><meta http-equiv="content-type" content="text/html;charset=utf-8"/><meta http-equiv="X-UA-Compatible" content="IE=Edge"/><meta content="always" name="referrer"/><link rel="stylesheet" type="text/css" href="https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css"/><title>百度一下,你就知道</title></head> <body link="#0000cc"> <div id="wrapper"> <div id="head"> <div class="head_wrapper"> ength="255" autocomplete="off" autofocus="autofocus"/></span><span class="bg s_btn_wr"><input type="submit" id="su" 。。。

</script> <a href="//www.baidu.com/more/" name="tj_briicon" class="bri" style="display: block;">更多產品</a> </div> </div> </div> <div id="ftCon"> <div id="ftConw"> <p id="lh"> <a href="http://home.baidu.com">關於百度</a> <a href="http://ir.baidu.com">About Baidu</a> </p> <p id="cp">©2017 Baidu <a href="http://www.baidu.com/duty/">使用百度前必讀</a>  <a href="http://jianyi.baidu.com/" class="cp-feedback">意見反饋</a> 京ICP證030173號  <img src="//www.baidu.com/img/gs.gif"/> </p> </div> </div> </div> </body> </html>

二、常用的CCS選擇器

從這一節開始,我們就要對PyQuery對象進行操作,獲得我們想要的各種數據。你會看到解析網頁,不論什麼苦,基本原理實際上是沒有區別的,學會了一種解析庫。再看其他解析庫文檔,是很容易理解的。

在 CSS 中,選擇器是一種模式,用於選擇需要添加樣式的元素。

常用的css選擇器

本文只講clas id 和element最常見的css選擇器。對css不太懂了,也沒關係,可以去w3c官網的css選擇器,查看下文檔

#使用上文的doc

print(doc)

Run

<html lang="en">

<head>

簡單好用的

<title>PyQuery</title>

</head>

<body>

<ul id="container">

<li class="object-1">Python</li>

<li class="object-2">大法</li>

<li class="object-3">好</li>

</ul>

</body>

</html>

2.1 列印id為container的標籤

print(doc('#container'))

print(type(doc('#container')))

Run

<ul id="container">

<li class="object-1">Python</li>

<li class="object-2">大法</li>

<li class="object-3">好</li>

</ul>

<class 'pyquery.pyquery.PyQuery'>

2.2 列印class為object-1的標籤

print(doc('.object-1'))

Run

<li class="object-1">Python</li>

列印標籤名為body的標籤

print(doc('body'))

Run

<body>

<ul id="container">

<li class="object-1">Python</li>

<li class="object-2">大法</li>

<li class="object-3">好</li>

</ul>

</body>

2.3 多種css選擇器使用

選出ul節點,有很多種表達方式。比如ul節點(該ul節點中的屬性鍵值對為id=container)

print(doc("ul[id=container]"))

Run

<ul id="container">

<li class="object-1">Python</li>

<li class="object-2">大法</li>

<li class="object-3">好</li>

</ul>

三、偽類選擇器

pseudo_html = """

<html lang="en">

<head>

簡單好用的

<title>PyQuery</title>

</head>

<body>

<ul id="container">

<li>Python</li>

<li>大法</li>

<li>好</li>

<li>好</li>

<li>好玩</li>

</ul>

</body>

</html>

"""

pseudo_doc = PyQuery(pseudo_html)

print(pseudo_doc)


Run

<html lang="en">

<head>

簡單好用的

<title>PyQuery</title>

</head>

<body>

<ul id="container">

<li class="object-1">Python</li>

<li class="object-2">大法</li>

<li class="object-3">好</li>

<li class="object-4">好</li>

<li class="object-6">好玩</li>

</ul>

</body>

</html>

3.1 偽類nth

print(pseudo_doc('li:nth-child(2)'))

#列印第一個li標籤

print(pseudo_doc('li:first-child'))

#列印最後一個標籤

print(pseudo_doc('li:last-child'))

Run

<li class="object-2">大法</li>

<li class="object-1">Python</li>

<li class="object-6">好玩</li>

3.2 contains

#找到含有Python的li標籤

print(pseudo_doc("li:contains('Python')"))

#找到含有好的li標籤

print(pseudo_doc("li:contains('好')"))

Run

<li class="object-1">Python</li>

<li class="object-3">好</li>

<li class="object-4">好</li>

<li class="object-6">好玩</li>

四、查找標籤

PyQuery對象擁有很多實用的定位方法

print(doc)


Run

<html lang="en">

<head>

簡單好用的

<title>PyQuery</title>

</head>

<body>

<ul id="container">

<li class="object-1">Python</li>

<li class="object-2">大法</li>

<li class="object-3">好</li>

</ul>

</body>

</html>

獲得所有的li標籤

doc('li')

Run

[<li.object-1>, <li.object-2>, <li.object-3>]

查看li標籤的類型

[type(l) for l in doc('li')]

Run

[lxml.etree._Element, lxml.etree._Element, lxml.etree._Element]

doc('li')返回的不是PyQuery類型,而是lxml.etree.Element類型。Element.text獲取節點的文本內容

[l.text for l in doc('li')]

Run

['Python', '大法', '好']

獲取所有的li,並以PyQuery形式逐個迭代

doc.items('li')

Run

<generator object PyQuery.items at 0x10e977a98>

查看doc.items迭代出的對象的數據類型

[type(l) for l in doc.items('li')]

Run

[pyquery.pyquery.PyQuery, pyquery.pyquery.PyQuery, pyquery.pyquery.PyQuery]

PyQuery類型擁有.text()方法

[l.text() for l in doc.items('li')]

Run

['Python', '大法', '好']

doc('body')

Run

[<body>]

獲得doc節點的(當前為整個文檔)的 id='container' 的節點

doc.find('#container')

Run

[<ul#container>]

id='container' 的節點的子節點們

id='container' 的節點的子節點們(節點內帶字符串)

doc.find('#container').children()

Run

[<li.object-1>, <li.object-2>, <li.object-3>]

doc.find('#container').contents()

Run

['\n ', <Element li at 0x10e57ac08>, '\n ', <Element li at 0x10d687848>, '\n ', <Element li at 0x10d687e08>, '\n ']

id='container' 的節點的第二個子節點

doc.find('#container').contents().eq(1)

Run

[<li.object-1>]

id='container' 的節點的子節點中不含有 class='object-2' 的節點

doc.find('#container').children().not_('.object-2')

Run

[<li.object-1>, <li.object-3>]

.map方法傳入兩個參數,分別是索引值和element。

def func(i, e):

return PyQuery(e).text()

doc('li').map(func)

Run

['Python', '大法', '好']

doc('li').map(lambda i,e: PyQuery(e).text())

Run

['Python', '大法', '好']

輸出ul的子節點的html

doc('ul').html()

Run

'\n <li>Python</li>\n <li>大法</li>\n <li>好</li>\n '

五、pyquery高級用法

PyQuery與BeautifulSoup對比,我們會發現PyQuery可以對網址發起請求。比如

from pyquery import PyQuery

PyQuery(url = 'https://www.baidu.com')

5.1 opener參數

PyQuery對百度網址進行請求,並將請求返回的響應數據處理為PyQuery對象。一般pyquery庫會默認調用urllib庫,如果想使用selenium或者requests庫,可以自定義PyQuery的opener參數。

opener參數作用是告訴pyquery用什麼請求庫對網址發起請求。常見的請求庫如urllib、requests、selenium。這裡我們自定義一個selenium的opener。

from pyquery import PyQuery

from selenium.webdriver import Chrome

from selenium.webdriver.chrome.options import Options

#用selenium訪問url

def selenium_opener(url):

#我沒有將Phantomjs放到環境變量,所以每次用都要放上路徑

#driver = PhantomJS(executable_path = 'phantomjs的路徑')

chrome_options = Options()

chrome_options.add_argument('--headless')

chrome_options.add_argument('--disable-gpu')

driver = Chrome(executable_path='chromedriver所在的路徑',

options=chrome_options)

driver.get(url)

html = driver.page_source

driver.quit()

return html

#注意,使用時opener參數是函數名,沒有括號的!

PyQuery(url='https://www.baidu.com/',

opener=selenium_opener)

Run

[<html>]

這時候我們就能上面學到的知識對PyQuery對象進行操作,提取有用的信息。

5.2 cookies、headers

在requests用法中,一般為了訪問網址更加真實,模仿成瀏覽器。一般我們需要傳入headers,必要的時候還需要傳入cookies參數。而pyquery庫就有這功能,也能偽裝瀏覽器。

from pyquery import PyQuery

cookies = {'Cookie':'你的cookie'}

headers = {'User-Agent':'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'}

PyQuery(url='https://www.baidu.com/',

headers=headers,

cookies=cookies)

Run注意,我這裡返回的內容你可能覺得很少,是因為這是PyQuery對象。PyQuery.html()

[<html>]

5.3 讓你的selenium帶上pyquery功能

如何讓driver訪問的網址得到的網頁直接變為PyQuery對象,更方便提取數據?

本來我想用Phantomjs自定義一個類,讓selenium擁有pyquery的功能。後來測試發現phantomjs去年不再支持selenium,因為曾經的無頭瀏覽器phantomjs具有不可替代的作用,但如今chrome和firefox都能提供無頭瀏覽器的功能。

from pyquery import PyQuery

from selenium.webdriver import Chrome

from selenium.webdriver.chrome.options import Options

class Browser(Chrome):

#Browser繼承Chrome類, 聲明Chrome為無頭模式訪問網站

def __init__(self, executable_path):

chrome_options = Options()

chrome_options.add_argument('--headless')

chrome_options.add_argument('--disable-gpu')

Chrome.__init__(self,

executable_path=executable_path,

options=chrome_options)

#property是裝飾器,需要知道@property下面緊跟的函數,實現了類的屬性功能。

@property

def dom(self):

return PyQuery(self.page_source)

browser = Browser(executable_path='chromedriver所在的路徑')

browser.get(url='https://www.baidu.com/')

print(type(browser.dom))

Run

<class 'pyquery.pyquery.PyQuery'>

這幾個對pyquery功能的擴展,我覺得實現方式很不錯,很美觀簡潔,以後我會多模仿,比如用函數或類的方式,對已有的庫及函數進行功能加持。

覺得內容還不錯的話,給我點個「在看」唄

相關焦點

  • 蟲術:初入爬蟲界
    這枚種子一直埋在心裡已經有十幾年的時光,終於在自己公眾號有些讀者的時候,開始嘗試用自己親身的經歷,來描述爬蟲的世界,帶大家了解爬蟲的工作都是做什麼,以及我心中的爬蟲界。《蟲術》這本小說名為《蟲術》,爬蟲工程師寫的每個爬蟲程序,就像是精心培養的爬蟲。初次接觸蟲術的蟲師們,都會精心培養屬於自己的爬蟲。
  • 西子閣:從奢華繁複還原低調簡潔
    「覺得這是一個挺好的活動,對於提升意法和西子閣的知名度,有很好的推廣作用,讓更多的採購商認識我們,關注我們」。  獲獎並非偶然,得益於老闆娘長期以來對店鋪裝修的重視。西子閣店鋪兩年裝修一次,於今年8月份完成的最新裝修,和兩年前的裝修風格相較,大相逕庭。
  • 最後的糧倉: 末日種子庫
    這些種子就存在今天的末日種子庫中。冰山上的種子銀行在北極圈內,有一座島嶼名叫斯匹次卑爾根島,歸屬於挪威,島上有一座普拉塔貝格山,坐落著一個世界級的「銀行」——末日種子庫。末日種子庫由挪威政府出資建造,目前儲存著大約1億顆、上百萬種來自世界各地的農作物種子。無論是常見的品種,比如市面上的大米,還是特有的種類,比如白鷹玉米,這裡都應有盡有。
  • C語言:優雅的字符串函數庫
    例如:用新語言寫代碼注釋 / commit message / README / issue;對了,我作為英文的愛好者,一直想重啟我的英文學習之路,後續想在公眾號裡記錄一些英文相關的知識,請你們不要笑話我~~~二、字符串函數庫:Simple
  • 圖文:北極圈種子庫
    來自南美洲秘魯安第斯社區的土著居民8月27日在位於北極圈極北凍土區的斯瓦爾巴全球種子庫(Svalbard Global Seed Vault)將精心挑選的750種馬鈴薯種子存入該種子庫。  南美安第斯地區擁有2000多種不同形狀、顏色和大小的馬鈴薯品種。過去幾十年來,由於氣候不斷變化以及包括馬鈴薯晚疫病在內的疾病影響,許多馬鈴薯品種已經消失。為了防止傳統馬鈴薯品種滅絕,安第斯的土著居民27日親自來到斯瓦爾巴全球種子庫,將挑選出的土豆種子存入該種子庫,使子孫後代能夠延續種植和食用這些馬鈴薯品種。
  • Wedding | J'adore 法式優雅,浪漫主義最完美的婚禮
    法式優雅,獻給浪漫主義者場地選擇在中國千年佛教遺址大報恩寺邊上的露臺。法式風風格婚禮講究自然,它追求內在和色彩的聯繫,我們身處其中會感覺到很大的一個活動空間。統一的優雅白,純粹而簡約,打造濃濃的法式情調。
  • 【末日種子庫】大門開啟!
    種子庫位於斯瓦爾巴群島一座北極山脈的山腰上,距離北極點大約1300公裡。斯瓦爾巴種子資源庫於2008年在朗伊爾島成立,包含了來自全球各個國家約八十六萬份樣品。設計種子庫的意圖是,一旦發生核武器戰爭,小行星撞地球,或者其他重大災難,它可以成為食物安全最後的安全網。
  • 南海意庫:綠色的秘密
    從蛇口工業區的建立開始,深圳進入沸沸揚揚的城市建設,在這之前,深圳還不能算是一座城市。....如今的蛇口,工業的色彩正在褪去,原「三洋廠房片區」的老房子和老倉庫經過藝術設計和改造,成為南海意庫文化創意產業園區的主體。斑駁的外牆洗去舊日的風塵,窗臺與護圍上的綠色盆栽一個接一個,連成一片,牆體就活潑了起來,樓裡與樓外被這濃密的綠分隔成兩個世界,生機盎然又不乏寧靜之美。
  • 寶貝討喜的過年新衣LOOK,媽媽們一個比一個心機
    ▷毛衣篇◁關鍵詞:軟綿、優雅大方、簡潔、優雅,躲不過的乖巧可愛呢。▷連衣裙篇◁關鍵詞:大方得體最重要對於男孩子來說,佩戴一個精緻的領結帥過路人甲,而女孩子一個bilingbiling的頭箍一下子直逼小名媛。還有帽子、鬥篷等有很多選擇呢!看完是不是忍不住又要剁手了?那麼,大家抓緊啦。
  • 【Top榜】如何優雅地形容一個人臉大?
    ——昨日,據某娛評人曝光,明星井柏然的字體被資本市場看中,將以1000元/字的價格,被某知名字庫買斷版權。對此井柏然的工作人員稱:「正在洽談,已達成了初步意向。」——昨天,瀋陽張氏帥府博物館將不久前拍賣獲得的50餘件張家藏品,其中包括張學良最愛——趙一荻的三張素顏生活照。據悉,這三張素顏照是首次面世。
  • 內地精子庫斷貨,捐精「送」iPhone 6s
    不過,香港媒體更關注是什麼原因造成內地精子庫精子短缺的。《環球時報》援引香港《南華早報》報導顯示,由於調整計劃生育政策引發需求增長,中國北方一精子庫面臨精源嚴重短缺現象。內地媒體報導稱,根據新的規定,一對夫婦可申請生育二孩,這導致山西省人類精子庫的需求不斷增加,但捐贈者的數量卻依然很少。這個精子庫是該省唯一的官方捐精來源。在2006年成立後的多年內,每年最多只有500名捐精者。
  • 卡爾登城市酒店:城市空間的優雅回應
    酒店主街面一角設置了一個特殊的圓柱形體量形體的對話 簡潔的塔樓通過豎向格柵和黑色玻璃的搭配卡爾登城市酒店的建築設計在有限的城市空間裡滿足了功能、場地與城市設計多方面的要求,也對密集的城市空間秩序提出了優雅的回應。
  • 看設計 | 簡潔酷炫的成人概念滑板車
    Hevesi 帶來的設計在整體上有著更為簡潔和時尚的外形,更符合成人的審美。把手中間設置了一個小小的液晶屏,用來顯示當前速度以及剩餘電量。液晶屏下方還有一個按鈕用來控制踏板的開合。可通過按鈕電動分開的踏板也是一個創新的設計,它可以電動打開,讓滑行姿勢更加穩定、舒適。
  • 原創 世界最罕見血型在中國現世,比熊貓血還稀有,已被國際基因庫收錄
    原標題:世界最罕見血型在中國現世,比熊貓血還稀有,已被國際基因庫收錄血液,是作為人類最基本的必需品,而血型則是血液的一種型號的代稱,世界上最早發現血型的時候是在1900年,奧地利維也納的卡爾·蘭德斯泰納便發現把一個人的紅細胞和另一個人的血清相混合的時候,看到了兩簇紅細胞凝聚在一起,形成了一個個不規則的團體,而且不會與之散開
  • 一個心慌小舉動,鳳凰橋旁意外查出「隱形炸藥庫」
    把「炸藥庫」分兩撥兒,一撥兒放在自家店門口,一撥兒放在自家倉庫裡,這事兒,您通知過左鄰右舍嗎?萬一爆炸了,您是打算「殺敵一千、自損八百」嗎?自己作為經營戶,更應該懂法守法,行政拘留的教訓您可得記牢了!
  • 新疆獨庫公路通車時間推後
    素有中國最美艱險公路之稱的新疆獨庫公路積雪比往多,雪線整體下移5公裡,最厚處的雪牆高達15米,預計通車時間要比往年晚幾天。當地相關部門提醒廣大自駕愛好者為了自身安全,不要貿然前往。去年入冬以來,獨庫公路山區遭遇了近20年來最大降雪量,加上近期山區頻繁降雪,雪線下移5公裡,由於天氣不穩定,前期已發生多次雪崩,獨庫公路的清雪工作難度較往年加大。
  • 【瑪格麗】溫暖羽絨,優雅出眾
    【瑪格麗】女裝品牌升級12月25日重裝啟幕全場貨品200升280活動時間:12月25日-27日電話:0951-6099453地址:國芳百貨三樓瑪格麗專櫃2015秋冬羽絨服系類採用經典藍白撞色設計,配有細節口袋和白色裝飾邊,輔以現代建築裝飾線條,為您冬天展現卓爾不群的優雅氣質
  • 孫芸芸:臺灣名媛的優雅與愛情
    每次無論在時尚場合還是在綜藝節目看到孫芸芸,她總是帶著一抹淡而優雅的微笑,不管是採訪或是拍照,她總是輕聲細語的面對每一個媒體要求、帶著些許ABC腔調的中文認真回答每個記者的提問與疑惑;不論專業問題還是打諢插科的玩笑話,她都有自己的一套方法與哲學得體的應對媒體也滿足大眾的好奇心
  • 如何優雅地說分手,中外明星分手文案大PK
    既然決定要分手,就要優雅地say goodbye。兩人話中絲毫沒有指責謾罵的戾氣,更多的是感念過往、彼此守候的溫情。文案雖短,卻不是看上去的那麼簡單。分手難,寫文案更難。如何不哭、不鬧、不上吊,優雅體面地說分手,這絕對是一門「學問」。小U集合了中外明星分手的優秀文案,來一次現場教學。1.
  • 招募 | 金山意庫*宜家:關於那些「可持續設計」
    因此,可持續性也就成為了一個全球話題,設計思維引導越來越多的人,走在有意義的創新的道路上。本周四12月17日下午三點,金山意庫將聯合宜家共同推出,以關於可持續設計為主題的沙龍。今年9月,宜家正式開啟2021財年,把「可持續」和「可負擔」作為2021財年的品牌重點,希望通過更可持續、低價且有意義的產品和解決方案,為消費者創造更加美好的日常生活;同時,通過貫穿公司運營、人與社會等方面的可持續努力,展望一個更美好的未來