python網絡爬蟲開發實戰之網頁數據的解析提取

目錄

1 XPath的使用

1.1 XPath概覽

1.2? XPath常用規則

1.3 準備工作

1.4 實例引入

1.5 所有節點

1.6 節點

1.7 父節點

1.8 屬性匹配

1.9 文本獲取

1.10 屬性獲取

1.11 屬性多值匹配

1.12 多屬性匹配

1.13 按序選擇

1.14?節點軸選擇

2 Beautiful Soup

2.1 簡介

2.2 解析器

2.3 準備工作

2.4 基本使用

2.5 節點選擇器

2.6 提取信息

2.6.1 獲取名稱

2.6.2 獲取屬性

2.6.3 獲取內容

2.6.4 嵌套選擇

2.7 關聯選擇

2.7.1 子節點和子孫節點

2.7.2 父節點和祖先節點

2.7.3 兄弟節點

2.7.4 提取信息

2.8 方法選擇器

2.8.1 find_all

2.8.2 name

2.8.3 attrs

2.8.4 text

2.8.5 find

2.8.6?其他查詢方法

2.9 CSS選擇器

2.9.1 嵌套選擇

2.9.2 獲取屬性

2.9.3 獲取文本

2.9.4?總結

3 pyquery

3.1 準備工作

3.2 初始化

3.2.1 字符串初始化

3.2.2 URL初始化

3.2.3 文件初始化

3.3 基本CSS選擇器

3.4 查找節點

3.4.1 子節點

3.4.2 父節點

3.4.3 兄弟節點

3.5 遍歷節點

3.5.1?獲取屬性

3.5.2?獲取文本

3.6 節點操作

3.6.1 addClass和removeClass

3.6.2 attr、text和html

3.6.3 remove

3.7 偽類選擇器

4 parsel 的使用

4.1 提取數據?

4.2 提取文本內容

4.3?提取特定的文本內容

4.4?提取特定的屬性值

4.5 提取屬性

4.6?正則提取


對于網頁的節點來說,可以定義id、class或其他屬性,而且節點之間還有層次關系,在網頁中可以通過XPath或CSS選擇器來定位一個或多個節點。相關的解析庫也比較多,包括lxml、Beautiful Soup、pyquery、parsel等。

1 XPath的使用

XPath的全程是XML Path Language,即XML路徑語言,用來在XML文檔中查找信息。雖然最初是用來搜尋XML文檔的,但同樣適用于HTML文檔的搜索。

1.1 XPath概覽

包含許多定位的節點。

1.2? XPath常用規則

XPath的一個常用匹配規則://title[@lang='eng'],代表選擇所有名稱為title,同時屬性為lang的值為eng的節點。

1.3 準備工作

使用lxml庫,利用XPath對HTML進行解析。

pip install lxml

1.4 實例引入

from lxml import etree
text='''
<div><ul><li class='item-0'><a href='link1.html'>first item</a></li><li class='item-1'><a href='link2.html'>second item</a></li><li class='item-inactive'><a href='link3.html'>third item</a></li><li class='item-1'><a href='link4.html'>fourth item</a></li><li class='item-0'><a href='link5.html'>fifth item</a></ul>
</div>
'''
html=etree.HTML(text)
result=etree.tostring(html)
print(result.decode('utf-8'))

<html><body><div><ul><li class='item-0'><a href='link1.html'>first item</a></li><li class='item-1'><a href='link2.html'>second item</a></li><li class='item-inactive'><a href='link3.html'>third item</a></li><li class='item-1'><a href='link4.html'>fourth item</a></li><li class='item-0'><a href='link5.html'>fifth item</a></li></ul>
</div>
</body></html>

from lxml import etree
html=etree.parse('./test.html',etree.HTMLParser())
result=etree.tostring(html)
print(result.decode('utf-8'))

1.5 所有節點

一般會用以//開頭的XPath規則,來選取所有符合要求的節點。

from lxml import etree
html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//*')
print(result)

*代表匹配的所有節點,也就是獲取整個HTML文本中的所有節點。從運行結果可以看到,返回形式是一個列表,其中每個元素是element類型,類型后面跟著節點的名稱。

如果想要獲取所有的li節點,實例如下:

from lxml import etree
html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//li')
print(result)
print(result[0])

從運行結果也可以看出,提取結果是一個列表,其中每個元素都是element類型,如果想要取出其中一個對象,可以直接用中括號加索引獲取,如[0]。

1.6 節點

通過/或//即可查找元素的子節點或子孫節點。如果想選擇li節點的所有直接子節點a,則可以通過以下代碼實現:

from lxml import etree
html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//li//a')
print(result)

如果要獲取節點的所有子孫節點,可以使用//。

from lxml import etree
html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//ul//a')
print(result)

但是如果這里用//ul/a,就無法獲取任何結果了,因為/用于獲取直接子節點,但ul節點下沒有直接的a子節點,只有li節點。

1.7 父節點

通過連續的/或//可以查找子節點或子孫節點,如果指導子節點,查找父節點,可以通過..實現。

例如,首先選中href屬性為link4.html的a節點,然后獲取其父節點,在獲取父節點的class屬性,代碼如下:

