三大解析庫的使用
- 2019 年 10 月 6 日
- 筆記
寫在前面的話:我們前面學習了正則,但是正則是個很繁瑣的東西,一旦寫錯,就要匹配失敗,我們還要不斷的調試,對於一個網頁來說都是具有一定的層次性,有的有id,class名,我們可不可以通過這些來獲取我們想要的屬性或者文本?下面可以看看怎麼來獲取。
1,XPath的使用
在使用前,需要安裝lxml庫。 安裝代碼:pip3 install lxml
1.1XPath的常用規則:
- / 表示選取直接子節點
- // 表示選取所有子孫節點
- . 選取當前節點
- .. 選取當前結點的父節點
- @ 選取屬性
看完這些?你是不是還是一臉懵逼?下面我們來實際運用一下。
1.2實例引用
如圖:

導入etree模塊
etree.HTML()是構造一個XPath對象
etree.tostring()是對代碼進行修正,如果有缺失的部分,會自動修復
方法比較簡單,就不截取效果圖了。
如果我們相對本地的文件進行解析怎麼辦?我們可以這樣寫

etree.parse()第一個參數為html的路徑,第二(etree.HTMLParser())和上面etree.HTML()的性質是一樣的,為了方便,接下里我使用對本地文件進行解析。
html文本如下:

1.3獲取所有的節點

結果:

開頭用//表示選取所有符合的節點,*表示獲取所有的節點,
上面兩句話一看這不是一個意思嗎?會不懂!
我們可以分為兩步理解:
第一步//是選取所有符合要求的節點,沒有指明是什麼要求!,不知道你要獲取什麼.
第二步*表示所有節點,所以才會獲取所有節點。這樣理解起來應該會很容易了吧。
注意:返回的是一個列表
1.4獲取指定的節點
還是上面的html文本,如果我們想獲取li節點怎麼辦?
只需要將result_text=html.xpath('//*')修改成result_text=html.xpath('//li')
如果想獲取a節點,就修改成//a,也可以寫成//li//a,或者//ul//a獲取//li/a
都是可以獲取到但是如果//ul/a是獲取不到的因為/表示的是直接子節點
注意:返回的都是節點,並不是文本信息。
即:

這種形式。
1.4屬性匹配
如果我們想要a標籤的href屬性,我們可以修改成//a/@href
返回結果:

返回的也是一個列表
如果我們想要匹配class為li_1的li,可以修改成//li[@class="li_1"]即可
1.5父節點匹配
我們來獲取link2.html的a節點的父節點的class屬性,我們是需要修改成//a[@href="link2.html"]/../@class,這裡的..表示尋找父節點,返回的依然是一個列表。
1.6獲取文本
我們來獲取class為li_3的li下a的文本,可以寫成//li[@class="li_3"]/a/text()即可
1.7contains()函數
比如其中有一個li為:
<li class="li li_last" id="caidan"></li>
此時:li具有兩個class名,我們如果這樣寫//li[@class="li"]是獲取不到節點的
那麼我們可以這樣寫獲取到節點//li[contains(@class,"li")]。
1.8多屬性獲取
<li class="li li_last" id="caidan"></li>,同樣是這個li我們需要獲取class名為li同時id為caidan的li,可以這樣寫//li[contains(@class,"li") and @id="caidan"]
獲取class名為li或者id為caidan的li就用or。
1.9,last(),position()函數
上面的html有很多li,如果我只想獲取第一個可以這樣:
//li[1],同理第二個改成2就可以了,如果想獲取最後一個://li[last()]
如果想獲取前兩個://li[position()<3]
2,Beautiful Soup的使用
同樣的在使用前我們也要安裝Beautiful Soup 沒有安裝的請自行安裝。 首先導入模塊:from bs4 import BeautifulSoup 這次我們直接用一個網站來試試,我選擇的是貓眼網, 你可以選擇其他網站哦。
獲取網頁部分,上節有教,鏈接:python第二大神器requests
如圖:

2.1初始化
BeautifulSoup()第一個參數為獲取的網頁內容,第二個參數為lxml,為什麼是lxml?因為Beautiful Soup在解析時依賴解析器,python自帶的解析器,容錯能力差,比較慢,所以我們使用第三方解析器lxml,
prettify()是將獲取的內容以縮進的方式輸出,看起來很舒服
如圖:

看起來舒服多了。
2.2獲取值
我們來獲取一下title信息,我們是需要這樣。

結果:

