from bs4 import BeautifulSoup
# 这个字符串不是以</html>结尾的标准的字符串
html_doc ="""
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story<span>lqz</span></b><b>adfasdf<b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1">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>
"""
soup = BeautifulSoup(html_doc,'lxml')# print(soup)# 美化print(soup.prettify())
# 遍历(从边上开始寻找数据)、搜索(从任意位置开始寻找数据)###遍历文档树# 遍历文档树:即直接通过标签名字选择,特点是选择速度快,但如果存在多个相同的标签则只返回第一个# 1、用法 通过 . 遍历
a = soup.html.body.a # 找body下的第一个a
a = soup.a # 找soup下的第一个aprint(a)# 2、获取标签的名称# soup.a 是个对象
a = soup.a.name
print(a)# a# 3、获取标签的属性
a = soup.a.attrs
print(a)# {'href': 'http://example.com/elsie', 'class': ['sister'], 'id': 'link1'}print(a.get('id'))
a = soup.a.attrs.get('href')print(a)# 4、获取标签的内容---文本内容# 标签名.text:会把当前标签的子子孙孙的文本内容都拿出来,拼到一起# 标签名.string:当前标签有且只有自己(没有子标签),把文本内容拿出来# 标签名.strings:是generator生成器,把子子孙孙的文本内容放到生成器中# 1.<p class="title"><b>The Dormouse's <em>lqz</em>story<span>hhhhh</span></b></p>print(soup.p.text)# The Dormouse's lqzstoryhhhhhprint(soup.p.string)# Noneprint(list(soup.p.strings))# ["The Dormouse's ", 'lqz', 'story', 'hhhhh']# 2.<p class="title"><b>The Dormouse's story</b></p>print(soup.p.text)# The Dormouse's storyprint(soup.p.string)# The Dormouse's storyprint(list(soup.p.strings))# ["The Dormouse's story"]# 5、嵌套选择 . 完后可以继续再 .print(soup.head.title.text)# The Dormouse's storyprint(soup.html.body.a.text)# Elsie# 6、子节点、子孙节点# <p class="title"><b>The Dormouse's story<span>lqz</span></b><b>adfasdf<b></p>print(soup.p.contents)# p下所有子节点print(list(soup.p.children))# 得到一个迭代器,包含p下所有子节点for i, child inenumerate(soup.p.children):print(i, child)print(list(soup.p.descendants))# 获取子孙节点,p下所有的标签都会选择出来for i, child inenumerate(soup.p.descendants):print(i, child)# 7、父节点、祖先节点print(soup.a.parent)# 获取a标签的父节点print(soup.a.parents)# 找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲...print(list(soup.a.parents))# 生成器,找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲...# 8、兄弟节点print(soup.a.next_sibling)# 下一个兄弟,第一个是'/n'print(soup.a.previous_sibling)# 上一个兄弟,第一个是p标签中的文本拼接上/nprint(list(soup.a.next_siblings))# 下面的兄弟们=>生成器对象print(list(soup.a.previous_siblings))# 上面的兄弟们=>生成器对象
三 bs4搜索文档树
# find:找到最符合的第一个 find_all:找到所有
五种过滤器: 字符串、正则表达式、列表、True、方法
from bs4 import BeautifulSoup
html_doc ="""
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b class ='baby'>The Dormouse's story<span>lqz</span></b><b>adfasdf<b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1" xx="xx">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" name="zzz">Tillie</a>;
and they lived at the bottom of a well.</p>
<p class="story">...</p>
"""
soup = BeautifulSoup(html_doc,'lxml')# 五种过滤器: 字符串、正则表达式、列表、True、方法# 字符串 通过字符串查找
a = soup.find(name='a')
a = soup.find_all(name='a', class_='sister')
a = soup.find_all(name='a',id='link1')
a = soup.find(text='Elsie').parent
a = soup.find(href='http://example.com/elsie')# 括号中可以写 name,id,class_,href,text,所有属性
a = soup.find(xx='xx')# 括号中可以写 name:标签名,id,class_,href,text,所有属性
a = soup.find(attrs={'class':'sister'})# 可以通过attrs传属性
a = soup.find(attrs={'name':'zzz'})# 可以通过attrs传属性print(a)# 正则表达式import re
a = soup.find_all(re.compile('^b'))
a = soup.find_all(class_=re.compile('^b'))# 找出类名以b开头,结果有b标签# 找出所有有链接的标签
a = soup.find_all(href=re.compile('^http'))
a = soup.find_all(name=re.compile('^b'))# 可以寻找出所有图片地址print(a)# 列表
a = soup.find_all(name=['b','body','span'])# Soup会将与列表中任一元素匹配的内容返回
a = soup.find_all(class_=['sister','title'])print(a)# True
a = soup.find_all(href=True)# 打印出有href属性的标签
a = soup.find_all(src=True, name='img')print(a)# 方法
如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 ,如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 Falsedefhas_class_but_no_id(tag):# 查询所有有class但是没有id的标签return tag.has_attr('class')andnot tag.has_attr('id')print(soup.find_all(has_class_but_no_id))
3.2 其他用法
# find 本质就是find_all find的参数,就是find_all的参数,但是find_all比find多# recursive=True:是否递归查找,默认是True,如果写成false,只找第一层, limit=None
a = soup.find_all(name='html')
a = soup.find_all(name='html', recursive=False)# 联合遍历文档树使用,先遍历出p标签
a = soup.html.p.find(name='b', recursive=False)print(a)# limit=None 限制找几条
a = soup.find_all(name='a', limit=1)print(a)
四 css选择器
# 该模块提供了select方法来支持css,详见官网:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#id37
html_doc ="""
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b class ='baby'>The Dormouse's story<span>lqz</span></b><b>adfasdf<b></p>
<p class="story">Once upon a time there were three little sisters; and their names were
<a href="http://example.com/elsie" class="sister" id="link1" xx="xx"><span id="name">lqz</span>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" name="zzz">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')# 1、CSS选择器print(soup.select('.sister'))print(soup.p.select('.sister'))# []print(soup.select('.sister span'))print(soup.select('#link1'))print(soup.select('#link1 span'))print(soup.select('.sister')[0].select('#name'))# 可以一直select# 2、联合使用print(soup.p.find(name='b').select('span'))# 3、获取属性print(soup.select('.sister')[0].attrs)# 4、获取内容print(soup.select('.sister')[0].get_text())'''
div
.类名
#id号
div a # div下的子子孙孙中得a
div>a #div直接子节点
'''# 以后,基本所有的解析器都会支持两种解析:css,xpath,都可以去页面中复制import requests
# 爬取菜鸟教程
html_doc = requests.get('http://it028.com/css-selectors.html')# 更改乱码
html_doc.encoding = html_doc.apparent_encoding # 从页面中解析出编码方式# res.encoding = 'utf-8' # 直接指定编码是utf-8# print(res.text)from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc.text,'lxml')# 在网页中复制css:找出内容-->右键Copy-->Copy selector
res = soup.select('#content > table > tbody > tr:nth-child(16) > td:nth-child(3)')print(res)# [<td>选择活动链接</td>]# 复制xpath:找出内容-->右键Copy-->Copy XPathfrom lxml import etree
element = etree.HTML(html_doc.text)
res2 = element.xpath('//*[@id="content"]/table/tbody/tr[16]/td[3]/text()')print(res2)# ['选择活动链接']# 去页面中复制,不一定能找出来,浏览器中是有js代码的,使用requests访问页面,可能js没有执行完成,没有渲染完成。# selenium 使用:解决 requests 和不能执行js的问题,直接控制浏览器
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架