from lxml import etree
html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//a[@href='link4.html]'/../@class')
print(result)

運行結果如下:

['item-1']

此外,也可以通過parent::獲取父節點,代碼如下:

from lxml import etree
html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//a[@href='link4.html]'/parent::*/@class')
print(result)

1.8 屬性匹配

在選取節點的時候,還可以使用@符號實現屬性過濾。例如,要選取class屬性為item-0的li節點,可以通過以下代碼實現:

from lxml import etree
html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//li[@class='item-0']')
print(result)

1.9 文本獲取

用XPath中的text方法可以獲取節點中的文本,接下來嘗試獲取前面li節點中的文本,代碼如下:

from lxml import etree
html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//li[@class='item-0']/text()')
print(result)

from lxml import etree
html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//li[@class='item-0']/a/text()')
print(result)

如果使用//,能夠獲取到的結果,代碼:

from lxml import etree
html=etree.parse('./test.html',etree.HTMLParser())
result=html.xpath('//li[@class='item-0']//text()')
print(result)

1.10 屬性獲取

利用@符號,可以獲取所有li節點下所有a節點的href屬性:

from lxml import etree
html = etree.parse('./test.html',etree.HTMLParser())
result = html.xpath('//li/a/@href')
print(result)

通過@href獲取節點的href屬性。此處與屬性匹配方法不同,屬性匹配是用中括號加屬性名和值來限定某個屬性,如[@href="link1.html"],此處的@href是指獲取節點的某個屬性。

1.11 屬性多值匹配

有時候,某些節點的某個屬性可能有多個值,例如:

from lxml import etree
text='''
<li class='li li-first'><a href='link.html'>first item</a></li>
'''
html=etree.HTML(text)
result=html.xpath('//li[@class='li']/a/text()')
print(result)

這里的HTML文本中li節點的class屬性就有兩個值:li和li-frist,需要用到contains方法,代碼如下:

from lxml import etree
text='''
<li class='li li-first'><a href='link.html'>first item</a></li>
'''
html=etree.HTML(text)
result=html.xpath('//li[contains(@class,'li')]/a/text()')
print(result)

上面的contains,給第一個參數傳入屬性名稱,第二個參數傳入屬性值,只要傳入的屬性包含傳入的屬性值,就可以完成匹配。

1.12 多屬性匹配

根據多個屬性確定一個節點,這時需要同時匹配多個屬性,運算符and用于連接多個屬性,代碼如下:

from lxml import etree
text='''
<li class='li li-first'><a href='link.html'>first item</a></li>
'''
html=etree.HTML(text)
result=html.xpath('//li[contains(@class='li') and @name='item']/a/text()')
print(result)

此外,還有許多運算符:

1.13 按序選擇

在選擇節點時,某些屬性可能同時匹配了多個節點,但我么只想要其中的某一個,可以使用往中括號中傳入索引的方法獲取特定次序的節點,代碼:

from lxml import etree
text='''
<div><ul><li class='item-0'><a href='link1.html'>first item</a></li><li class='item-1'><a href='link2.html'>second item</a></li><li class='item-inactive'><a href='link3.html'>third item</a></li><li class='item-1'><a href='link4.html'>fourth item</a></li><li class='item-0'><a href='link5.html'>fifth item</a></ul>
</div>
'''
html=etree.HTML(text)
result=html.xpath('//li[1]/a/text()')
print(result)
result=html.xpath('//li[last()]/a/text()')
print(result)
result=html.xpath('//li[position()<3]/a/text()')
print(result)
result=html.xpath('//li[last()-2]/a/text()')
print(result)

注:這里的代碼序號以1開頭,而不是0。last()表示最后,position表示位置。

1.14?節點軸選擇

XPath提供了許多節點軸的選擇方法,包括獲取子元素、兄弟元素、父元素、祖先元素等,代碼:

from lxml import etree
text ='''
<div><ul><li class="item-0"><a href="link1.html"><span>first item</span></a></li><li class="item-1"><a href_"link2.html">second item</a></li><li class="item-inactive"><a href="link3.html">third item</a></li><li class="item-1"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></ul>
</div>
'''
html = etree.HTML(text)
result = html.xpath('//li[1]/ancestor::*')
print(result)
result = html.xpath('//li[1]/ancestor::div')
print(result)
result = html.xpath('//li[1]/attribute::*')
print(result)
result = html.xpath('//li[1]/child::a[@href="link1.html"]')
print(result)
result = html.xpath('//li[1]/descendant::span')
print(result)
result = html.xpath('//li[1]/following::*[2]')
print(result)
result = html.xpath('//li[1]/following-sibling::*')
print(result)

第一次選擇,調用ancestor軸,可以獲取所有祖先節點,其后需要跟兩個冒號,然后是節點的選擇器(*表示匹配所有節點)。返回的是第一個li節點的所有祖先節點,包括html、body、div和ul。

第二次選擇,加了限定條件。

第三次選擇,調用了attribute軸,可以獲取所有屬性值,其后跟的選擇器還是*,代表獲取節點的所有屬性,返回值就是li節點的所有屬性值。

