(三)BeautifulSoup

一、BeautifulSoup_demo

>>> from urllib.request import urlopen
>>> from bs4 import BeautifulSoup
>>> html = urlopen("http://www.pythonscraping.com/pages/page1.html")
>>> bs0bj = BeautifulSoup(html.read(),'lxml') 
# 加不加 .read() 好像沒差,但一次請求只能 read 一次
>>> bs0bj
<html>
<head>
<title>A Useful Page</title>
</head>
<body>
<h1>An Interesting Title</h1>
<div>
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</div>
</body>
</html>

#HTML節(jié)點附近的信息都可以提取
#獲取bs0bj里面的title標簽里的內(nèi)容
>>> print(bs0bj.title)
<title>A Useful Page</title>
>>> print(bs0bj.html.body.h1)
<h1>An Interesting Title</h1>
>>> print(bs0bj.div) 
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

#可以用節(jié)點不同的方法調(diào)用到同一標簽
>>> print(bs0bj.html.body.h1)
<h1>An Interesting Title</h1>
>>> print(bs0bj.body.h1)
<h1>An Interesting Title</h1>
>>> print(bs0bj.html.h1)
<h1>An Interesting Title</h1>

#get_text()去除標簽獲取純文本內(nèi)容
>>> print(bs0bj.html.body.h1.get_text())
An Interesting Title

解析器

解析器 使用方法 優(yōu)劣勢
Python標準庫 BeautifulSoup(markup, "html.parser") 速度適中,內(nèi)置標準庫
lxml HTML 解析器 BeautifulSoup(markup, "lxml") , BeautifulSoup(markup, "xml") 速度快,推薦這個
lxml XML 解析器 BeautifulSoup(markup, ["lxml", "xml"]) 速度快
html5lib BeautifulSoup(markup, "html5lib") 生成HTML5格式的文檔

二、基本元素

  • Tag 標簽
  • Name 標簽名
  • Attributes 屬性
  • NavigableString .string
  • Comment 注釋

三、遍歷功能

(一)下行遍歷

.contents
.children
.descendants

(二)上行遍歷

.parent
.parents

(三)平行遍歷

.next_sibling
.previous_sibling
.next_siblings
.previous_siblings

(四)find_all()

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

find_all方法搜索當前tag的所有tag子節(jié)點,并判斷是否符合過濾器的條件.這里有幾個例子(返回的是列表):

soup.find_all("title")

