什么是 Xpath?
-
解析 XML 语言的一种语言(HTML其实是XML的子级),广泛用于解析 HTML 数据
-
几乎所有语言都能使用 xpath , 比如 Java 和 C 语言
Xpath 语法
-
层级:
/
直接子级//
跳级 -
属性:
@
直接属性访问contains()
包含属性访问 -
文本:
text()
按文本访问 -
索引:
[1]
第一个、[2]
第二个……[last()-1]
倒数第二个、[last()]
最后一个 -
节点:
.
当前节点,用于二次筛选
XPath 表达式
-
访问元素,示例: //e[@id=“id值”] //e[@id=“id值”]/f
-
访问元素的文本,示例://e/tetx() //e[@id=“id值”]/text()
-
访问元素的属性值,示例://e/@href //e[@id=“id值”]/@alt
Python中的 lxml 库具有 Xpath 语法
示例:
from lxml import etree
import requests
res = requests.get('https://www.baidu.com')
html = res.content.decode('utf8')
'''字符串转化为etree._Element对象,然后具有Xpath方法'''
doc = etree.HTML(html)
# print(type(html))
# >>>> <class 'lxml.etree._Element'>
'''通过 标签名 定位元素,返回列表'''
title = doc.xpath('//title')
print(type(title))
# >>> <class 'list'>
print(title)
# >>> [<Element title at 0x17357367d08>]
'''选取 元素的文本,返回列表'''
title = doc.xpath('//title/text()')
print(title)
# >>> ['百度一下,你就知道']
'''通过 属性 选取元素的属性值'''
su = doc.xpath('//input[@id="su"]/@value')
print(su)
# >>> ['百度一下']
'''通过 多个属性 定位元素'''
su = doc.xpath('//input[@id="su"][@type="submit"]/@value')
print(su)
# >>> ['百度一下']
'''通过 层级 定位元素'''
links = doc.xpath('//div[@id="u1"]/a/text()')
print(links)
# >>> ['新闻', 'hao123', '地图', '视频', '贴吧', '更多产品']
'''跳级 定位元素'''
item = doc.xpath('//div[@class="head_wrapper"]//img/@src')
print(item)
# >>> ['//www.baidu.com/img/bd_logo1.png']
link2 = doc.xpath('//div[@id="u1"]/a[@name="tj_trhao123"]/text()')
print(link2)
# >>> ['hao123']
'''通过 部分属性值 定位元素'''
link2 = doc.xpath('//a[contains(@name,"hao123")]/text()')
print(link2)
# >>> ['hao123']
'''通过 文本 定位元素'''
href2 = doc.xpath('//a[text()="hao123"]/@href')
print(href2)
# >>> ['https://www.hao123.com']
'''通过 索引 定位元素'''
link3 = doc.xpath('//div[@id="u1"]/a[3]/text()')
print(link3)
# >>> ['地图']
'''xpath方法返回的结果是列表,可以通过列表 ‘索引’ 提取数据'''
link5 = doc.xpath('//div[@id="u1"]/a[last()-1]/text()')[0]
print(link5)
# >>> 贴吧
'''节点的二次筛选'''
links = doc.xpath('//div[@id="u1"]')[0]
link1 = links.xpath('./a[1]/text()')[0]
print(link1)
# >>> 新闻
lxml 库提取元素内容的方法
除了 Xpath 语法中直接通过访问元素中的文本或属性值来提取内容之外,也可以先定位到元素,然后使用 lxml 的提供给元素的.text
属性和get()
方法来提取内容,如下面的例子:
from lxml import etree
import requests
res = requests.get('https://www.baidu.com')
html = res.content.decode('utf8')
'''字符串转化为etree._Element对象,然后具有Xpath方法'''
doc = etree.HTML(html)
'''定位元素,返回包含元素的列表'''
link = doc.xpath('//a[text()="hao123"]')[0]
# 获取元素中的文本
print(link.text)
# 获取元素的属性值
print(link.get('href'))
用 lxml 库解析数据的爬取百度搜索热点的例子
import requests
from lxml import etree
def get_html(url):
"""获取解析后的页面"""
s = requests.Session()
r = s.get(url, timeout=6)
html = etree.HTML(r.text)
return html
def get_search_hots():
"""获取搜索热点的标题"""
html = get_html('http://www.baidu.com/s?wd=xpath')
search_hots = html.xpath('//div[@class="FYB_RD"]//tbody/tr//a/@title')
hots_dict = {}
for index, word in enumerate(search_hots):
print(index, word)
hots_dict[str(index)] = word
return hots_dict
def get_news(url):
"""获取搜索热点的新闻报道"""
html = get_html(url)
links = html.xpath('//div[@class="c-offset"]/div//a/@href')
times = html.xpath('//div[@class="c-offset"]/div//span[1]/text()')
news = html.xpath('//div[@class="c-offset"]/div//span[2]/text()')
links = [requests.get(link).url for link in links]
for new, time, link in zip(news, times, links):
print(new, time, link)
def main():
print('最新的百度热搜如下:\n')
try:
# 获取搜索热点的标题
hots_dict = get_search_hots()
while True:
index = input('\n请输入对应的序号查看新闻报道:')
if index not in hots_dict:
continue
word = hots_dict[index]
# 获取搜索热点的提交网址
url = 'http://www.baidu.com/s?wd=' + word
# 获取搜索热点的新闻报道
get_news(url)
except:
print('产生异常!爬取失败...')
if __name__ == "__main__":
main()