第四次選擇,調用了child軸,可以獲取所有直接子節點,這里的限定條件指的事選取href屬性為link.html的a節點。

第五次選擇,調用了descendant軸,可以獲取所有子孫節點,這里的限定條件指獲取span節點。

第六次選擇,調用了following軸,獲取當前節點之后的所有節點,這里的限定條件指獲取了第二個后續節點。

第七次選擇,調用了following-sibling軸,獲取當前節點之后的所有同級節點。

2 Beautiful Soup

2.1 簡介

python的一個html或xml的解析庫,用它可以方便地從網頁中提取數據。

2.2 解析器

通過上表,lxml解析器具有解析html和xml的功能。

使用lxml解析器,只需要在初始化時,把第二個參數修改為lxml即可:

from bs4 import BeautifulSoup
soup=BeautifulSoup('<p>Hello</p>','lxml')
print(soup.p.string)

2.3 準備工作

pip3 install beautifulsoup4

2.4 基本使用

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/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>
"""
from bs4 import BeautifulSoup
soup=BeautifulSoup(html,'lxml')
print(soup.prettify())
print(soup.title.string)

2.5 節點選擇器

直接調用節點的名稱即可選擇節點,然后調用string屬性就可以得到節點內的文本了。

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/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>
"""from bs4 import BeautifulSoup
soup=BeautifulSoup(html,'lxml')
print(soup.title)
print(type(soup.title))
print(soup.title.string)
print(soup.head)
print(soup.p)

2.6 提取信息

2.6.1 獲取名稱

利用name屬性可以獲取節點的名稱。

print(soup.title.name)

2.6.2 獲取屬性

一個節點可能有多個屬性,例如id和class,選擇某個節點元素后,可以調用attrs獲取其所有屬性:

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

print(soup.p['name'])
print(soup.p['Class'])

2.6.3 獲取內容

print(soup.p.string)

2.6.4 嵌套選擇

html ='''
<html><head><title>The Dormouse's story</title></head>
<body>
'''
from bs4 import BeautifulSoup
soup=BeautifulSoup(html,'lxml')
print(soup.head.title)
print(type(soup.head.title))
print(soup.head.title.string)

2.7 關聯選擇

在做選擇的過程中,需要先選中某一個節點,然后再以這個節點為基準選子節點、父節點、兄弟節點等。

2.7.1 子節點和子孫節點

選取節點之后,如果想要獲取它的直接子節點,可以調用contens屬性,代碼:

<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 href="http://example.com/elsie" class="sister" id="link1"><span>Elsie</span></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>
'''
from bs4 import BeautifulSoup
soup=BeautifulSoup(html,'lxml')
print(soup.p.contents)

可以看到,返回結果是列表形式:p節點里既包括文本,又包括節點。列表中的每個元素都是p節點的直接子節點。像第一個a節點里面包括的span節點,相當于孫子節點,但是返回結果并沒有把span節點單獨選出來。所以說,contens屬性得到的結果是直接子節點組成的列表。

同樣,可以調用children屬性得到相應的結果:

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.p.children)
for i, child in enumerate(soup.p.children):print(i, child)

這里掉用children屬性來選擇,返回結果是生成器類型,利用for循環輸出了相應內容。

如果要得到所有的子孫節點,則可以調用descendants屬性:

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.p.descendants)
for i, child in enumerate(soup.p.descendants):print(i, child)

2.7.2 父節點和祖先節點

如果要獲取某個節點元素的父節點,可以掉用parents屬性:

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 href="http://example.com/elsie" class="sister" id="link1"><span>Elsie</span></a></p><p class="story">...</p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.a.parent)

這里選的是第一個a節點的父節點元素,a節點的父節點是p節點,所以輸出結果是p節點及其內部內容。

如果想要獲取所有祖先節點,可以調用parents屬性:

html = """
<html><body><p class="story"><a href="http://example.com/elsie" class="sister" id="link1"><span>Elsie</span></a></p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(type(soup.a.parents))
print(list(enumerate(soup.a.parents)))

2.7.3 兄弟節點

如果想要獲取同級節點,也就是兄弟節點:

html = """
<html><body><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"><span>Elsie</span></a>Hello<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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print('Next Sibling', soup.a.next_sibling)
print('Prev Sibling', soup.a.previous_sibling)
print('Next Siblings', list(enumerate(soup.a.next_siblings)))
print('Prev Siblings', list(enumerate(soup.a.previous_siblings)))

可以看到,這里調用了4個屬性。next_sibling和previous_sibling分別用于獲取節點的下一個和上一個兄弟節點,next_siblings和previous_siblings則分別返回后面和前面的所有兄弟節點。

2.7.4 提取信息

關聯元素的信息獲取,代碼如下:

html = """
<html><body><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">Bob</a><a href="http://example.com/lacie" class="sister" id="link2">Lacie</a></p>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print('Next Sibling:')
print(type(soup.a.next_sibling))
print(soup.a.next_sibling)
print(soup.a.next_sibling.string)
print('Parent:')
print(type(soup.a.parents))
print(list(soup.a.parents)[0])
print(list(soup.a.parents)[0].attrs['class'])

如果返回結果是單個節點,可以直接掉用string、attrs等屬性獲取其文本和屬性;如果返回結果是包含多個節點的生成器,則可以現將結果轉為列表,再從中取出某個元素,之后調用string、attrs等屬性即可獲取對應節點的文本和屬性。

2.8 方法選擇器

利用以下方法可以靈活查詢相應參數:

2.8.1 find_all

查詢所有符合條件的元素,可以給它傳入一些屬性或文本得到符合條件的元素,API如下:

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

2.8.2 name

根據name參數查詢元素,代碼如下:

html = '''
<div class="panel"><div class="panel-heading"><h4>Hello</h4></div><div class="panel-body"><ul class="list" id="list-1"><li class="element">Foo</li><li class="element">Bar</li><li class="element">Jay</li></ul><ul class="list list-small" id="list-2"><li class="element">Foo</li><li class="element">Bar</li></ul></div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(name='ul'))
print(type(soup.find_all(name='ul')[0]))

