(数据科学学习手札61)xpath进阶用法
一、簡介
xpath作為對網頁、對xml文件進行定位的工具,速度快,語法簡潔明了,在網絡爬蟲解析內容的過程中起到很大的作用,除了xpath的基礎用法之外(可參考我之前寫的(數據科學學習手札50)基于Python的網絡數據采集-selenium篇),xpath中還存在著非常之多的進階用法,本文將對筆者日常使用中積累的xpath進階用法進行總結并舉例說明:
?
二、xpath進階用法
本文以http://quotes.toscrape.com/示例頁面,首先抓取網頁源碼并利用etree解析:
import requestsfrom lxml import etreehtml = requests.get('http://quotes.toscrape.com/') tree = etree.HTML(html.text)
2.1 獲取某一節點的上一級節點
在xpath中/..表示向上一級,這里我們用xpath按照下圖中的路徑提取a標簽里的內容:
'''提取頁面中符合下列位置規則的所有keyword''' tree.xpath("//meta[@class='keywords']/../a[@class='tag']/text()")
? 或者利用parent來向上一級跳轉,效果是一樣的:
'''提取頁面中符合下列位置規則的所有keyword''' tree.xpath("//meta[@class='keywords']/parent::*/a[@class='tag']/text()")2.2 定位指定屬性以某個特定字符開頭的標簽
在xpath中有函數starts-with(屬性名稱,開始字符),可用于定位指定屬性以某個特定字符開頭的標簽,如下例,實現與2.1中相同功能:
'''提取href屬性以/tag開頭的a標簽內容''' tree.xpath("//a[starts-with(@href,'/tag')]/text()")
2.3 定位指定屬性值包含特定字符片段的標簽
在xpath中函數contains(屬性名稱,包含字符)可用于定位指定屬性值包含特定字符片段的標簽內容,比如我們想要找到所有text()內容中帶有know的名人名言,就可以像下面這樣做:
'''提取text()內容包含know的span標簽對應的text()內容''' tree.xpath("//span[contains(text(),'know')]/text()")?
2.4 匹配具有某屬性的所有標簽
比如說我們想獲取頁面中所有的href超鏈接,就可以用下面的方式:
'''獲取整個頁面內所有href屬性''' tree.xpath("//@href")?
2.5 同時定位多個內容
比如說我們想在一行代碼里同時取得兩種不同的規則下匹配的內容,可以在xpath語句中將不同的多個xpath語句用|連接起來,最終返回的結果在同一個列表里,所以使用這種語法時需要考慮取得的內容是否適合放在一起:
?
2.6 選取指定節點下所有子元素
有時候我們想要快捷的獲取某一節點下一級所有標簽的某一屬性內容,可以使用child來表示下一級節點:
'''選取class為quote的div節點下所有span子節點的text()內容''' tree.xpath("//div[@class='quote']/child::span/text()")? 當不指定標簽名稱而使用*代替時,代表匹配所有子節點:
'''選取class為quote的div節點下所有子節點的text()內容''' tree.xpath("//div[@class='quote']/child::*/text()")?
2.7 選取某一節點所有的屬性值
有時候我們想要獲取滿足條件的節點下所有的屬性值:
'''選取class為quote的div標簽下所有的屬性值''' tree.xpath("//div[@class='quote']/attribute::*")
也可以指定要提取的具體屬性值,如這里我們只提取href,只需要將*替換成href即可:
'''選取class為tag的a標簽下所有的href屬性值''' tree.xpath("//a[@class='tag']/attribute::href")?
2.8 定位某一節點的祖先節點
比如我們想要獲取class為keywords的meta標簽之上所有標簽的class屬性內容,可以像下面這樣:
tree.xpath("//meta[@class='keywords']/ancestor::*/@class")? 若想同時包含所有祖先節點及自己本身,則可使用ancestor-or-self:
tree.xpath("//meta[@class='keywords']/ancestor-or-self::*/text()")?
2.9 定位某一節點的后代節點
類似2.8,只不過這里我們來定位某一節點之下的所有后代節點,使用descendant:
'''獲取class為tags的標簽下所有后代節點中a標簽的href信息''' tree.xpath("//div[@class='tags']/descendant::a/@href")?2.10 條件與或非
在xpath中使用邏輯運算來定位的方法如下:
與:
'''定位class為text且itemprop為text的span標簽''' tree.xpath("//span[@class='text' and @itemprop='text']/text()")或:
tree.xpath("//div[@class='quote' or @class='tags']/@class")?
?非:
'''提取所有span標簽class屬性不為text的class屬性值''' tree.xpath("//span[not(@class='text')]/@class")?2.11 選取指定標簽結束之后的所有指定標簽
在xpath中我們可以使用following來定位以某個標簽在文檔中的位置為起點的所有指定標簽:
'''提取所有class為keywords的meta標簽結束標簽之后出現的標簽a的text()內容''' tree.xpath("//meta[@class='keywords']/following::a/text()")2.12?選取指定標簽開始之前的所有指定標簽
與following的功能截然相反,在xpath中使用preceding可以定位指定標簽之前的所有標簽:
'''選取body標簽之前的所有標簽的text()內容''' tree.xpath("//body/preceding::*/text()")?
2.13 選取指定標簽結束之后的所有同級指定標簽
在following的基礎上,若想定位所有指定標簽之后且與指定標簽同一級別的標簽,可使用following-sibling:
'''提取所有class為keywords的meta標簽結束標簽之后出現的同級別標簽a的text()內容''' tree.xpath("//meta[@class='keywords']/following-sibling::a/text()")2.14 選取指定標簽開始之前的所有同級指定標簽
類似following-sibling,使用preceding-sibling可以實現相反的效果:
'''選取body標簽之前的所有同級標簽的text()內容''' tree.xpath("//body/preceding-sibling::*/text()")?
2.15 對提取內容中的空格進行規范化處理
在xpath中我們可以使用normalize-space對目標內容中的多余空格進行清洗,其作用是刪除文本內容之前和之后的所有\s類的內容,并將文本中夾雜的兩個及以上空格轉化為單個空格,下面比較使用normalize-space前后對提取結果的影響:
'''清洗前''' tree.xpath("//p[@class='text-muted']/text()") '''清洗后''' tree.xpath("normalize-space(//p[@class='text-muted']/text())")使用normalize-space之后得到的結果更加的規整,可以提高爬取數據的效率。
?
2.16 在xpath中使用正則表達式
有時候一些任務情況比較特殊,在xpath中可能沒有對應的函數直接可以使用,這時可以在xpath語句中穿插正則表達式,比如我們想要提取class為tag且href屬性符合.*?-.*?page.*?規則的a標簽中的href與text()內容,就可以在傳入規范的正則命名空間,并利用match來匹配自定義的正則語句,如下:
tree.xpath(r"//a[@class='tag' and ns:match(@href, '.*?-.*?page.*?')]/text() | //a[@class='tag' and ns:match(@href, '.*?-.*?page.*?')]/@href",namespaces={"ns": "http://exslt.org/regular-expressions"})?
?
以上就是本文的全部內容,實際上xpath中還有更多方便使用的功能,本文僅根據筆者的日常使用積累做了片面的總結,如有筆誤之處望斧正!
?
?
?
?
?
?
轉載于:https://www.cnblogs.com/feffery/p/10996526.html
總結
以上是生活随笔為你收集整理的(数据科学学习手札61)xpath进阶用法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用户故事与敏捷方法阅读笔记03
- 下一篇: 使用装饰器配置路由的