[<title>The Dormouse's story</title>]

soup.find_all("p", "title")

[<p class="title"><b>The Dormouse's story</b></p>]

soup.find_all("a")

[<a class="sister" id="link1">Elsie</a>,
<a class="sister" href="http://example.com/lacie"id="link2">Lacie</a>,
<a class="sister" id="link3">Tillie</a>]

soup.find_all(id="link2")

[<a class="sister" id="link2">Lacie</a>]

import re
soup.find(text=re.compile("sisters"))

u'Once upon a time there were three little sisters; and their names were\n'

1、name參數(shù) (name)

name參數(shù)可以查找所有名字為 name 的 tag,字符串對象會被自動忽略掉

soup.find_all("title")
[<title>The Dormouse's story</title>]

2、keyword參數(shù) (attr, **kwargs)

搜索 tag 標簽內(nèi)指定屬性的參數(shù) ,如 id='link2', href='href=re.compile("elsie")。class屬性要用 class_ ,因為 class 是類的關(guān)鍵字,見按 css 搜索。

soup.find_all(id='link2')
[<a class="sister" id="link2">Lacie</a>]
soup.find_all(href=re.compile("elsie"))
[<a class="sister" id="link1">Elsie</a>]

參數(shù)值可以為字符串,正則表達式,列表,True
下面的例子在文檔樹中查找所有包含 id 屬性的tag,無論 id 的值是什么:

soup.find_all(id=True)
[<a class="sister" id="link1">Elsie</a>,
<a class="sister" id="link2">Lacie</a>,
<a class="sister" id="link3">Tillie</a>]

也可以這樣

soup.find_all("a", {"class":"sister"})

a->標簽,{}->標簽的屬性和其對應(yīng)值

images = bs0bj.find_all("img", {"src":re.compile(".?")})
找出img標簽里src屬性里的所有東西re.compile(".
?")匹配所有

使用多個指定名字的參數(shù)可以同時過濾tag的多個屬性:

soup.find_all(href=re.compile("elsie"), id='link1')
[<a class="sister" id="link1">three</a>]

對于一些其他屬性,可以通過 find_all() 方法的 attrs 參數(shù)定義一個字典參數(shù)來搜索包含特殊屬性的tag:

data_soup.find_all(attrs={"data-foo": "value"})
[<div data-foo="value">foo!</div>]

3、按CSS搜索 (attr, **kwargs)

class_ 參數(shù)同樣接受不同類型的 過濾器 ,字符串,正則表達式,方法或 True :

soup.find_all("a", class_="sister")
[<a class="sister" id="link1">Elsie</a>,
<a class="sister" id="link2">Lacie</a>,
<a class="sister" id="link3">Tillie</a>]

也可以這樣搜索查找:

soup.find_all("a", {"class":"sister"})
[<a class="sister" id="link1">Elsie</a>,
<a class="sister" id="link2">Lacie</a>,
<a class="sister" id="link3">Tillie</a>]

4、text參數(shù) (text)

通過 text 參數(shù)可以搜索文檔中的字符串內(nèi)容,與 name 參數(shù)的可選值一樣,text 參數(shù)接受字符串,正則表達式,列表,True :

soup.find_all(text="Elsie")
[u'Elsie']
soup.find_all(text=["Tillie", "Elsie", "Lacie"])
[u'Elsie', u'Lacie', u'Tillie']
soup.find_all(text=re.compile("Dormouse"))

[u"The Dormouse's story", u"The Dormouse's story"]

當然也可以與其他參數(shù)混合使用來過濾 tag

soup.find_all("a", text="Elsie")
[<a class="sister" id="link1">Elsie</a>]

5、limit參數(shù) (limit)

該參數(shù)限制返回數(shù)量

soup.find_all("a", limit=2)
[<a class="sister" id="link1">Elsie</a>,
<a class="sister" id="link2">Lacie</a>]

6、recursive 參數(shù) (recursive)

遞歸,循環(huán)參數(shù)。調(diào)用tag的 find_all() 方法時,Beautiful Soup會檢索當前tag的所有子孫節(jié)點,如果只想搜索tag的直接子節(jié)點,可以使用參數(shù) recursive=False

7、像調(diào)用find_all()一樣調(diào)用tag

簡寫方法:

soup.find_all("a")
soup("a")

這兩行代碼也是等價的:

soup.title.find_all(text=True)
soup.title(text=True)

(五)find()

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

find()只返回一個結(jié)果
下面兩行代碼是等價的:

>>> soup.find_all('title', limit=1)
[<title>The Dormouse's story</title>]
>>> soup.find('title')
<title>The Dormouse's story</title>

唯一的區(qū)別是 find_all() 方法的返回結(jié)果是值包含一個元素的列表,而 find() 方法直接返回結(jié)果.
find_all() 方法沒有找到目標是返回空列表, find() 方法找不到目標時,返回 None .

(六)CSS選擇器

可以通過瀏覽器的審查元素的 copy selector 定位,Beautiful不支持Xpath
在 Tag 或 BeautifulSoup 對象的 .select() 方法中傳入字符串參數(shù),即可使用CSS選擇器的語法找到tag:

soup.select("title")
[<title>The Dormouse's story</title>]
soup.select("p nth-of-type(3)")
[<p class="story">...</p>]

通過CSS的類名查找:

soup.select(".sister")
[<a class="sister" id="link1">Elsie</a>,
<a class="sister" id="link2">Lacie</a>,
<a class="sister" id="link3">Tillie</a>]

soup.select("[class~=sister]")
[<a class="sister" id="link1">Elsie</a>,
<a class="sister" id="link2">Lacie</a>,
<a class="sister" id="link3">Tillie</a>]

通過tag的id查找:

soup.select("#link1")
[<a class="sister" id="link1">Elsie</a>]

soup.select("a#link2")
[<a class="sister" id="link2">Lacie</a>]

通過是否存在某個屬性來查找:

soup.select('a[href]')
[<a class="sister" id="link1">Elsie</a>,
<a class="sister" id="link2">Lacie</a>,
<a class="sister" id="link3">Tillie</a>]

通過屬性的值來查找:

soup.select('a[href="http://example.com/elsie"]')
[<a class="sister" id="link1">Elsie</a>]

soup.select('a[href^="http://example.com/"]')
[<a class="sister" id="link1">Elsie</a>,
<a class="sister" id="link2">Lacie</a>,
<a class="sister" id="link3">Tillie</a>]

soup.select('a[href$="tillie"]')
[<a class="sister" id="link3">Tillie</a>]

soup.select('a[href*=".com/el"]')
[<a class="sister" id="link1">Elsie</a>]

(七)get_text()

如果只想得到tag中包含的文本內(nèi)容,那么可以嗲用 get_text() 方法,這個方法獲取到tag中包含的所有文版內(nèi)容包括子孫tag中的內(nèi)容,并將結(jié)果作為Unicode字符串返回:

>>> markup = '<a >\nI linked to <i>example.com</i>\n</a>'
>>> soup = BeautifulSoup(markup, 'lxml')
>>> soup.get_text()
'\nI linked to example.com\n'
>>> soup.i.get_text()  #獲取 i 標簽內(nèi)的文本
'example.com'

可以通過參數(shù)指定tag的文本內(nèi)容的分隔符:

soup.get_text("|")
'\nI linked to |example.com|\n'

還可以去除獲得文本內(nèi)容的前后空白:

soup.get_text("|", strip=True)
'I linked to|example.com'

或者使用 .stripped_strings 生成器,獲得文本列表后手動處理列表:

[text for text in soup.stripped_strings]
['I linked to', 'example.com']

(八)對 ResultSet 的處理

1、.get_text()
2、.get("href")
3、["href"]
3、.find('span').string
4、.text

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容