調用find_all方法,向其中傳入name參數,其參數值為ul,意思是查詢所有ul節點。

列表中每個元素都是bs4.element.Tag類型,依然可以進行嵌套查詢。代碼:

for ul in soup.find_all(name='ul'):print(ul.find_all(name='li'))

返回結果還是列表類型,列表中每個元素依然是Tag類型。接下來遍歷每個li節點,獲取文本內容:

for ul in soup.find_all(name='ul'):print(ul.find_all(name='li'))for li in ul.find_all(name='li'):print(li.string)

2.8.3 attrs

除了根據節點名查詢,也可以傳入一些屬性進行查詢:

html = '''
<div class="panel"><div class="panel-heading"><h4>Hello</h4></div><div class="panel-body"><ul class="list" id="list-1"><li class="element">Foo</li><li class="element">Bar</li><li class="element">Jay</li></ul><ul class="list list-small" id="list-2"><li class="element">Foo</li><li class="element">Bar</li></ul></div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(attrs={'id':'lisy-1'}))
print(soup.find_all(attrs={'name':'elements'}))

另一種查詢方式:

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(id="lisy-1"))
print(soup.find_all(class="elements"))

2.8.4 text

text參數可以用來匹配節點的文本,其傳入形式可以是字符串,也可以是正則表達式形式,代碼:

import re
html='''
<div class="panel"><div class="panel-body"><a>Hello, this is a link</a><a>Hello, this is a link, too</a></div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find_all(text=re.compile('link')))

這里有兩個a節點,其內部包含文本信息,find_all方法中傳入text參數,該參數為正則表達式,返回結果是由所有與正則表達式相匹配的節點文本組成的元素。

2.8.5 find

find方法可以查詢符合條件的元素,但是find方法返回的是單個元素,也就是第一個匹配的元素,而find_all會返回由所有匹配的元素組成的列表,代碼:

html='''
<div class="panel"><div class="panel-heading"><h4>Hello</h4></div><div class="panel-body"><ul class="list" id="list-1"><li class="element">Foo</li><li class="element">Bar</li><li class="element">Jay</li></ul><ul class="list list-small" id="list-2"><li class="element">Foo</li><li class="element">Bar</li></ul></div>
</div>
'''
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
print(soup.find(name='ul'))
print(type(soup.find(name='ul')))
print(soup.find(class_='list'))

2.8.6?其他查詢方法

2.9 CSS選擇器

使用CSS選擇器,只需要調用select方法,傳入相應的CSS選擇器即可,代碼:

html = '''
<div class="panel"><div class="panel-heading"><h4>Hello</h4></div><div class="panel-body"><ul class="list" id="list-1"><li class="element">Foo</li><li class="element">Bar</li><li class="element">Jay</li></ul><ul class="list list-small" id="list-2"><li class="element">Foo</li><li class="element">Bar</li></ul></div>
</div>
'''
from bs4 import BeautifulSoupsoup = BeautifulSoup(html, 'lxml')
print(soup.select('.panel .panel-heading'))
print(soup.select('ul li'))
print(soup.select('#list-2 .element'))
print(type(soup.select('ul')[0]))

返回結果均是符合css選擇器的節點組成的列表,例如select('ul li')表示選擇所有ul節點下面的所有li節點,結果便是所有li節點組成的列表。

2.9.1 嵌套選擇

例如,先選擇所有ul節點,再遍歷每個ul節點,選擇其li節點,代碼:
?

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
for ul in soup.select('ul'):print(ul.select('li'))

2.9.2 獲取屬性

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
for ul in soup.select('ul'):print(ul['id'])print(ul.attrs['id'])

2.9.3 獲取文本

from bs4 import BeautifulSoup
soup = BeautifulSoup(html, 'lxml')
for li in soup.select('li'):print('Get Text:', li.get_text())print('String:', li.string)

2.9.4?總結

3 pyquery

功能更強大的庫

3.1 準備工作

pip3 install pyquery

3.2 初始化

在用pyquery庫解析html文本的時候,需要先將其初始化為一個PyQuery對象。

3.2.1 字符串初始化

