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')