python爬虫解析库(Xpath、beautiful soup、Jsonpath)
1. HTML解析
HTML的内容返回给浏览器,浏览器就会解析它,并对它渲染。 HTML 超文本表示语言,设计的初衷就是为了超越普通文本,让文本表现力更强。 XML 扩展标记语言,不是为了代替HTML,而是觉得HTML的设计中包含了过多的格式,承担了一部分数据之外的 任务,所以才设计了XML只用来描述数据。HTML和XML都有结构,使用标记形成树型的嵌套结构。DOM(Document Object Model)来解析这种嵌套树型 结构,浏览器往往都提供了对DOM操作的API,可以用面向对象的方式来操作DOM。
2. Xpath
XPath 是一门在 XML 文档中查找信息的语言。XPath 可用来在 XML 文档中对元素和属性进行遍历。工具 XMLQuire win7+需要.NET框架4.0-4.5。 测试XML、XPath
2.1 节点
在 XPath 中,有七种类型的节点:元素、属性、文本、命名空间、处理指令、注释以及文档(根)节点。
- / 根结点
- <bookstore> 元素节点
- <author>Corets, Eva</author> 元素节点,
- id="bk104" 是属性节点,id是元素节点book的属性
- 节点之间的嵌套形成父子(parent、children)关系。
- 具有同一个父节点的不同节点是兄弟(sibling)关系。
节点选择:
谓语:谓语用来查找某个特定的节点或者包含某个指定的值的节点。 谓语被嵌在方括号中。 谓语就是查询的条件。 即在路径选择时,在中括号内指定查询条件。
XPath(轴节点):轴的意思是相对于当前节点的节点集
步step:步的语法 轴名称::节点测试[谓语]
XPATH实例 :以斜杠开始的称为绝对路径,表示从根开始。 不以斜杆开始的称为相对路径,一般都是依照当前节点来计算。当前节点在上下文环境中,当前节点很可能已经不 是根节点了。 一般为了方便,往往xml如果层次很深,都会使用//来查找节点。
2.2. lxml
lxml安装:$ pip install lxml
from lxml import etreewith open('./books.xml') as f:# print(f.read())text = f.read()html = etree.HTML(text.encode())# print(html)print(html.tag)print(html.xpath('//title')) # 从根节点向下找任意层中title的节点print(html.xpath('//book//title'))print(html.xpath('//book[@id="bk102"]'))print(html.xpath('//book[@id]'))print(html.xpath('//@id')) # 取回的是属性print(html.xpath('//*[@id]'))print(html.xpath('//bookstore/book[1]'))print(html.xpath('//bookstore/book[1]/@id')) # ['bk101']print(html.xpath('//bookstore/book[last()]/@id')) # last()为最后一个节点print(html.xpath('//*[contains(local-name(), "store")]')) # [<Element bookstore at 0x2ce5648>]# local-name()为当前标签名字print(html.xpath('//bookstore/*')) # 匹配根节点bookstore下的所有子节点,不递归;print(html.xpath('//*[@*]')) # 匹配所有有属性的节点print(html.xpath('//@*')) # 匹配所有属性print(html.xpath('//book/title|//book/price')) # 匹配book节点下title标签或prices标签print(html.xpath('//book[position()=2]/@id')) # ['bk102']print(html.xpath('//book[price > 40]/@id'))print(html.xpath('//book[1]/text()')) # 匹配第一个book节点下所有文本子节点print(html.xpath('//book[1]//text()')) # 匹配第一个book节点下所有文本节点print(html.xpath('//*[contains(@class,"even")]')) # 匹配属性class中包含even字符串的节点
从豆瓣电影中提取“本周口碑榜”:
import requests
from lxml import etree # lxml 是c语言的库,效率非常高
from bs4 import BeautifulSoupurl = 'http://movie.douban.com'
headers = {'User-agent': "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) \Chrome/55.0.2883.75 Safari/537.36"}
response = requests.get(url, headers=headers)with response:if response.status_code == 200:text = response.texthtml = etree.HTML(text)print(html.tag)titles = html.xpath('//div[@class="billboard-bd"]//a/text()')for title in titles:print(title)print("*********************")
2.3 Beautiful Soup4
BeautifulSoup可以从HTML、XML中提取数据。目前BS4在持续开发。
官方中文文档https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh/
安装:$ pip install beautifulsoup4
BeautifulSoup(markup, "html.parser") 使用Python标准库,容错差且性能一般。BeautifulSoup(markup, "lxml") 容错能力强,速度快。需要安装系统C库。 推荐使用lxml作为解析器,效率高。 请手动指定解析器,以保证代码在所有运行环境中解析器一致。
四种对象
BeautifulSoup将HTML文档解析成复杂的树型结构,每个节点都是Python的对象,可分为4种:
BeautifulSoup、Tag、NavigableString、Comment
BeautifulSoup:代表整个文档。
Tag:它对应着HTML中的标签。有2个常用的属性:
- name:Tag对象的名称,就是标签名称
- attrs:标签的属性字典
多值属性,对于class属性可能是下面的形式, <h3 class="title highlight">python高级班</h3> ,这 个属性就是多值({'class': ['title', 'highlight']})属性可以被修改、删除
from lxml import etree # lxml 是c语言的库,效率非常高
from bs4 import BeautifulSoup
# from bs4 import Tag# features推荐写清楚
with open('E:/马哥教育培训资料/slides/chapter16爬虫/test.html', encoding='utf-8') as f:soup = BeautifulSoup(f, 'lxml') # str 就是html内容;file-like obj open:'lxml'print(0, soup.builder)print(1, soup.name)print(2, soup.img) # 返回第一个,print(3, soup.p) # 深度优先遍历,取第一个print(4, soup.p.attrs) # 结果是字典print(5, soup.h3.attrs) # 字典print(6, soup.h3['class'])print(7, soup.h3.get('class'))soup.h3['class'] = 'new_class'print(8, soup.h3.get('class'))print(000, soup.div.name, soup.div.attrs)print(9, soup.p.string) # p标签的内容print(10, soup.div.contents) # 直接子,包括文本print(11, list(soup.div.children)) # 返回子节点的迭代器print(12, list(soup.div.descendants)) # 返回所有子孙节点的迭代器print(list(map(lambda x: x.name if x.name else x, soup.div.descendants))) # 子孙节点print('************************')print(13, "".join(soup.div.strings)) # 拼接,但是换行符还在print(14, "".join(soup.div.stripped_strings)) # 连接在一起了print(15, soup.p.next_sibling)print(16, soup.img.get('src'))print(17, soup.img['src'])print(18, soup.a) # 找不到返回Nonedel soup.h3['class'] # 删除属性print(19, soup.h3.get('class'))
注意,我们一般不使用上面这种方式来操作HTML,此代码是为了熟悉对象类型
NavigableString:如果只想输出标记内的文本,而不关心标记的话,就要使用NavigableString。
print(soup.div.p.string) # 第一个div下第一个p的字符串;print(soup.p.string) # 同上
Comment :注释对象,这就是HTML中的注释,它被Beautiful Soup解析后对应Comment对象。
遍历字符串 :在前面的例子中,soup.div.string返回None,是因为string要求soup.div只能有一个NavigableString类型子节点, 也就是如这样 <div>only string</div> 。 如果div有很多子孙节点,如何提取字符串?
print(soup.div.string) # 返回None,因为多于1个子节点
print("".join(soup.div.strings)) # 返回迭代器,带多余的空白字符
print("".join(soup.div.stripped_strings)) # 返回迭代器,去除多余空白符
遍历祖先节点:
print(soup.parent) # None 根节点没有父节点
print(soup.div.parent.name) # body,第一个div的父节点
print(soup.p.parent.parent.get('id')) # 取id属性,main
print(list(map(lambda x: x.name, soup.p.parents))) # 父迭代器,由近及远
遍历兄弟节点:
print('{} [{}]'.format(1, soup.p.next_sibling)) # 第一个p元素的下一个兄弟节点,注意可能是一个文本节
点
print('{} [{}]'.format(2, soup.p.previous_sibling))
print(list(soup.p.next_siblings)) # previous_siblings
遍历其他元素 :next_element是下一个可被解析的对象(字符串或tag),和下一个兄弟节点next_sibling不一样
print(soup.p.next_element) # 返回"字典"2个字
print(soup.p.next_element.next_element.next_element)
print(list(soup.p.next_elements))
from lxml import etree # lxml 是c语言的库,效率非常高
from bs4 import BeautifulSoup
# from bs4 import Tag# features推荐写清楚
with open('E:/马哥教育培训资料/slides/chapter16爬虫/test.html', encoding='utf-8') as f:soup = BeautifulSoup(f, 'lxml') # str 就是html内容;file-like obj open:'lxml'print(soup.p.next_element) # 返回字典两个字print(soup.p.next_element.next_element)print(soup.p.next_element.next_element.next_element)print(list(soup.p.next_elements))print(list(soup.p.next_siblings))
搜索文档树:
name:官方称为filter过滤器,这个参数可以是以下类型:
i.字符串:一个标签名称的字符串,会按照这个字符串全长匹配标签名
print(soup.find_all('p'))
ii.正则表达式对象:按照正则表达式对象的模式匹配标签名
print(soup.find_all(re.compile(r'^h\d'))) # 标签名一h开头后接数字
iii.列表
print(soup.find_all(['p', 'h1', 'h3']))print(soup.find_all(['p', re.compile(r'h\d')]))
IV.True或None:True或None,则find_all返回全部非字符串节点、非注释节点,接胡思Tag标签类型。
print(soup.list(map(lambda x: x.name, soup.find_all(True))))print(soup.list(map(lambda x: x.name, soup.find_all(None))))print(soup.list(map(lambda x: x.name, soup.find_all())))
from lxml import etree # lxml 是c语言的库,效率非常高
from bs4 import BeautifulSoup
import re
from bs4 import Tag# features推荐写清楚
with open('E:/马哥教育培训资料/slides/chapter16爬虫/test.html', encoding='utf-8') as f:soup = BeautifulSoup(f, 'lxml') # str 就是html内容;file-like obj open:'lxml'values = [True, None, False]for value in values:all = soup.find_all(value)print(type(all[0]))print(len(all))count = 0for i, t in enumerate(soup.descendants):print(i, type(t), t.name)if isinstance(t, Tag):count += 1print(count)
V.函数:如果使用以上过滤器还不能提取出想要的节点,可以使用函数,此函数仅只能接收一个参数。 如果这个函数返回True,表示当前节点匹配;返回False则是不匹配。
from lxml import etree # lxml 是c语言的库,效率非常高
from bs4 import BeautifulSoup
import re
import bs4def many_class(tag: bs4.Tag):# print(type(tag))# print(tag.attrs)return len(tag.attrs.get('class', [])) > 1# features推荐写清楚
with open('E:/马哥教育培训资料/slides/chapter16爬虫/test.html', encoding='utf-8') as f:soup = BeautifulSoup(f, 'lxml') # str 就是html内容;file-like obj open:'lxml'print(soup.find_all(many_class))# [<h3 class="title highlight">python高级班</h3>]
keyword传参:使用关键字传参,如果参数名不是find系函数已定义的位置参数名,参数会被kwargs收集并被当做标签的属性来搜索。属性的传参可以是字符串、正则表达式对象、True、列表。
print(soup.find_all(id='first')) # id为first的所有节点列表
print(soup.find_all(id=re.compile('\w+'))) # 相当于找有id的所有节点
print(soup.find_all(id=True)) # 所有有id的节点
print(list(map(lambda x:x['id'], soup.find_all(id=True))))
print(soup.find_all(id=['first', re.compile(r'^sec')])) # 指定id的名称列表
print(soup.find_all(id=True, src=True)) # 相当于条件and,既有id又有src属性的节点列表
css的class的特殊处理:class是Python关键字,所以使用 class_ 。class是多值属性,可以匹配其中任意一个,也可以完全匹配。
print(soup.find_all(class_="content"))
print(soup.find_all(class_="title")) # 可以使用任意一个css类
print(soup.find_all(class_="highlight")) # 可以使用任意一个css类
print(soup.find_all(class_="highlight title")) # 顺序错了,找不到
print(soup.find_all(class_="title highlight")) # 顺序一致,找到,就是字符串完全匹配
attrs参数:attrs接收一个字典,字典的key为属性名,value可以是字符串、正则表达式对象、True、列表。可以多个属性
print(soup.find_all(attrs={'class':'title'}))
print(soup.find_all(attrs={'class':'highlight'}))
print(soup.find_all(attrs={'class':'title highlight'}))
print(soup.find_all(attrs={'id':True}))
print(soup.find_all(attrs={'id':re.compile(r'\d$')}))
print(list(map(lambda x:x.name, soup.find_all(attrs={
'id':True, 'src':True
}))))
text参数:可以通过text参数搜索文档中的字符串内容,接受字符串、正则表达式对象、True、列表
print(list(map(lambda x: (type(x), x), soup.find_all(text=re.compile('\w+'))))) # 返回文本类节点
print(list(map(lambda x: (type(x), x), soup.find_all(text=re.compile('[a-z]+')))))
print(soup.find_all(re.compile(r'^(h|p)'), text=re.compile('[a-z]+'))) # 相当于过滤出Tag对象,并看
它的string是否符合text参数的要求,返回Tag对象
limit参数:限制返回结果的数量
print(soup.find_all(id=True, limit=3)) # 返回列表中有3个结果
find_all()是非常常用的方法,可以简化省略掉:
print(soup('img')) # 所有img标签对象的列表,不等价于soup.img
print(soup.img) # 深度优先第一个img
print(soup.a.find_all(text=True)) # 返回文本
print(soup.a(text=True)) # 返回文本,和上面等价
print(soup('a', text=True)) # 返回a标签对象
print(soup.find_all('img', attrs={'id':'bg1'}))
print(soup('img', attrs={'id':'bg1'})) # find_all的省略
print(soup('img', attrs={'id':re.compile('1')}))
find方法:find( name , attrs , recursive , text , **kwargs ) 参数几乎和fifind_all一样。 找到了,fifind_all返回一个列表,而fifind返回一个单值,元素对象。 找不到,fifind_all返回一个空列表,而fifind返回一个None。
print(soup.find('img', attrs={'id':'bg1'}).attrs.get('src', 'magedu'))
print(soup.find('img', attrs={'id':'bg1'}).get('src')) # 简化了attrs
print(soup.find('img', attrs={'id':'bg1'})['src'])
CSS选择器 ***
和JQuery一样,可以使用CSS选择器来查找节点,使用soup.select()方法,select方法支持大部分CSS选择器,返回列表。CSS中,标签名直接使用,类名前加.点号,id名前加#井号。
from bs4 import BeautifulSoup# features推荐写清楚
with open('E:/马哥教育培训资料/slides/chapter16爬虫/test.html', encoding='utf-8') as f:soup = BeautifulSoup(f, 'lxml') # str 就是html内容;file-like obj open:'lxml'# 元素选择器print(1, soup.select('p')) # 所有的p标签# 类选择器print(2, soup.select('.title'))# 使用了伪类# 直接子标签是p的同类型的所有p标签中的第二个# (同类型)同标签名p的第2个,伪类只实现了nth-of-type,且要求是数字print(3, soup.select('div.content > p:nth-of-type(2)')) # 只实现了这个伪类# id选择器print(4, soup.select('p#second'))print(5, soup.select('#bg1'))# 后代选择器print(6, soup.select('div p')) # div下逐层找pprint(7, soup.select('div div p')) # div下逐层找div下逐层找p# 子选择器,直接后代print(8, soup.select('div > p')) # div下直接子标签的p,有2个# 相邻兄弟选择器print(9, soup.select('div p:nth-of-type(1) + [src]')) # 返回[]print(9, soup.select('div p:nth-of-type(1) + p')) # 返回[]print(9, soup.select('div > p:nth-of-type(2) + input')) # 返回input Tagprint(9, soup.select('div > p:nth-of-type(2) + [type]')) # 同上# 普通兄弟选择器print(10, soup.select('div p:nth-of-type(1) ~ [src]')) # 返回2个img# 属性选择器print(11, soup.select('[src]')) # 有属性srcprint(12, soup.select('[src="/"]')) # 属性src等于/print(13, soup.select('[src="http://www.magedu.com/"]')) # 完全匹配print(14, soup.select('[src^="http://www"]')) # 以http://www开头print(15, soup.select('[src$="com/"]')) # 以com/结尾print(16, soup.select('img[src*="magedu"]')) # 包含mageduprint(17, soup.select('img[src*=".com"]')) # 包含.comprint(18, soup.select('[class="title highlight"]'))print(19, soup.select('[class~=title]')) # 多值属性中有一个title
获取文本内容:
from bs4 import BeautifulSoup# features推荐写清楚
with open('E:/马哥教育培训资料/slides/chapter16爬虫/test.html', encoding='utf-8') as f:soup = BeautifulSoup(f, 'lxml') # str 就是html内容;file-like obj open:'lxml'ele = soup.select('div') # 所有的div标签print(ele[0].string, end='\n------------\n') # 内容仅仅只能是文本类型,否则返回Noneprint(list(ele[0].strings), end='\n------------\n') # 迭代保留空白字符print(list(ele[0].stripped_strings), end='\n------------\n') # 迭代不保留空白字符print(ele[0], end='\n------------\n')print(ele[0].text, end='\n------------\n') # 本质上就是get_text(),保留空白字符的stringsprint(ele[0].get_text(), end='\n------------\n') # 迭代并join,保留空白字符,strip默认为Falseprint(ele[0].get_text(strip=True)) # 迭代并join,不保留空白字符
2.4 Json解析
拿到一个Json字符串,如果想提取其中的部分内容,就需要遍历了。在遍历过程中进行判断。还有一种方式,类似于XPath,叫做JsonPath。安装:$ pip install jsonpath
import requests
import simplejson
from jsonpath import jsonpathurl = "https://movie.douban.com/j/search_subjects?type=movie&tag=%E7%83%AD%E9%97%A8&page_limit=50&page_start=0"headers = {'User-agent': "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) \Chrome/55.0.2883.75 Safari/537.36"}
response = requests.get(url, headers=headers)with response:text = response.textprint(type(text), text)data = simplejson.loads(text)print(data)# //subjects# subjects = jsonpath(data, '$..subjects') # 找不到就返回bool的False# if isinstance(subjects, list) and len(subjects) == 1:# print(subjects)# for subject in subjects[0]:# print(subject.get['title'])# //subjects[rate > 8]/title $.subjects[?(@.rate >8)]subjects = jsonpath(data, '$.subjects[?(@.rate > "8")].title') # 找不到就返回bool的False# if isinstance(subjects, list) and len(subjects) == 1:print(subjects)
python爬虫解析库(Xpath、beautiful soup、Jsonpath)相关推荐
- python xpath语法-Python爬虫 | 解析库Xpath的使用
first itemsecond itemthird itemfourth itemfifth item
- Python爬虫 解析库的使用
已写章节 第一章 网络爬虫入门 第二章 基本库的使用 第三章 解析库的使用 第四章 数据存储 第五章 动态网页的抓取 文章目录 已写章节 第三章 解析库的使用 3.1BeautifulSoup 3.1 ...
- Python 爬虫利器二之 Beautiful Soup 的用法
上一节我们介绍了正则表达式,它的内容其实还是蛮多的,如果一个正则匹配稍有差池,那可能程序就处在永久的循环之中,而且有的小伙伴们也对写正则表达式的写法用得不熟练,没关系,我们还有一个更强大的工具,叫 B ...
- 两万字教会你解析库之Beautiful Soup
目录 1.简介 2.准备工作 3.解析器 4.基本用法 5.节点选择器 5.1选择元素 5.2提取信息 5.3嵌套选择 5.4关联选择 6.方法选择器 7. css 选择器 7.1 嵌套选择 7.2 ...
- Python爬虫利器二之Beautiful Soup的用法
如果一个正则匹配稍有差池,那可能程序就处在永久的循环之中,没关系,我们还有一个更强大的工具,叫Beautiful Soup,有了它我们可以很方便地提取出HTML或XML标签中的内容. 1. Beaut ...
- Python爬虫(三)Beautiful Soup 实战,爬取前程无忧网站
Beautiful Soup介绍 Beautiful Soup提供一些简单的.python式的函数用来处理导航.搜索.修改分析树等功能. Beautiful Soup自动将输入文档转换为Unicode ...
- 爬虫解析库xpath
# xpath简介 XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言.用于在 XML 文档中通过元素和属性进行导航. XPath基于XM ...
- Python网络解析库Xpath,妈妈再也不会担心我不会解析了
本文同步发表于我的微信公众号,扫一扫文章底部的二维码或在微信搜索 极客导航 即可关注,每个工作日都有文章更新. 一.概况 前两篇我们把网络库Requests大概的用法学了一遍,把网站上的每页数据请求下 ...
- python利器怎么用-Python爬虫利器二之Beautiful Soup的用法
The Dormouse's story Once upon a time there were three little sisters; and their names were , Lacie ...
最新文章
- 看了看カルタグラ~魂ノ苦悩~(カルタグラ~ツキ狂イノ病~PS2移植版)的官网...
- Quartz-异常处理
- RPNet++:人脸对齐faceAlignment和基于CNN的三维人脸恢复
- java 置信区间_仅从均值和标准差绘制置信区间
- Tomcat 中文路径乱码
- 10 行代码构建常见目标检测应用
- 合肥工贸高级技工学校计算机系,合肥工贸高级技工学校
- python基础编程语法-编程入门02:Python基础语法
- 顺序表的简单操作代码(c++实现)
- 苍穹影视V20七彩视界免授权开源源码
- python小说爬虫练习
- 高斯-拉格朗日(Gauss-Legendre )Ⅱ型求积公式 数值分析 勘误 P111
- html flv jquery 插件,基于js与flash实现的网站flv视频播放插件代码
- 屏蔽烦人的百度搜索热点
- 【ITool】js多个页面传值
- 阳离子铱配合物(Ir1+)|(Ir2-)|Ir(dmecf3ppz)2bpy+(PF6)-齐岳合成
- html设置鼠标移入移出样式,鼠标移入移出_CSS3实现鼠标移入移出时改变样式的效果...
- 各类支付通道大全以及支付通道选择
- html文本框后面加一个按钮怎么对齐,怎样对齐文本框和图像(image)按钮实现三点一线...
- 串口干扰 linux复位,消除RS422串口干扰的方法与流程
热门文章
- 物联网发展预期与展望
- 题目1198:a+b-----没有AC掉,,,,,借鉴了别人的一份,还有carr(c[len] = carr)(++len);是什么意思?...
- Google图书馆现在开幕
- Git: checkout的用法总结(1)
- 智慧城市,离我们还有多远?
- Python——返回函数
- Db2 load 导致表空间pengding
- 阿里云短信验证服务详细基础教程
- 2018 ACM-ICPC青岛现场赛 B题 Kawa Exam 题解 ZOJ 4059
- OpenCV(C++)---绘制形状与文字