爬虫基础之 解析"/>
Python爬虫基础之 解析
二、解析
Xpath
1.初识Xpth
1.1什么是Xpath?
XPath (XML Path Language) 是一门在 XML 文档中查找信息的语言,可用来在 XML 文档中对元素和属性进行遍历。
XPath定位在爬虫和自动化测试中都比较常用,通过使用路径表达式来选取 XML 文档中的节点或者节点集,熟练掌握XPath可以极大提高提取数据的效率。
1.2Xpath语法
选取节点
表达式 | 描述 |
---|---|
nodename | 选取此节点的所有子节点。 |
/ | 从根节点选取(取子节点)。 |
// | 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置(取子孙节点)。 |
. | 选取当前节点。 |
… | 选取当前节点的父节点。 |
@ | 选取属性。 |
路径表达式 | 结果 |
---|---|
bookstore | 选取 bookstore 元素的所有子节点。 |
/bookstore | 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径! |
bookstore/book | 选取属于 bookstore 的子元素的所有 book 元素。 |
//book | 选取所有 book 子元素,而不管它们在文档中的位置。 |
bookstore//book | 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。 |
//@lang | 选取名为 lang 的所有属性。 |
谓语
谓语用来查找某个特定的节点或者包含某个指定的值的节点。
谓语被嵌在方括号中。
在下面的表格中,我们列出了带有谓语的一些路径表达式,以及表达式的结果:
路径表达式 | 结果 |
---|---|
/bookstore/book[1] | 选取属于 bookstore 子元素的第一个 book 元素。 |
/bookstore/book[last()] | 选取属于 bookstore 子元素的最后一个 book 元素。 |
/bookstore/book[last()-1] | 选取属于 bookstore 子元素的倒数第二个 book 元素。 |
/bookstore/book[position() < 3] | 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。 |
//title[@lang] | 选取所有拥有名为 lang 的属性的 title 元素。 |
//title[@lang=‘eng’] | 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。 |
/bookstore/book[price>35.00] | 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。 |
/bookstore/book[price>35.00]//title | 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。 |
选取未知节点
XPath 通配符可用来选取未知的 XML 元素。
通配符 | 描述 |
---|---|
* | 匹配任何元素节点。 |
@* | 匹配任何属性节点。 |
@* | 匹配任何属性节点。 |
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
路径表达式 | 结果 |
---|---|
/bookstore/* | 选取 bookstore 元素的所有子元素。 |
//* | 选取文档中的所有元素。 |
//title[@*] | 选取所有带有属性的 title 元素。 |
选取若干路径
通过在路径表达式中使用"|"运算符,可以选取若干个路径。
在下面的表格中,我们列出了一些路径表达式,以及这些表达式的结果:
路径表达式 | 结果 |
---|---|
//book/title | //book/price | 选取 book 元素的所有 title 和 price 元素。 |
//title | //price | 选取文档中的所有 title 和 price 元素。 |
/bookstore/book/title | //price | 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。 |
1.3HTML的基本标签
标题:`<h1>、<h2>、<h3>、<h4>、<h5>、<h6>、<title>`段落:<p>链接:<a>图像:<img>样式:<style>列表:`无序列表<ul>、有序列表<ol>、列表项<li>`块:`<div>、<span>`脚本:<script>注释:<!--注释-->
2.Xpath的基本使用
2.1安装lxml库
在pycharm的设置–>项目:Python爬虫–>Python解释器 中进行安装。
2.2Xpath解析类型
(1)本地文件 etree.parse
(2)服务器响应的数据 etree.HTML(content)
2.2.1Xpath解析本地文件
本地文件
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"/><title>Title</title>
</head>
<body><ul><li id="l1" class="c1">北京</li><li id="l2">上海</li><li id="c3">深圳</li><li id="c4">上海</li></ul><ul><li>大连</li><li>锦州</li><li>沈阳</li></ul></body>
</html>
解析的基本使用
from lxml import etree# xpath解析本地文件
tree = etree.parse('17_解析_xpath的基本使用.html')# tree.xpath('xpath路径')
# // 查找所有的子孙结点,不考虑层级关系
#// 找直接子节点# 查找ul下面的li
# li_list = tree.xpath('//body/ul/li')# 查找所有有id的属性的li标签
# text()获取标签中的内容
# li_list = tree.xpath('//ul/li[@id]/text()')# 找到id为l1的li标签
# li_list = tree.xpath('//ul/li[@id="l1"]/text()')# 查找到id为l1的li标签的class的属性值
# []中写标签的属性值,属性名前要有@,值用""括起来
# li = tree.xpath('//ul/li[@id="l1"]/@class')# 查询id中包含l的li标签
# li_list = tree.xpath('//ul/li[contains(@id, "l")]/text()')# 查询id的值以l开头的li标签
# li_list = tree.xpath('//ul/li[starts-with(@id, "l")]/text()')# 查询id为l1和class为c1的标签
# li_list = tree.xpath('//ul/li[@id="l1" and @class="c1"]/text()')# | (或)不能再标签之间用
li_list = tree.xpath('//ul/li[@id="l1"]/text() | //ul/li[@id="l2"]/text()')print(li_list)
print(len(li_list))
2.2.2Xpath解析服务器响应数据
例一:以获取百度网站的“百度一下”为例
import urllib.requesturl = ''headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36'
}reqeust = urllib.request.Request(url=url, headers=headers)response = urllib.request.urlopen(request)content = response.read().decode('utf-8')from lxml import etree# 解析服务器响应的数据
tree = etree.HTML(content)# 获取想要的数据 xpath的返回值是一个列表类型的数据
result = tree.xpath('//input[@id="su"]/@value')[0]print(result)
例二:利用解析下载站长素材的前十页图片
import urllib.request
form lxml import etree
# 需求 下载前十页的图片
# .html
# .html
# .html# 封装请求对象定制
def create_request(page):if (page == 1): # 因为第一页的url和其他页的不同需要单独判断url = '.html'else:url = '' + str(page) + '.html'headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36'}request = urllib.request.Request(url=url, headers=headers)return request# 封装获取网页内容
def get_content(request):response = urllib.request.urlopen(request)content = response.read().decode('utf-8')return contentdef down_load(content):# 下载图片 利用xpath找出图片名称以及图片的路径tree = etree.HTML(content)name_list = tree.xpath('/html/body/div[3]/div[2]/div//img/@alt')src_list = tree.xpath('/html/body/div[3]/div[2]/div/img/@data-original')for i in range(len(name_list)):name = name_list[i]src = src_list[i]url = 'https:' + srcurllib.request.urlretrieve(url=url, filename='./loveImg/' + name + '.jpg')if __name__ == '__main__':start_page = int(input('请输入起始页码:'))end_page = int(input('请输入结束页码:'))for page in range(start_page, end_page+1):# (1)请求对象的定制request = create_request(page)# (2)模拟向服务器发送数据content = get_content(request)# (3)下载down_load(content)
JsonPath
1.初识JsonPath
1.1关于JsonPath
JsonPath和JSON文档有关系,正如XPath之于XML文档一样,JsonPath为Json文档提供了解析能力,通过使用JsonPath,你可以方便的查找节点、获取想要的数据,JsonPath是Json版的XPath。
1.2JsonPath语法
(1)JsonPath语法要点:
-
$
表示文档的根元素 -
@
表示文档的当前元素 -
.node_name
或['node_name']
匹配下级节点 -
[index]
检索数组中的元素 -
[start:end:step]
支持数组切片语法 -
*
作为通配符,匹配所有成员 -
..
子递归通配符,匹配成员的所有子元素 -
(<expr>)
使用表达式 -
?(<boolean expr>)
进行数据筛选(2)JsonPath与Xpath的比较
XPath JsonPath 说明 /
$
文档根元素 .
@
当前元素 /
.
或[]
匹配下级元素 ..
N/A
匹配上级元素,JsonPath不支持此操作符 //
..
递归匹配所有子元素 *
*
通配符,匹配下级元素 @
N/A
匹配属性,JsonPath不支持此操作符 []
[]
下标运算符,根据索引获取元素,XPath索引从1开始,JsonPath索引从0开始 ` ` [,]
N/A
[start:end:step]
数据切片操作,XPath不支持 []
?()
过滤表达式 N/A
()
脚本表达式,使用底层脚本引擎,XPath不支持 ()
N/A
分组,JsonPath不支持 注意:
- JsonPath的索引从0开始计数
- JsonPath中字符串使用单引号表示,例如:
$.store.book[?(@.category=='reference')]
中的'reference'
2.JsonPath的基本使用
2.1JsonPath解析本地文件
本地文件
{ "store": {"book": [{ "category": "修真","author": "六道","title": "坏蛋是怎样练成的","price": 8.95},{ "category": "修真","author": "天蚕土豆","title": "斗破苍穹","price": 12.99},{ "category": "修真","author": "唐家三少","title": "斗罗大陆","isbn": "0-553-21311-3","price": 8.99},{ "category": "修真","author": "南派三叔","title": "星辰变","isbn": "0-395-19395-8","price": 22.99}],"bicycle": {"color": "黑色","price": 19.95}}
}
代码示例
import urllib.request
import json
import jsonpath#加载本地文件
obj = json.load(open('filename'))# 获取书店下的所有作者
author_list = jsonpath.jsonpath(obj, '$.store.book[*].author')
print(author_list)# 直接利用绝对路径获取所有作者
authors_list = jsonpath.jsonpath(obj, '$..author')
print(authors_list)# 获取store下所有的元素
tag_list = jsonpath.jsonpath(obj, '$.store.*')
print(tag_list)# 获取store下所有东西的价格
price_list = jsonpath.jsonpath(obj, '$.store..price')
print(price_list)
注意:
- json.load()参数是对象
- json.loads()参数是字符串
2.2JaonPath解析服务器响应文件
以解析淘票票为例
import urllib.request
import jsonurl = '.json?activityId&_ksTS=1681105103837_108&jsoncallback=jsonp109&action=cityAction&n_s=new&event_submit_doGetAllRegion=true'# 经测试只需要referer即可
headers = {'referer': '/?spm=a1z21.3046609.city.1.7db2112axDN5Jc&n_s=new&city=110100',
}request = urllib.request.Request(url=url, headers=headers)response = urllib.request.urlopen(reqeust)content = response.read().decode('utf-8')#利用分隔符分割,返回的是数组,取第二个元素,即下标为1
content = content.split('(')[1].split(')')[0]#写入本地文件
with open('解析_jsonpath解析淘票票.json', 'w', encoding='utf-8') as fp:fp.write(content)obj = json.load(open('解析_jsonpath解析淘票票.json', 'r', encoding='utf-8'))city_list = jsonpath.jsonpath(obj, '$..regionName')print(city_list)
关于本例url如何获取的问题
f12,刷新主页,清空全部nerwork栏内容,然后鼠标点击地名会出现接口,接口中有url,为json数据内容。
注意:
content.split('(')
以'('
为分割符进行分割,并以列表 形式返回
Bs4
1.初识Bs4
1.1什么是Bs4
BS4全称是Beatiful Soup,它提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为tiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。
1.2Bs4语法
在 BS4 中,通过标签名和标签属性可以提取出想要的内容
eg:
获取整个p标签的html代码:soup.p
获取p标签:soup.p.b
获取p标签内容:soup.p.text
2.Bs4的基本使用
2.1Bs4解析本地文件
本地文件
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><div><ul><li id="l1">张三</li><li id="l2">李四</li><li>王五</li><a href="" id="" class="a1">尚硅谷</a></ul></div><a href="" title="a2">百度</a><div id="d1"><span>哈哈哈</span></div><p id="p1" class="p1">呵呵呵</p>
</body>
</html>
解析本地文件
from bs4 import BeautifulSoup# 默认打开文件的格式是gbk
soup = BeautifulSoup(open('解析_bs4的基本使用.html', encoding='utf-8'), 'lxml')# 根据标签名查找节点
# 找到的是第一个符合条件的数据
print(soup.a)
print(soup.a.attrs) # attrs 获取标签的属性和属性值# bs4的一些函数
# (1)find
# 返回第一个符合条件的数据
print(soup.find('a'))
# 根据title的值找到对应的标签对象
print(soup.find('a', title="a2"))
# 根据class的值找到对应的标签对象,class需要加下划线
print(soup.find('a', class_="a1"))# (2)find_all 返回列表,并返回所有的a标签
print(soup.find_all('a'))# 如果想获取的是多个标签的数据,那么需要在参数中添加列表的数据(参数的数据类型是列表)
print(soup.find_all('['a', 'span']'))
# limit的作用,查找前几个数据
print(soup.find_all('li', limit=2))# (3) select 推荐使用
# select方法返回的是一个列表,并且返回多个数据
print(soup.select('a'))
# 可以通过 . 代表class,我们把这种操作叫做类选择器
print(soup.select('.a1'))
# 可以通过 # 代表id
print(soup.select('#l1')) # 属性选择器--通过属性来寻找对应的标签
# 查找li标签中有id的标签
print(soup.select('li[id]'))
# 查找li标签中id为l2的标签
print(soup.select('li[id="l2"]'))# 层级选择器
# 后代选择器
# 找到的是div下面的li
print(soup.select('div li'))# 子代选择器
# 某标签的第一级子标签
# 注意:很多的计算机编程语言中,如果不加空格不会输出内容,但在bs4中,不会报错,会显示内容
print(soup.select('div > ul > li'))# 找到a标签和li标签的所有对象
print(soup.select('a, li'))# 节点信息
# 获取节点信息
obj = soup.select('#d1')[0]
# 如果标签对象中只有内容,那么string和get_text()都可以使用
# 如果标签对象中除了内容还有标签,那么string就获取不到数据,而get_text()可以获取数据
# 推荐使用 get_text()
print(obj.string)
print(obj.get_text())# 节点的属性
obj = soup.select('#p1')[0]
# name是标签的名字
print(obj.name)
# 将属性值作为一个字典返回
print(obj.attrs)# 获取节点的属性
obj = soup.select('#p1')[0]print(obj.attrs.get('class')) # 通过字典中的get()方法获取class的值
print(obj.get('class'))
print(obj['class'])
2.1Bs4解析服务器响应文件
以爬取星巴克数据为例
import urllib.request
from bs4 import BeautifulSoupurl = ''response = urllib.request.urlopen(url)content = response.read().decode('utf-8')soup = BeautifulSoup(content, 'lxml')# //ul[@class="grid padded-3 product"]//strong/text()
# name_list = soup.select('.grid padded-3 product') 错误的
name_list = soup.select('ul[class="grid padded-3 product"] strong')
# print(name_list)for name in name_list:# print(name.string)print(name.get_text())
更多推荐
Python爬虫基础之 解析
发布评论