1.4Beautiful Soup

Beautiful Soup 是一个可以从 HTML 或 XML 文件中提取数据的 Python 库

Beautiful Soup简介

Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。
它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。

安装

pip install beautifulsoup4
#安装Beautifulsoup4
pip install lxml
#安装解析器

基本用法

<--示例代码-->
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="sister"><b>$37</b></p>
<p class="story" id="p">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" >Elsie</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_doc, 'lxml')

# 具备自动补全html标签功能
print(soup)

# 美化html便签
html_doc = soup.prettify()
print(html_doc)

遍历文档树

主要看标黑的

1、直接使用 '.' 来查找,只能找到第一个,返回的是一个对象

# 直接选择标签(返回的是一个对象)
print(soup.a)  # 获取第一个a标签
print(soup.p)  # 获取第一个p标签
print(type(soup.a))  # <class 'bs4.element.Tag'>

2、获取标签的名称(没什么用)

print(soup.a.name)  # 获取a标签的名字

3、获取标签的属性(也没什么用)

方式一

soup = BeautifulSoup(html_doc, 'lxml')
res = soup.p
print(res['class'])  # class 可以有多个,所以是列表
# ['sister']

方式二

print(soup.a.arrts)  # 获取a标签内所有的属性
# {'href': 'http://example.com/elsie', 'class': ['sister']}
print(res.a.attrs['class'])
# ['sister']

4、获取标签的内容

print(soup.p.text)  # 所有层级都拿出来拼到一起
print(soup.string)  # 只有 1 层,才能取出
pring(list(soup.strings))  # 把每次取出来都做成一个生成器
print(soup.a.arrts['href'])  # 获取a标签内的href属性
#http://example.com/elsie

5、嵌套选择

print(soup.p.b)   #获取第一个p标签内的b标签		#<b>$37</b>
print(soup.p.b.text)  # 打印b标签内的文本		  #$37

6、子节点、子孙节点(不经常用)

print(soup.p.children)	 # 获取第一个p标签所有的子节点,返回的是一个迭代器
print(list(soup.p.children))  # list转成列表

7、父节点、祖先节点(不经常用)

print(soup.a.parent)  # 获取第一个a标签内的父节点
# 获取祖先节点(爸爸,爸爸的爸爸,爸爸的爸爸的爸爸...以此类推)
print(list(soup.a.parents))  # 获取第一个a标签的祖先节点,返回的是一个生成器

8、兄弟节点(不经常用)

# (sibling: 兄弟姐妹)
# 获取下一个兄弟节点   
print(soup.a.next_sibling)
# 获取下一个的所有兄弟节点,返回的是一个生成器
print(soup.a.next_siblings)
print(list(soup.a.next_siblings)) 
# 获取上一个兄弟节点
print(soup.a.previous_sibling)
# 获取上一个的所有兄弟节点,返回的是一个生成器
print(list(soup.a.previous_siblings))

搜索文档树

BeautifulSoup定义了很多搜索方法,这里着重介绍2个:find() find_all(),两个配合使用

1、字符串查找 引号内是字符串

print(soup.find('p'))	#获取第一个p标签
print(soup.find_all('p'))	#获取所有的p标签
print(soup.find_all(class_='title'))  # 获取所有 class 为 title 的标签
print(soup.find_all(id='id_p'))  # 获取所有 id 为 id_p 的标签

print(soup.find(text='$37'))  # 查找标签内为$37的文本,推荐配合其他匹配规则使用,否则毫无意义
print(soup.find_all(name='p',text='$37'))  # 查找所有文本为$37的p标签
print(soup.find_all(href='http://example.com/elsie'))  # href属性为http://example.com/elsie的标签

# 组合使用
print(soup.find_all(name='a',attrs={'id':'link3'},text='Tillie'))  # 查找所有id为link3,文本为Tillie的a标签

2、正则表达式

import re
res = re.compile('^b')
res = soup.find_all(name=res)  # 查找以 b 开头的所有标签
res = re.compile('#con')
res = soup.find_all(id='res')  # 查找 id 为 con 开头的 id 的所有标签

3、列表

# 列表内可以匹配多个
ret=soup.find_all(name=['body','b'])
ret=soup.find_all(id=['id_p','link1'])
ret=soup.find_all(class_=['id_p','link1'])

and 关系
ret=soup.find_all(class_='title',name='p')

4、True

ret=soup.find_all(name=True)  # 所有有名字的标签
ret=soup.find_all(id=True)   # 所有有id的标签
ret=soup.find_all(href=True)  # 所有有herf属性的

5、方法(了解)

def has_class_but_no_id(tag):
    return tag.has_attr('class') and not tag.has_attr('id')
print(soup.find_all(has_class_but_no_id))

6、其他使用(了解)

ret=soup.find_all(attrs={'class':"title"})
ret=soup.find_all(attrs={'id':"id_p1",'class':'title'})

7、拿到标签,取属性,取 text

ret=soup.find_all(attrs={'id':"id_p",'class':'title'})
print(ret[0].text)