html = '''
<div><ul><li class="item-0">first item</li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li><li class="item-1 active"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul></div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
print(doc('li'))

3.2.2 URL初始化

初始化的參數除了能以字符串形式傳遞,還能是網頁的url,此時只需要指定PyQuery對象的參數url即可:

from pyquery import PyQuery as pq
doc = pq(url='https://cuiqingcai.com')
print(doc('title'))

下面代碼實現的功能是相同的:

from pyquery import PyQuery as pq
import requests
doc = pq(requests.get('https://cuiqingcai.com').text)
print(doc('title'))

3.2.3 文件初始化

還可以傳遞本地的文件名,此時將參數指定為filename即可:

from pyquery import PyQuery as pq
doc = pq(filename = 'demo.html')
print(doc('li'))

3.3 基本CSS選擇器

實例:

html = '''
<div><ul><li class="item-0">first item</li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li><li class="item-1 active"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul></div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
print(doc('#container .list li'))
print(type(doc('#container .list li')))

運行結果如下:

采用直接遍歷獲取的節點,調用text方法,可以直接獲取節點的文本內容,代碼:

for item in doc('#container .list li').items():print(item.text())

3.4 查找節點

3.4.1 子節點

查找子節點時,需要用到find方法,其參數時css選擇器,代碼:

from pyquery import PyQuery as pq
doc = pq(html)
items = doc('.list')
print(type(items))
lis = items.find('li')
print(type(lis))
print(lis)

這里我們選擇class為list的節點,然后調用find方法,并將其傳入css選擇器,選取其內部的li節點,最后打印輸出。

此外,如果想只查找子節點,可以用children方法:

lis = items.children()
print(type(lis))
print(lis)

如果要篩選所有子節點中符合條件的節點,例如想篩選出子節點中class為active的節點,則可以向children方法傳入css選擇器.active,代碼:

lis = items.children('.active')
print(lis)

3.4.2 父節點

用parent方法獲取某個節點的父節點,代碼:

html = '''
<div class='wrap'><div id='container'><ul class="list"><li class="item-0">first item</li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li><li class="item-1 active"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul></div>
</div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
print(doc('.list'))
container = items.parent()
print(type(container))
print(container)

這里我們首先用.list選取class為list的節點,然后調用parent方法得到其父節點,其類型依然是PyQuery。

如果想獲取某個祖先節點,可以用parents方法:

如果想要篩選某個祖先節點,可以向parents方法傳入css選擇器,就會返回祖先節點中符合css選擇器的節點:

parent = items.parents('.wrap')
print(parent)

3.4.3 兄弟節點

獲取兄弟節點可以使用siblings方法:

from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.list .item-0.active')
print(li.siblings())

這里首先選擇class為list的節點內部的class為item-0和active的節點,也就是第三個li節點。

如果要篩選某個兄弟節點,依然可以向siblings方法中傳入css選擇器,這樣就能從所有兄弟節點中挑選出符合條件的節點:

from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.list .item-0.active')
print(li.siblings('.active'))

運行結果如下:

3.5 遍歷節點

pyquery庫的選擇結果可能是多個節點,也可能是單個節點,類型都是pyquery類型,但不像beautiful soup那樣返回列表。

如果結果是單個節點,既可以直接打印輸出,也可以直接轉成字符串:

from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.item-0.active')
print(li)
print(str(li))

如果結果是多個節點,就可以通過items方法遍歷獲取:

from pyquery import PyQuery as pq
doc = pq(html)
lis = doc('li').items()
print(type(lis))
for li in lis:print(li,type(li))

需要獲取的信息一般包括屬性和文本:

3.5.1?獲取屬性

html = '''
<div class='wrap'><div id='container'><ul class="list"><li class="item-0">first item</li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li><li class="item-1 active"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul></div>
</div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
a = doc('.item-0.active')
print(a,type(a))
print(a.attr('href'))

此外,也可以通過調用attr屬性來獲取屬性值:

print(a.attr.href)

如果選中的多個元素,調用attr方法,智慧得到第一個節點的屬性:

a = doc('a')
print(a,type(a))
print(a.attr('href'))
print(a.attr.href)

如果想要獲取a節點的所有屬性,需要遍歷:

from pyquery import PyQuery as pq
doc = pq(html)
a = doc('a')
for item in a.items():print(item.attr('href'))

3.5.2?獲取文本

獲取節點之后的另一個主要操作就是獲取其內部的文本,調用text方法實現:

