python爬蟲——BeautifulSoup詳解(附加css選擇器)

 

BeautifulSoup是一個靈活有方便的網頁解系庫,處理搞笑,支持多種解析器,利用他能夠不編寫正賊表達式便可方便實現網頁信息的提取。css

 

 

解析庫:html

咱們主要用lxml解析器python

 

 

標籤選擇器ide

# coding=utf-8
from bs4 import BeautifulSoup as bs

html = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title" name="dromouse"><b>The Dormouse's story</b></p>

<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>,
<a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and
<a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>;
and they lived at the bottom of a well.</p>

<p class="story">...</p>
"""

soup = bs(html, 'lxml')
print(soup.title)
print(type(soup.title))
print(soup.head)
print(type(soup.head))
print(soup.p)
print(type(soup.p))

這裏咱們print了soup.title、head、p三個標籤以及他們的類型,結果以下:編碼

他們的類型都是bs.elment.tag,類型,類就是標籤類型,而且對於soup.p,是把第一個p標籤輸出,也就是說有多個相同的標籤,只輸出第一個spa

 

 

獲取名稱:code

print(soup.title.name)

輸出結果就是titleorm

 

 

獲取屬性: xml

print(soup.title.attrs['name'])

print(soup.p['name'])

能夠看到這兩種方式都是相同的htm

 

 

獲取內容:

print(soup.p.string)

 

 

嵌套選擇:

 

也就是說從body到p,是一個嵌套的關係,p也是說,經過 .head獲得的tag還能夠進一步 向下索取,經過.body.p獲得p標籤

 

 

子節點和子孫節點(children和contents):

contents:

# coding=utf-8
from bs4 import BeautifulSoup as bs

html = """
 <html>
 <head>
  <title>
   The Dormouse's story
  </title>
 </head>
 <body>
  <p class="story">
   Once upon a time there were three little sisters; and their names were
   <a class="sister" href="http://example.com/elsie" id="link1">
    Elsie
   </a>
   ,
   <a class="sister" href="http://example.com/lacie" id="link2">
    Lacie
   </a>
   and
   <a class="sister" href="http://example.com/tillie" id="link2">
    Tillie
   </a>
   ; and they lived at the bottom of a well.
  </p>
  <p class="story">
   ...
  </p>
 </body>
