python課程設計筆記(五) ----Resuests+BeautifulSoup (爬蟲入門)
官方參考文件(中文版):
requests:http://docs.python-requests.org/zh_CN/latest/user/quickstart.html
beautifulsoup:https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/
這篇部落格只是簡單介紹思路,建議直接閱讀上面的官方文件
目標
從一個HTML或XML檔案中提取資料,節省人工的時間。我這裡提取一個html頁面(https://www.zxzhijia.com/tuce/f1301_h_m )的所有圖片。
需要安裝的:requests
- requests 安裝: pip install requests
- beautifulsoup 安裝:pip install beautifulsoup4
- lxml解析器安裝:pip install lxml
requests: 獲取某個URL的內容。(這裡只用到了獲取HTML的內容)
Beautiful Soup :從HTML或XML檔案中提取資料。
lxml解析器:beautifulsoup提取資料時用到。
requests獲得的HTML內容要用lxml解析,用BeautifulSoup提取。
效果演示:
爬取的HTML頁面:https://www.zxzhijia.com/tuce/f1301_h_m,要爬取七張裝修案例的圖片,把圖片路徑放入MySQL資料庫
#爬取裝修圖片 import requests import re #正則表示式from bs4 import BeautifulSoup #利用requests獲取html網頁內容 res=requests.get("https://www.zxzhijia.com/tuce/f1301_h_m") #傳給beautifulsoup,指定用lxml解析器解析 soup = BeautifulSoup(res.text, 'lxml') #獲得指定7個img影象 img_src=soup.find(name='div',class_='waterfall').findAll(name="img",src=re.compile("img"),limit=7) for img in img_src: img=img['src'] #抓取src屬性的屬性值(圖片的href)print(img)
詳解beautifulsoup的作用:
res=requests.get("https://www.zxzhijia.com/tuce/f1301_h_m")
soup = BeautifulSoup(res.text, 'lxml')
這兩句之後soup裡面就有html的內容了。
BeautifulSoup會將複雜HTML文件轉換成一個複雜的樹形結構,每個節點都是Python物件,所有物件可以歸納為4種: Tag , NavigableString , BeautifulSoup , Comment。
樹形結構很關鍵,比如一段這樣的html,(下面都以這段為例):
<html>
<head>
<title>測試介面</title>
</head>
<body>
<div>
<ul class="c">
<li class="c">beautifulsoup</li>
<li><span>span裡面的字</span>span外的字</li>
<li><a href="#">連結</a></li>
</ul>
</div>
</body>
beautifulsoap會生成文件樹,我把它畫出來 了:
(直接從ul開始畫)--就已經這麼麻煩了
一個紅框稱為一個節點!!仔細看字串也是一個節點!!
分析文件樹中的節點(紅框框):
- Tag型別:是最普通的節點,看圖中這些,一個框叫一個Tag物件,不是”a””div”。看最上面的這個Tag物件,它的name(名字)是“ul”,它擁有的attributes(屬性)是“class”,而這個屬性的值為“c”。
- NavigableString型別:普通字串也一種節點型別。
- BeautifulSoup 型別:表示的是一個文件的全部內容。大部分時候,可以把它當作 Tag 物件。就是一個HTML轉換成樹以後最上方的節點,比<html>..</html>還高。
- Comment型別:註釋,不多講。
操作和遍歷一個Tag物件的子節點
Beautiful Soup提供了許多操作和遍歷子節點的屬性。
1 獲取單個Tag物件
獲取單個tag: tag = soup.tag的名字 ----------這種方法只取當前名字的第一個Tag
import requests from bs4 import BeautifulSoup response=requests.get("http://localhost/test/test.html") soup = BeautifulSoup(response.text, 'lxml') tag=soup.li print(tag.name) #li print(tag.string) #beautifulsoup
獲取單個tag物件裡面的子tag物件: soup.tag名.tag名
2 獲取一堆tag物件,用find_all()方法 !!注意,返回的時子節點列表,獲得tag物件或navigatestring物件需要遍歷這個列表
find_all( name , attrs , recursive , text , **kwargs )
搜尋當前tag的所有tag子節點,並判斷是否符合條件,返回的是一堆子節點。
name:tag的名字,可以是字串('a')、正則表示式(瞭解re的使用),列表['a','div'],或者 True(全部) .
attrs={‘屬性名a’,‘屬性值b’} :搜尋子節點中擁有屬性a,且a="b"的。
一般寫法:可以直接寫成 屬性名a=‘屬性值b’ id='aaa' ,多個時用”,”隔開就可以。
對於css屬性class 需要寫成 _class="名稱",這樣單個多個都可以匹配。 不能寫成class=" ",因為”class"時python保留字會有語法錯誤,寫成attrs 時,如果class=“a b" ,就算只想搜尋a,也必須寫{”class":"a b"}才能搜尋到這個tag,必須要完全匹配,所以不適合這麼寫。
text :tag裡面夾的string內容,soup.find_all(text=["Tillie", "Elsie", "Lacie"])
limit:可以使用 limit 引數限制返回結果的數量。當搜尋到的結果數量達到 limit 的限制時,就停止搜尋返回結果。文件樹中有3個tag符合搜尋條件,但結果只返回了2個,因為我們限制了返回數量:
soup.find_all("a", limit=2)
recursive:呼叫tag的 find_all() 方法時,Beautiful Soup會檢索當前tag的所有子孫節點,如果只想搜尋tag的直接子節點,可以使用引數 recursive=False
tag=soup.find_all("li") tag=soup.find_all(re.compile("l")) tag=soup.find_all(name='li',class_='c') tag=soup.find_all('li',attrs={'class','c'}) tag=soup.find_all(True) tag=soup.fine_all('li',limit=2)
find()方法:!!注意,獲得的是一個子節點,就是tag物件或navigatestring物件,可以直接使用.name .string ['屬性名']
用法和find_all方法一樣。唯一的區別是 find_all() 方法的返回結果是值包含一個元素的列表,而 find() 方法直接返回結果.
3 獲取tag物件的屬性值和tag物件裡面的字串內容(<div>XXX</div>中的XXX)
屬性值:
tag['屬性名']
字串內容:
.string
一個tag物件中間的字串,可以直接tag.string
如果tag只有一個 NavigableString 型別子節點,那麼這個tag可以使用 .string 得到子節點:tag.string
如果一個tag僅有一個子節點,那麼這個tag也可以使用 .string 方法,輸出結果與當前唯一子節點的 .string 結果相同.
如果tag有超過一個子節點就不能直接.string,只會輸出None
舉例:遍歷find_all()獲得的list:
tags=soup.find_all('li') for item in tags: print(item.string) #beautifulsoup #None #連結
4 遍歷一個tag物件的所有子節點
.contents 一個tag物件的所有直接子節點組成的list
迴圈遍歷直接子節點 .children
for child in tag.children: print(child)
迴圈遍歷所有子節點 .descendants
for child in tag.descendants: print(child)