html = '''
<div class='wrap'><div id='container'><ul class="list"><li class="item-0">first item</li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li><li class="item-1 active"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul></div>
</div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
a = doc('.item-0.active')
print(a)
print(a.text)

如果想要獲取節點內部的html文本,需要用到html方法:

from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.item-0.active')
print(li)
print(li.html())

如果我們選中的是多個節點,html方法返回的是第一個li節點內部的html文本,而text返回了所有li節點內部的純文本,各節點內部中間用一個空格分隔開,返回結果是一個字符串。

html = '''
<div class='wrap'><div id='container'><ul class="list"><li class="item-0">first item</li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li><li class="item-1 active"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul></div>
</div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('li')
print(li.html())
print(li.text())
print(type(li,text())

3.6 節點操作

pyquery庫提供了一系列方法對節點進行動態修改,例如為某個節點添加一個class,移除某個節點等。

3.6.1 addClass和removeClass

html = '''
<div class='wrap'><div id='container'><ul class="list"><li class="item-0">first item</li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li><li class="item-1 active"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul></div>
</div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.item-0.active')
print(li)
li.removeClass('active')
print(li)
li.addClass('active')
print(li)

3.6.2 attr、text和html

html = '''
<ul class="list"><li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li></ul>
'''
from pyquery import PyQuery as pq
doc = pq(html)
li = doc('.item-0.active')
print(li)
li.attr('name','link')
print(li)
li.text('changed item')
print(li)
li.html('<span>changed item</span>')
print(li)

3.6.3 remove

html = '''
<div class='wrap'>Hello,world<p>This is a paragraph.</p>
</div>
'''
from pyquery import PyQuery as pq
doc = pq(html)
wrap = doc('.wrap')
print(wrap.text())

3.7 偽類選擇器

html = '''
<div class='wrap'><div id='container'><ul class="list"><li class="item-0">first item</li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li><li class="item-1 active"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul></div>
</div>
'''
from pyquery import PyQuery as pq
doc = pq(html)# 選擇第一個 li 節點
li = doc('li:first-child')
print("第一個 li 節點:")
print(li)
print()# 選擇最后一個 li 節點
li = doc('li:last-child')
print("最后一個 li 節點:")
print(li)
print()# 選擇第奇數個 li 節點
li = doc('li:nth-child(odd)')
print("第奇數個 li 節點:")
print(li)
print()# 選擇第偶數個 li 節點
li = doc('li:nth-child(even)')
print("第偶數個 li 節點:")
print(li)
print()# 選擇包含文本 "second" 的 li 節點
li = doc('li:contains("second")')
print('包含文本 "second" 的 li 節點:')
print(li)
print()# 選擇類名為 "active" 的 li 節點
li = doc('li.active')
print('類名為 "active" 的 li 節點:')
print(li)
print()# 選擇有子元素 a 的 li 節點
li = doc('li:has(a)')
print('有子元素 a 的 li 節點:')
print(li)
print()

4 parsel 的使用

4.1 提取數據?

使用 selector.css('.item-0') 提取所有類名為 item-0<li> 元素。使用 selector.xpath('//li[contains(@class, "item-0")]') 提取所有包含 item-0 類的 <li> 元素。打印提取到的元素數量、類型和內容。

html = '''
<div><ul><li class="item-0">first item</li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li><li class="item-1 active"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul></div>
'''
from parsel import Selectorselector = Selector(text=html)
items = selector.css('.item-0')
print(len(items), type(items), items)
items2 = selector.xpath('//li[contains(@class, "item-0")]')
print(len(items2), type(items), items2)

4.2 提取文本內容

使用 CSS 選擇器 .item-0 提取所有類名為 item-0<li> 元素。遍歷提取到的元素,使用 XPath 表達式 .//text() 提取每個元素及其子元素中的所有文本內容。使用 CSS 選擇器 .item-0 *::text 提取所有 .item-0 元素的子元素中的文本節點,并獲取所有結果。

html = '''
<div><ul><li class="item-0">first item</li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li><li class="item-1 active"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul></div>
'''
from parsel import Selector
selector = Selector(text=html)
items = selector.css('.item-0')
for item in items:text = item.xpath('.//text()').get()print(text)# result = selector.xpath('//li[contains(@class, "item-0")]//text()').get()
# print(result)result = selector.css('.item-0 *::text').getall()
print(result)# result = selector.css('.item-0::text').get()
# print(result)

4.3?提取特定的文本內容

selector.xpath('//li[contains(@class, "item-0")]//text()') 使用 XPath 表達式提取所有 <li> 元素中包含 item-0 類的文本內容。//li[contains(@class, "item-0")]:匹配所有 <li> 元素,其 class 屬性包含 item-0//text():提取匹配到的 <li> 元素及其子元素中的所有文本節點。.getall() 獲取所有提取到的文本節點,返回一個列表。

html = '''
<div><ul><li class="item-0">first item</li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li><li class="item-1 active"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul></div>
'''
from parsel import Selector
selector = Selector(text=html)
result = selector.xpath('//li[contains(@class, "item-0")]//text()').getall()
print(result)# result = selector.css('.item-0::text').get()
# print(result)

4.4?提取特定的屬性值

selector.xpath('//li[contains(@class, "item-0") and contains(@class, "active")]/a/@href') 使用 XPath 表達式提取同時具有 item-0active 類的 <li> 元素中的 <a> 標簽的 href 屬性值。//li[contains(@class, "item-0") and contains(@class, "active")]:匹配同時具有 item-0active 類的 <li> 元素。/a/@href:提取 <a> 標簽的 href 屬性值。.get() 獲取提取到的第一個屬性值。

html = '''
<div><ul><li class="item-0">first item</li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li><li class="item-1 active"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul></div>
'''
from parsel import Selector
selector = Selector(text=html)
result = selector.css('.item-0.active a::attr(href)').get()
print(result)
result = selector.xpath('//li[contains(@class, "item-0") and contains(@class, "active")]/a/@href').get()
print(result)

4.5 提取屬性

對于每個匹配到的 .item-0 元素,正則表達式 link.* 會匹配其文本內容中以 "link" 開頭的部分。具體來說:

  • 第一個 .item-0 元素的文本是 "first item",不匹配正則表達式。

  • 第二個 .item-0 元素的文本是 "third item",不匹配正則表達式。

  • 第三個 .item-0 元素的文本是 "fifth item",不匹配正則表達式。

html = '''
<div><ul><li class="item-0">first item</li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li><li class="item-1 active"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul></div>
'''
from parsel import Selector
selector = Selector(text=html)
result = selector.css('.item-0').re('link.*')
print(result)

4.6?正則提取

selector.css('.item-0') 提取所有類名為 item-0<li> 元素。.re_first('<span class="bold">(.*?)</span>') 使用正則表達式 <span class="bold">(.*?)</span> 提取匹配的內容,并返回第一個匹配結果。<span class="bold">(.*?)</span>:匹配 <span class="bold"> 開頭,</span> 結尾的內容,并捕獲中間的任意字符(非貪婪模式)。

html = '''
<div><ul><li class="item-0">first item</li><li class="item-1"><a href="link2.html">second item</a></li><li class="item-0 active"><a href="link3.html"><span class="bold">third item</span></a></li><li class="item-1 active"><a href="link4.html">fourth item</a></li><li class="item-0"><a href="link5.html">fifth item</a></li></ul></div>
'''
from parsel import Selector
selector = Selector(text=html)
result = selector.css('.item-0').re_first('<span class="bold">(.*?)</span>')
print(result)

?

?來源:

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/73230.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/73230.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/73230.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

理解操作系統(一)馮諾依曼結構和什么是操作系統

認識馮諾依曼系統 操作系統概念與定位 深?理解進程概念&#xff0c;了解PCB 學習進程狀態&#xff0c;學會創建進程&#xff0c;掌握僵?進程和孤?進程&#xff0c;及其形成原因和危害 1. 馮諾依曼體系結構 我們常?的計算機&#xff0c;如筆記本。我們不常?的計算機&am…

Tomcat常見漏洞攻略

一、CVE-2017-12615 漏洞原理&#xff1a;當在Tomcat的conf&#xff08;配置?錄下&#xff09;/web.xml配置?件中添加readonly設置為false時&#xff0c;將導致該漏洞產 生&#xff0c;&#xff08;需要允許put請求&#xff09; , 攻擊者可以利?PUT方法通過精心構造的數據包…

快速求出質數

要快速判斷一個數是否為質數&#xff0c;可以采用以下優化后的試除法&#xff0c;結合數學規律大幅減少計算量&#xff1a; 步驟說明 處理特殊情況&#xff1a; 若 ( n \leq 1 )&#xff0c;不是質數。若 ( n 2 ) 或 ( n 3 )&#xff0c;是質數。若 ( n ) 能被 2 或 3 整除&…

Linux上位機開發實戰(camera視頻讀取)

【 聲明&#xff1a;版權所有&#xff0c;歡迎轉載&#xff0c;請勿用于商業用途。 聯系信箱&#xff1a;feixiaoxing 163.com】 關于linux camera&#xff0c;一般都是認為是mipi camera&#xff0c;或者是usb camera。當然不管是哪一種&#xff0c;底層的邏輯都是v4l2&#x…

高性能緩存:使用 Redis 和本地內存緩存實戰示例

在現代高并發系統中&#xff0c;緩存技術是提升性能和降低數據庫壓力的關鍵手段。無論是分布式系統中的Redis緩存&#xff0c;還是本地高效的本地內存緩存&#xff0c;合理使用都能讓你的應用如虎添翼。今天&#xff0c;我們將基于go-dev-frame/sponge/pkg/cache庫的代碼示例&a…

Python實現deepseek接口的調用

簡介&#xff1a;DeepSeek 是一個強大的大語言模型&#xff0c;提供 API 接口供開發者調用。在 Python 中&#xff0c;可以使用 requests 或 httpx 庫向 DeepSeek API 發送請求&#xff0c;實現文本生成、代碼補全&#xff0c;知識問答等功能。本文將介紹如何在 Python 中調用 …

山東大學數據結構課程設計

題目&#xff1a;全國交通咨詢模擬系統 問題描述 處于不同目的的旅客對交通工具有不同的要求。例如&#xff0c;因公出差的旅客希望在旅途中的時間盡可能地短&#xff0c;出門旅游的旅客則期望旅費盡可能省&#xff0c;而老年旅客則要求中轉次數最少。編織一個全國城市間的交…

深入理解倒排索引原理:從 BitSet 到實際應用

倒排索引是一種極為重要的數據結構&#xff0c;它能夠高效地支持大規模數據的快速查詢&#xff0c;本文將深入探討倒排索引的原理&#xff0c;借助 BitSet 這種數據結構來理解其實現機制&#xff0c;并通過具體的JSF請求條件示例來展示其在實際應用中的運算過程。 BitSet&#…

Unity網絡開發快速回顧

知識點來源&#xff1a;總結人間自有韜哥在&#xff0c; 唐老獅&#xff0c;豆包 目錄 1.網絡通信-通信必備知識-IP地址和端口類2.網絡通信中序列化和反序列化2進制數據3.Socket類4.TCP同步服務端和客戶端基礎實現4.1.服務端基本實現4.2.客戶端實現&#xff1a; 5.區分消息類型…

內網滲透技術 Docker逃逸技術(提權)研究 CSMSF

目錄 如何通過上傳的webshell判斷當前環境是否是物理環境還是Docker環境 方法一&#xff1a;檢查文件系統 方法二&#xff1a;查看進程 方法三&#xff1a;檢查網絡配置 方法四&#xff1a;檢查環境變量 方法五&#xff1a;檢查掛載點 總結 2. 如果是Docker環境&#x…

動態規劃:從暴力遞歸到多維優化的算法進化論(C++實現)

動態規劃&#xff1a;從暴力遞歸到多維優化的算法進化論 一、動態規劃的本質突破 動態規劃&#xff08;Dynamic Programming&#xff09;不是簡單的遞歸優化&#xff0c;而是計算思維范式的革命性轉變。其核心價值在于通過狀態定義和決策過程形式化&#xff0c;將指數復雜度問…

數據結構與算法-數據結構-樹狀數組

概念 樹狀數組&#xff0c;也叫二叉索引樹&#xff08;Binary Indexed Tree&#xff0c;BIT&#xff09;&#xff0c;它是用數組來模擬樹形結構。樹狀數組的每個節點存儲的是數組中某一段的和&#xff08;或其他可合并的信息&#xff09;&#xff0c;通過巧妙的索引方式和樹形…

AI比人腦更強,因為被植入思維模型【19】三腦理論思維模型

定義 三腦理論思維模型是由美國神經科學家保羅麥克萊恩&#xff08;Paul MacLean&#xff09;提出的&#xff0c;該理論認為人類的大腦由三個不同但又相互關聯的部分組成&#xff0c;分別是爬蟲腦&#xff08;Reptilian Brain&#xff09;、邊緣腦&#xff08;Limbic Brain&am…

使用 patch-package 優雅地修改第三方依賴庫

在前端開發中&#xff0c;有時我們需要對第三方依賴庫進行修改以滿足項目需求。然而&#xff0c;直接修改 node_modules 中的文件并不是一個好方法&#xff0c;因為每次重新安裝依賴時這些修改都會丟失。patch-package 是一個優秀的工具&#xff0c;可以幫助我們優雅地管理這些…

馬科維茨均值—方差理論推導過程

下面給出一個詳細的、符號嚴謹、公式連貫的馬科維茨均值—方差理論推導過程&#xff0c;假設你輸入了 nnn 列股票的歷史收盤價數據。我們從數據符號的定義開始&#xff0c;逐步構建所有公式&#xff0c;并詳細解釋每個符號的意義。

僅靠prompt,Agent難以自救

Alexander的觀點很明確&#xff1a;未來 AI 智能體的發展方向還得是模型本身&#xff0c;而不是工作流&#xff08;Work Flow&#xff09;。還拿目前很火的 Manus 作為案例&#xff1a;他認為像 Manus 這樣基于「預先編排好的提示詞與工具路徑」構成的工作流智能體&#xff0c;…

【css酷炫效果】純CSS實現懸浮彈性按鈕

【css酷炫效果】純CSS實現懸浮彈性按鈕 緣創作背景html結構css樣式完整代碼效果圖 想直接拿走的老板&#xff0c;鏈接放在這里&#xff1a;https://download.csdn.net/download/u011561335/90492020 緣 創作隨緣&#xff0c;不定時更新。 創作背景 剛看到csdn出活動了&…

決策樹基礎

決策樹 定義 從根節點開始&#xff0c;也就是擁有全部的數據&#xff0c;找一個維度對根節點開始劃分&#xff0c; 劃分后希望數據整體的信息熵是最小的&#xff0c; 針對劃分出來的兩個節點&#xff0c;我們繼續重復剛才的劃分方式尋找信息熵最小的維度和閾值。 遞歸這個…

動態查找表

1.問題分析&#xff1a; 動態查找表是一種可以動態地插入、刪除和查找元素的數據結構。它是基于二叉搜索樹實現的&#xff0c;具有快速的查找和插入操作。 以下是一些關于動態查找表的問題分析&#xff1a; 1. 插入操作&#xff1a;在動態查找表中插入一個元素時&#xff0c…

得分匹配的朗之萬動力學——Score-Matching Langevin Dynamics (SMLD)

得分匹配的朗之萬動力學——Score-Matching Langevin Dynamics (SMLD) 文章目錄 得分匹配的朗之萬動力學——Score-Matching Langevin Dynamics (SMLD)摘要Abstract周報內容0. 上期補充1. 本期的基本思想2. 從一個分布中采樣&#xff08;Sampling from a Distribution&#xff…