8、limit(限制条数)

# soup.find()  就是find_all limit=1
ret=soup.find_all(name=True,limit=2)  # 只要 2 条数据

9、recursive(了解)

# recursive=False (只找儿子)不递归查找,只找第一层
ret=soup.body.find_all(name='p',recursive=False)

CSS 选择器

1 css 选择器

Tag 对象.select("css 选择器")

print(soup.p.select('.sister'))
print(soup.select('.sister span'))

print(soup.select('#link1'))
print(soup.select('#link1 span'))

print(soup.select('#list-2 .element.xxx'))

print(soup.select('#list-2')[0].select('.element')) #可以一直select,但其实没必要,一条select就可以了

2 获取属性

print(soup.select('#list-2 h1')[0].attrs)

3 获取内容

print(soup.select('#list-2 h1')[0].get_text())

XPath 选择

/ 从根节点选取
// 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置
. 选取当前节点
.. 选取当前节点的父节点
@ 选取属性

示例文档
doc='''
<html>
 <head>
  <base href='http://example.com/' />
  <title>Example website</title>
 </head>
 <body>
  <div id='images'>
   <a href='image1.html' id="xxx">Name: My image 1 <br /><img src='image1_thumb.jpg' /></a>
   <h5>test</h5>
   <a href='image2.html'>Name: My image 2 <br /><img src='image2_thumb.jpg' /></a>
   <a href='image3.html'>Name: My image 3 <br /><img src='image3_thumb.jpg' /></a>
   <a href='image4.html'>Name: My image 4 <br /><img src='image4_thumb.jpg' /></a>
   <a href='image5.html' class='li li-item' name='items'>Name: My image 5 <br /><img src='image5_thumb.jpg' /></a>
   <a href='image6.html' name='items'><span><h5>test</h5></span>Name: My image 6 <br /><img src='image6_thumb.jpg' /></a>
  </div>
 </body>
</html>
'''

1 所有节点

a=html.xpath('//*')

2 指定节点(结果为列表)

a=html.xpath('//head')

3 子节点,子孙节点

a=html.xpath('//div/a')

4 父节点

a=html.xpath('//body//a[@href="image1.html"]/..')
a=html.xpath('//body//a[@href="image1.html"]')
a=html.xpath('//body//a[1]/..')
也可以这样
a=html.xpath('//body//a[1]/parent::*')

5 属性匹配

a=html.xpath('//body//a[@href="image1.html"]')

6 文本获取 标签后加:/text()

a=html.xpath('//body//a[@href="image1.html"]/text()')
a=html.xpath('//body//a/text()')

7 属性获取 标签后:/@href

a=html.xpath('//body//a/@href')
# 注意从1 开始取(不是从0)
a=html.xpath('//body//a[3]/@href')

8 属性多值匹配

a=html.xpath('//body//a[@class="li"]')
a=html.xpath('//body//a[@href="image1.html"]')
a=html.xpath('//body//a[contains(@class,"li")]')
a=html.xpath('//body//a[contains(@class,"li")]/text()')
a=html.xpath('//body//a[contains(@class,"li")]/@name')

9 多属性匹配 or 和 and (了解)

a=html.xpath('//body//a[contains(@class,"li") or @name="items"]')
a=html.xpath('//body//a[contains(@class,"li") and @name="items"]/text()')
a=html.xpath('//body//a[contains(@class,"li")]/text()')

10 按序选择

a=html.xpath('//a[2]/text()')
a=html.xpath('//a[2]/@href')
# 取最后一个(了解)
a=html.xpath('//a[last()]/@href')
a=html.xpath('//a[last()]/text()')
# 位置小于3的
a=html.xpath('//a[position()<3]/@href')
a=html.xpath('//a[position()<3]/text()')
# 倒数第二个
a=html.xpath('//a[last()-2]/@href')

11 节点轴选择

# ancestor:祖先节点
# 使用了* 获取所有祖先节点
a=html.xpath('//a/ancestor::*')
# # 获取祖先节点中的div
# a=html.xpath('//a/ancestor::div')
# a=html.xpath('//a/ancestor::div/a[2]/text()')
# attribute:属性值
# a=html.xpath('//a[1]/attribute::*')
# a=html.xpath('//a[1]/@href')
# child:直接子节点
# a=html.xpath('//a[1]/child::*')
# a=html.xpath('//a[1]/img/@src')
# descendant:所有子孙节点
# a=html.xpath('//a[6]/descendant::*')
# following:当前节点之后所有节点(递归)
# a=html.xpath('//a[1]/following::*')
# a=html.xpath('//a[1]/following::*[1]/@href')
# following-sibling:当前节点之后同级节点(同级)
# a=html.xpath('//a[1]/following-sibling::*')
# a=html.xpath('//a[1]/following-sibling::a')
# a=html.xpath('//a[1]/following-sibling::*[2]')
# a=html.xpath('//a[1]/following-sibling::*[2]/@href')
posted @ 2020-10-06 21:18  短戈行  阅读(165)  评论(0编辑  收藏  举报