</html>
"""

soup = bs(html, 'lxml')
print(soup.body.contents)

能夠看到contents屬性返回了一個列表,整個p中的內容。把全部的換行符 標籤放進了列表

children:

當咱們把contents換成children:

print(soup.body.children)

 

 

contents:

它返回了一個迭代器,須要用for循環遍歷使用

 

 

後代descendants:

print(soup.body.descendants)

仍是一個迭代器,而且descendants是得到全部子孫節點,也就是兒子的兒子也會得到

 

 

父節點parent:

返回父節點

 

 

父節點parents:

 

 

兄弟節點siblings:

 

以上是標籤選擇器,是經過名字進行選擇,可是在選擇時候,每每會有不少名字相同的標籤,因此咱們不能徹底用標籤選擇器進行選擇,故引入標準選擇器:

標準選擇器:

 

 

find_all(name, attrs, recursive, text, **kwargs)

可根據標籤名、屬性、內容查找文檔, 把全部符合條件的結果,並以列表的形式返回

name:

能夠看到findall返回的列表中的每個項哦都是tag類型

由此咱們能夠嵌套for循環:

for p in soup.find_all('p'):
    print(p.find_all('a'))

attrs:

print(soup.find_all(attrs={'id': 'list-1'}))
print(soup.find_all(attrs={'name': 'elements'}))

attr須要傳入一個字典

而且對於某一些屬性,能夠直接用參數傳入:

print(soup.find_all(id='list-1'))
print(soup.find_all(class_='elements'))   #class 是python的一個關鍵詞,因此咱們用class_代替class

text:

根據文本的內容選擇,而它的返回值僅僅是文本的列表而不是tag

 

 

find(name, attrs, recursive, text, **kwargs)

與find_all不一樣是  find返回單個元素,fan_all返回全部元素。 find查找一個不存在的元素返回None

 

find_parent()和find_parents():

find_parent()返回全部祖先節點,find_parent()返回直接父節點。

 

find_next_siblings() 和 find_next_sibling()

find_next_siblings() 返回後面全部兄弟節點 find_next_sibling()返回前面一個兄弟節點

 

find_all_next() 和find_next()

find_all_next()返回節點後全部符合條件的節點,find_next()返回第一個符合條件的節點 

 

find_all_previous()和find_previous()

find_all_previous()返回節點錢全部符合條件的節點,find_previous返回第一個符合條件的節點

 

 

 

css選擇器

經過css()直接傳入css選擇器便可完成選擇

標籤(什麼都不用加).屬性(加點) #id(加井號) 

  1. import requests  
  2. from bs4 import BeautifulSoup as bs  
  3.   
  4. html = """ 
  5. <html> 
  6.     <head> 
  7.         <title>The Dormouse's story</title> 
  8.     </head> 
  9.     <body> 
  10.         <p class="title" name="dromouse"> 
  11.             <b>The Dormouse's story</b> 
  12.         </p> 
  13.         <p class="story"> 
  14.             Once upon a time there were three little sisters; and their names were 
  15.             <a class="mysis" href="http://example.com/elsie" id="link1"> 
  16.                 <b>the first b tag<b> 
  17.                 Elsie 
  18.             </a>, 
  19.             <a class="mysis" href="http://example.com/lacie" id="link2" myname="kong"> 
  20.                 Lacie 
  21.             </a>and 
  22.             <a class="mysis" href="http://example.com/tillie" id="link3"> 
  23.                 Tillie 
  24.             </a>;and they lived at the bottom of a well. 
  25.         </p> 
  26.         <p class="story"> 
  27.             myStory 
  28.             <a>the end a tag</a> 
  29.         </p> 
  30.         <a>the p tag sibling</a> 
  31.     </body> 
  32. </html> 
  33. """  
  34. soup = bs(html, 'lxml')  
  35. print(soup.select('p'))  
  36. print(soup.select('p a'))  
  37. print(type(soup.select('p')[0]))  

輸出結果1是一個包含全部p標籤的列表 2是一個包含全部p標籤下的a標籤的列表,3是,也就是說。css選擇器生成的結果就是一個tag類型的列表

同時對於soup.select('a.mysis‘表示class屬性爲mysis的全部標籤。也即沒有空格的表示有某一個屬性的或者id的標籤。 有空格表明是同等的

又由於select返回的是tag類型的列表,因此咱們能夠繼續使用上面的方法得到屬性即:、

  1. for a in soup.select('p a'):    
  2.     #方法一    
  3.     print(a['href'])    
  4.     #方法二    
  5.     print(a.attrs['href'])    

 如下羅列出一些css選擇器的方法:(如下內容轉自https://www.cnblogs.com/kongzhagen/p/6472746.html)


一、經過標籤選擇

  1. # 選擇全部title標籤  
  2. soup.select("title")  
  3. # 選擇全部p標籤中的第三個標籤  
  4. soup.select("p:nth-of-type(3)") 至關於soup.select(p)[2]  
  5. # 選擇body標籤下的全部a標籤  
  6. soup.select("body a")  
  7. # 選擇body標籤下的直接a子標籤  
  8. soup.select("body > a")  
  9. # 選擇id=link1後的全部兄弟節點標籤  
  10. soup.select("#link1 ~ .mysis")  
  11. # 選擇id=link1後的下一個兄弟節點標籤  
  12. soup.select("#link1 + .mysis")  

二、經過類名查找

  1. # 選擇a標籤,其類屬性爲mysis的標籤  
  2. soup.select("a.mysis")  

三、經過id查找

  1. # 選擇a標籤,其id屬性爲link1的標籤  
  2. soup.select("a#link1")  

四、經過【屬性】查找,固然也適用於class

  1. # 選擇a標籤,其屬性中存在myname的全部標籤  
  2. soup.select("a[myname]")  
  3. # 選擇a標籤,其屬性href=http://example.com/lacie的全部標籤  
  4. soup.select("a[href='http://example.com/lacie']")  
  5. # 選擇a標籤,其href屬性以http開頭  
  6. soup.select('a[href^="http"]')  
  7. # 選擇a標籤,其href屬性以lacie結尾  
  8. soup.select('a[href$="lacie"]')  
  9. # 選擇a標籤,其href屬性包含.com  
  10. soup.select('a[href*=".com"]')  
  11. # 從html中排除某標籤,此時soup中再也不有script標籤  
  12. [s.extract() for s in soup('script')]  
  13. # 若是想排除多個呢  
  14. [s.extract() for s in soup(['script','fram']  

五、獲取文本及屬性

  1. html_doc = """<html> 
  2.     <head> 
  3.         <title>The Dormouse's story</title> 
  4.     </head> 
  5. <body> 
  6.     <p class="title"><b>The Dormouse's story</b></p> 
  7.     <p class="story">Once upon a time there were three little sisters; and their names were 
  8.         <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>, 
  9.         <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and 
  10.         <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; 
  11.     </p> 
  12.         and they lived at the bottom of a well. 
  13.     <p class="story">...</p> 
  14. </body> 
  15. """  
  16. from bs4 import BeautifulSoup  
  17. ''''' 
  18. 以列表的形式返回 
  19. '''  
  20. soup = BeautifulSoup(html_doc, 'html.parser')  
  21. s = soup.select('p.story')  
  22. s[0].get_text()  # p節點及子孫節點的文本內容  
  23. s[0].get_text("|")  # 指定文本內容的分隔符  
  24. s[0].get_text("|", strip=True)  # 去除文本內容先後的空白  
  25. print(s[0].get("class"))  # p節點的class屬性值列表(除class外都是返回字符串)  

六、UnicodeDammit.detwingle() 方法只能解碼包含在UTF-8編碼中的Windows-1252編碼內容

  1. new_doc = UnicodeDammit.detwingle(doc)  
  2. print(new_doc.decode("utf8"))  
  3. # ☃☃☃「I like snowmen!」  

在建立 BeautifulSoup 或 UnicodeDammit 對象前必定要先對文檔調用 UnicodeDammit.detwingle() 確保文檔的編碼方式正確.若是嘗試去解析一段包含Windows-1252編碼的UTF-8文檔,就會獲得一堆亂碼,好比: ☃☃☃「I like snowmen!」.

7 、其餘

  1. html_doc = """<html> 
  2.     <head> 
  3.         <title>The Dormouse's story</title> 
  4.     </head> 
  5. <body> 
  6.     <p class="title"><b>The Dormouse's story</b></p> 
  7.     <p class="story">Once upon a time there were three little sisters; and their names were 
  8.         <a href="http://example.com/elsie" class="sister" id="link1">Elsie</a>, 
  9.         <a href="http://example.com/lacie" class="sister" id="link2">Lacie</a> and 
  10.         <a href="http://example.com/tillie" class="sister" id="link3">Tillie</a>; 
  11.     </p> 
  12.         and they lived at the bottom of a well. 
  13.     <p class="story">...</p> 
  14. </body> 
  15. """  
  16. from bs4 import BeautifulSoup  
  17. ''''' 
  18. 以列表的形式返回 
  19. '''  
  20. soup = BeautifulSoup(html_doc, 'html.parser')  
  21. soup.select('title')  # title標籤  
  22. soup.select("p:nth-of-type(3)")  # 第三個p節點  
  23. soup.select('body a')  # body下的全部子孫a節點  
  24. soup.select('p > a')  # 全部p節點下的全部a直接節點  
  25. soup.select('p > #link1')  # 全部p節點下的id=link1的直接子節點  
  26. soup.select('#link1 ~ .sister')  # id爲link1的節點後面class=sister的全部兄弟節點  
  27. soup.select('#link1 + .sister')  # id爲link1的節點後面class=sister的第一個兄弟節點  
  28. soup.select('.sister')  # class=sister的全部節點  
  29. soup.select('[class="sister"]')  # class=sister的全部節點  
  30. soup.select("#link1")  # id=link1的節點  
  31. soup.select("a#link1")  # a節點,且id=link1的節點  
  32. soup.select('a[href]')  # 全部的a節點,有href屬性  
  33. soup.select('a[href="http://example.com/elsie"]')  # 指定href屬性值的全部a節點  
  34. soup.select('a[href^="http://example.com/"]')  # href屬性以指定值開頭的全部a節點  
  35. soup.select('a[href$="tillie"]')  # href屬性以指定值結尾的全部a節點  
  36. soup.select('a[href*=".com/el"]')  # 支持正則匹配
相關文章
相關標籤/搜索