BeautifulSoup4和lxml
這兩個庫主要是解析html/xml文檔,BeautifulSoup 用來解析 HTML 比較簡單,API非常人性化,支持CSS選擇器、
Python標准庫中的HTML解析器,也支持 lxml 的 XML解析器。關於BeautifulSoup和lxml的實例介紹如下:
一、BeautifulSoup4庫:
安裝:pip install beautifulsoup4 如果不寫4會默認安裝beautifulsoup3
數據結構、種類:Beautiful Soup將復雜HTML文檔轉換成一個復雜的樹形結構,每個節點都是Python對象,所有對象可
以歸納為4種: Tag NavigableString BeautifulSoup Comment 。
Tag: 即我們在寫網頁時所使用的標簽(如<a>超鏈接標簽)
NavigableString:簡單的說就是一種可以遍歷的字符串
搜索文檔:
使用requests庫獲取網頁源代碼:
1 import requests 2 from bs4 import BeautifulSoup 3 url = 'https://www.baidu.com/s?wd=python'
4 headers = { 5 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)
Chrome/64.0.3282.140 Safari/537.36',} 6 req = requests.session() 7 response = req.get(url, headers=headers, verify=False) 8 html_test = response.text
html_test就是獲取的一個網頁源代碼,它沒有爬取到JS的內容,所有可能和網頁內容不完全一致!
要解析文檔內容之前,先要用BeautifulSoup實例一個對象。如下,它的類型為<class 'bs4.BeautifulSoup'>
1 soup = BeautifulSoup(html_test, 'lxml') 2 print(soup, type(soup))
獲取標簽Tag: soup.'標簽名' 就可以匹配出第一個該標簽,它將會把第一次出現的該標簽完整的返回。
1 print(soup.span)
獲取標簽屬性:
1 print(type(soup.a)) 2 print(soup.a['id']) # 沒有該屬性會報錯
3 print(soup.a.attrs) # 輸出標簽的屬性和值
4 print(soup.a.get('id')) # 推薦使用get取屬性,沒有返回None
代碼的運行結構:
- <class 'bs4.element.Tag'>
- result_logo
- {'href': '/', 'id': 'result_logo', 'onmousedown': "return c({'fm':'tab','tab':'logo'})"}
- None
獲取文檔內容:獲取到標簽后(或者是soup),有幾種不同的方法獲取標簽里的內容,分別如下:
strings: 直接加 .strings 返回的是一個生成器,但是作者不能調用next()方法,查詢之后使用如下
1 a = soup.div.strings 2 a.__next__()
執行之后,可以再調用a.__next__(),這樣會將文本內容一條條地返回,但是大多數時候,這樣做是非常麻煩的。
基於搜索方法find()和find_all()去獲取文本內容:
字符串:soup.find_all('p') 獲取所有的P標簽,返回一個列表,soup.findl('p')只返回一個,類型為'bs4.element.Tag'
1 print(soup.find_all('p')[1])
2 print(soup.find_all('i', class_='c-icon-lidot')) # 限制屬性class
字符串里只能是標簽名,不能是其他內容,否則find_all()獲取的是空列表,find()獲取的是None
find_all()獲取的是列表元素也是類型為 'bs4.element.Tag' !
正則表達式:需要導入re,再用re.compile()根據包含的正則表達式的字符串創建模式對象。
1 import re 2 for i in soup.find_all(re.compile('span')): 3 print(i.text) # 會將span標簽內的所有文本內容返回
soup.find_all(re.compile('span'))的元素仍然是'bs4.element.Tag' !
列表:find_all方法也能接受列表參數,BeautifulSoup會將與列表中任一元素匹配的內容返回。
1 print(soup.find_all(['i', 'a'])) # 獲取所有的i標簽和a標簽
返回的數據類型為bs4.element.ResultSet,跟列表相似,可以通過索引取值且有序
方法(調用函數體):如果沒有合適的過濾器,我們也可以自定義一個方法,方法只接受一個元素參數。
1 def has_class_and_no_id(tag): 2 return tag.has_attr('class') and not tag.has_attr('id') 3 for tag in soup.find_all(has_class_and_no_id): 4 print(tag) 5 # soup.find_all(has_class_and_no_id)返回的數據類型是'bs4.element.ResultSet'
6 # 同上,類似列表,可以索引取值且無序!
基於select獲取:css選擇器,寫 CSS 時,標簽名不加任何修飾,類名前加.,id名前加#;返回值是一個列表
標簽名查找:soup.select('h3 a')取h3標簽下的a標簽;等價於soup.select('h3 > a')
1 for i in soup.select('h3 a'): 2 # text取內容時返回的是str字符串
3 result_1 = i.text 4 # get_text取內容時返回的是str字符串
5 result_2 = i.get_text() 6 # string返回的是NavigableString,沒有內容,將返回None
7 result_3 = i.string 8 # strings返回的是generator 如果內容為空,將返回None
9 result_4 = i.strings 10 print(result_1, type(result_1)) 11 print(result_2, type(result_2)) 12 print(result_3, type(result_3)) 13 print(result_4, type(result_4))
類名查找或id查找: soup.select('.c-gap-left-small') soup.select('#content_bottom')
組合查找: soup.select('a .c-gap-left-small')
搜索