我們可以看到title獲取的是title節點的所有信息,而加個string就變成了title里的文本內容,這樣是不是也是很簡單?
2.21獲取屬性值
比如,我們想要獲取img的src屬性,我們只需要,soup.img['src']就可以獲取到,soup.img.arrts['src']也可以獲取到。
如果想獲取到所有的屬性就這樣寫:soup.img.arrts即可
如圖所示:

注意:所有的屬性返回的形式是以字典的形式返回。
2.3獲取直接子節點和子孫節點,父節點,祖先節點,兄弟節點
- 獲取直接子節點:contents,例如我想獲取p標籤的直接子節點:soup.p.contents即可
- 獲取子孫節點:descendants,例如我想獲取p標籤的子孫節點:soup.p.descendants即可
- 獲取父節點:parent屬性,例如我想獲取p標籤的父節點:soup.p.parent即可
- 獲取祖先節點:parents屬性,例如我想獲取p標籤的祖先節點:soup.p.parents即可
- 獲取兄弟節點:next_sibling,previous_sibling,next_siblings,previous_siblings分別為下一個兄弟節點,上一個兄弟節點,上面所有的兄弟節點,下面所有的兄弟節點。
2.4獲取文本屬性
string為獲取文本
attrs為獲取屬性
2.5方法選擇器
find_all()返回的一個列表,匹配所有符合要求的元素
- 如果我們想要獲取ul可以這樣寫:soup.find_all(name='ul')
- 如果我們想要獲取id為id1屬性可以這樣寫:soup.find_all(arrts[id='id1'])
- 如果我們想要獲取class為class1屬性可以這樣寫:soup.find_all(arrts[class_='class1']) 因為class有特殊意義,所以我們獲取class的時候價格_即可
- 如果我們想要獲取文本值可以這樣寫:soup.find_all(text=re.compile('')) 匹配text需要用到正則,匹配你想要的text值
- find()只返回一個值,匹配到符合要求的第一個值。 用法和上面的方法一樣
注意:以上說有的屬性,方法都是通過我實例的soup來調用,soup是我的命名,你可以修改它,同時你調用就要用你的命名了
2.6css選擇器
我們如果用css選擇器需要調用select()方法
比如想獲取class名為class1的節點,我們可以這樣寫:soup.select('.class1')即可,和css的表達方式是一樣的,但是他的css選擇器功能不夠強大,下面我們介紹一個針對css的解析庫。
3,pyquery的使用
首先要安裝pyquery 沒有安裝的請自行安裝。 導入模塊:from pyquery import PyQuery 首先和上面的一樣,同樣需要初始化,獲取對象
如下:

結果:

這樣就獲取到了所有的li
此外:初始化對象時,可以填寫文本(上面就是),還可以填寫url:PyQuery(url='https://maoyan.com/')
還可以填寫本地文件:PyQuery(filename=''),''中填寫本地文件的路徑
3.1css選擇器的基本用法
如果想選取class名為class1下的li可以這樣寫result('.class li')和css的選擇器寫法是一樣的。
3.2find()方法,子節點,父節點,兄弟節點
和上面不同這裡的find()方法是查找所有的子孫節點,
- 如果想獲取li下的所有a節點可以這樣寫:result('li').find('a')即可
- 如果只想查找子節點:children()方法即可
- 父節點:parent()獲取直接父節點
- 獲取所有父節點:parents()獲取所有父節點,如果只想要父節節點中class為class1的可以這樣寫:parents('.class1')
注意:輸出的是父節點的所有內容。
兄弟節點:siblis()方法,如果只想要兄弟節點中id為id1的可以這樣寫:parents('#id1')
3.3對於獲取的結果,不想上面返回的是列表,這裡如果返回多個對象需要for循環遍歷
3.4獲取屬性,文本,
例如我們想要獲取li下a的href屬性(attr()函數),由於有多個結果,所以我們這裡需要遍歷。
如圖:

結果:

注意:如果不遍歷,只會輸出第一個
- 如果我們想要獲取文本值:text()方法,只需要將attr()函數改為text()函數即可
3.6對屬性,文本,class的刪除,修改
- addClass('class1'):表示添加一個class名,名字為class1
- removeClass('class1')表示刪除一個class名,名字為class1
我們來實例一下:

結果:

同時我們還可以添加屬性,文本
- 添加屬性:attr('name','name1')
- 添加文本:text('123123')
- 添加代碼:html('<span>12122</apan>')
有了添加,就有刪除remove()函數
- 比如如果我們想刪除li下的所有a節點
- 可以這樣寫:result('li').find('a').remove()
4.0完
