html_doc = """
<html><head><title>The Dormouse's story</title></head><body>
<p class="title"><b>The Dormouse's story</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>
"""
from bs4 import BeautifulSoup
bsobj = BeautifulSoup(html_doc,'html.parser') #转化成bs对象,html格式,BeautifulSoup有检验html格式,若有缺失标签,会自动补齐
bsobj = BeautifulSoup(html_doc,'xml')#xml格式
print(bsobj.prettify())
from bs4 import BeautifulSoup
soup_html = BeautifulSoup(open('C:/Users/Administrator/Desktop/hello.html').read(),'html.parser')#参数可以是一个文件句柄
soup_html
#bsobj.标签名
bsobj.title
bsobj.title.name
bsobj.p#获取第一个P标签
bsobj.p['class']#p标签的class属性值
bsobj.a
#结合find_all和find方法使用
bsobj.find_all('a')#获取所有的a标签,以列表形式返回
bsobj.find('a')#获取第一个a标签
bsobj.find(id='link2')
bsobj.find_all('a')[0].get('href')#获取第一个a标签的href属性值
bsobj.find('a').get('href')#获取第一个a标签的href属性值
bsobj.a.get_text()#获取第一个a标签的内容
#对象种类
#Tag
type(bsobj.title)#bs4.element.Tag
#Tag的名称
bsobj.title.name#'title'
#bsobj.title.name='Title'#修改标签的名称
#Tag Attributes
bsobj.find('a').attrs#获取a标签的属性,以字典形式返回
bsobj.a.attrs
bsobj.a['href']#获取a标签href属性值
bsobj.a['class']
bsobj.a['id']='link22'#修改a标签的id属性值
del bsobj.a['id']#删除a标签的id属性
bsobj.a['id']='link1'#a标签添加id属性
bsobj.a
#多值属性
#html支持多值属性
obj =BeautifulSoup('<p class="aaa bbb"></p>','html.parser')
obj.p['class']#返回['aaa', 'bbb']
#xml不支持多值属性
obj =BeautifulSoup('<p class="aaa bbb"></p>','xml')
obj.p['class']#返回'aaa bbb'
#获取标签的内容
bsobj.a.string
bsobj.a.get_text()
type(bsobj.a.string)#bs4.element.NavigableString(可遍历字符串)
type(bsobj.a.get_text())#str
bsobj.a.string='Elsie'#修改a标签的内容
bsobj.a.string.replace_with('eee')#替换a标签的内容
bsobj.a.string
#BeautifulSoup对象表示的是一个文档的全部内容,可以理解为一个Tag对象,但其没有name和attribute属性,但有一个特殊的.name属性
bsobj.name#'[document]'
comment_str = "<b><!--Hey, buddy. Want to buy a used parser?--></b>"
soup = BeautifulSoup(comment_str)
comment = soup.b.string
type(comment)#bs4.element.Comment
#.contents 和.children:都指的是直接节点
print(bsobj.html.contents)
tag = bsobj.html.contents[1]
bsobj.html.contents[1].contents[1].contents
tag.contents
tag.contents[0].name
[child for child in bsobj.html.children]
#.descendants:后代子孙节点
[child for child in bsobj.html.descendants]#html后的所有子节点
#.string和.contents
print(bsobj.body.string)
bsobj.title
bsobj.title.string
bsobj.title.contents
soup_html.div.contents
soup_html.div.ul.contents #包含换行符
#soup_html.contents
#len(soup_html.div.ul.contents)
[child for child in soup_html.div.children]
[child for child in soup_html.div.descendants]
#.string:获取标签的内容,内容只含有单个字符串
soup_html.div.ul.li.string
soup_html.li.string
type(soup_html.li.string)#bs4.element.NavigableString
#.strings:获取标签的内容,内容可以含有多个字符串,可能包含空格或空行
type(soup_html.div.strings)#generator
[string for string in soup_html.div.strings]
#.stripped_strings:获取标签的内容,除去了首尾空格或空行
[string for string in soup_html.div.stripped_strings]
#兄弟节点:标准格式输出时,兄弟节点具有相同的缩进级别
#.next_sibling:下一个兄弟节点
print(soup_html.prettify())#格式化标准输出
soup_html.li.next_sibling#返回的是换行符
soup_html.li.next_sibling.next_sibling#返回第二个li标签
#.previous_sibling:上一个兄弟节点
soup_html.li.next_sibling.previous_sibling#返回第一li标签
#.next_siblings:当前节点下的所有兄弟节点
[sister for sister in soup_html.li.next_siblings]
#.previous_siblings:当前节点前的所有兄弟节点
[sister for sister in soup_html.find_all('li')[2].previous_siblings]#第三个li标签的previos兄弟,注意返回的顺序
#前进与回退
#.next_element:当前节点下一个节点元素
soup_html.li.next_element#<a href="link1.html">first item</a>
soup_html.li.next_element.next_element#first item
#.previous_element:当前节点的前一个节点元素
soup_html.li.next_element.next_element.previous_element#<a href="link1.html">first item</a>
#.next_elements:当前节点后的所有节点元素
list(soup_html.li.next_elements)
#.previous_elements:当前节点前的所有节点元素
list(soup_html.li.previous_elements)
#搜索文档
#find_all( name , attrs , recursive , string , **kwargs )
#根据标签名查找
soup_html.find_all('li')#获取所有li标签,以列表形式返回
#根据(标签名,属性值)查找
soup_html.find_all('li','item-0')#获取属性为item-0的li标签
#根据正则表达式查找
import re
soup_html.find_all(re.compile('^li'))#获取所有以li开头的标签
soup_html.find_all(re.compile('u'))#获取标签名中含有u的标签
#根据列表中的元素查找
soup_html.find_all(['li','ul'])#获取li、ul标签
soup_html.find_all(('li','item-0'))
soup_html.find_all(('li','ul'))
#布尔类型查找
[tag.name for tag in soup_html.find_all(True)]
#根据方法查找
def has_class(tag):
return tag.has_attr('class')
soup_html.find_all(has_class)#查找函数class属性的标签
#class属性访问时,需注意不能用class关键,需用class_
soup_html.find_all(class_= re.compile('item-\d'))
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</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>
"""
from bs4 import BeautifulSoup
soup = BeautifulSoup(html_doc,'html.parser')
print(soup.prettify())
soup.find_all('title')#[<title>The Dormouse's story</title>]
soup.find_all('p','title')#[<p class="title"><b>The Dormouse's story</b></p>]
soup.find_all('p',{'class':'title'})#[<p class="title"><b>The Dormouse's story</b></p>]
soup.find_all('a')
soup.find_all(id='link2')#[<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]
import re
soup.find_all(string = re.compile('sisters'))#查找标签内容中含有sisters
soup.find_all(id=True)
soup.find_all(href = re.compile('elsie'),id='link1')
#在HTML5中data属性搜索不能使用
data_soup = BeautifulSoup('<div data-foo="value">foo!</div>')
#data_soup.find_all(data-foo="value")#keyword can't be an expression
#attrs参数定义一个字典参数老搜索包含特殊属性的标签
data_soup.find_all(attrs={'data-foo':'value'})
#find_all( name , attrs , recursive , string , **kwargs ):name表示标签名 keyword:指定名称属性=属性值
#按CSS搜索:CSS中class关键字是python中的保留字,需通过class_参数搜索
soup.find_all('a',class_='sister')#class_=字符串
soup.find_all(class_ = re.compile('itl'))#class_=正则表达式
def has_six_character(css_class):
return css_class is not None and len(css_class)==6
soup.find_all(class_=has_six_character) #class_=方法
#标签的class属性多值
css_soup = BeautifulSoup('<p class="body strikeout"></p>')
css_soup.find_all('p', class_='strikeout')#[<p class="body strikeout"></p>]
css_soup.find_all('p' ,class_='body')#结果同上
css_soup.find_all('p' ,class_='body strikeout')#class_完全匹配
css_soup.find_all('p', attrs={'class': 'body strikeout'})
#sting参数:可以搜索文档中字符串内容
soup.find_all(string = 'Elsie')
soup.find_all(string=['Tillie', 'Elsie', 'Lacie'])
soup.find_all(string = re.compile('Dormous'))
def only_string(s):
return s==s.parent.string
soup.find_all(string=only_string)
soup.find_all('a',string='Elsie')
#limit参数:限制返回的结果记录数
soup.find_all('a',limit=3)
#recursive参数:find_all()返回当前满足过滤器的所有子孙节点,使用recursive=False只查找直接子节点
soup.html.find_all('title')#[<title>The Dormouse's story</title>]
soup.html.find_all('title',recursive=False)#[]<title>不是html标签的直接子节点
soup.html.find_all('head',recursive=False)#[<head><title>The Dormouse's story</title></head>]
soup.a#第一个a标签
soup('a')#所有a标签
soup.find_all('a')#所有a标签
soup.title(string = True)#["The Dormouse's story"]
soup.title.find_all(string=True)#["The Dormouse's story"]
soup.title.get_text()#"The Dormouse's story"
#find():用法同find_all相同,find_all结果以列表形式返回,find直接返回结果,find_all找不到时返回[],find返回None
soup.find('a')
soup.find_all('a',limit=1)
#find_all()和find()只搜索当前节点的所有子节点
#find_parents()和find_parent():用于搜索当前节点的父辈节点
#find_next_siblings()和find_next_sibling():用于搜索当前节点后面的兄弟节点
#find_previous_siblings()和find_previous_sibling():用于搜索当前节点前面的兄弟节点
#find_all_next()和find_next():用于搜索当前节点后的所有标签节点和字符串节点
#find_all_previous()和find_previous():用于搜索当前节点前的所有标签节点和字符串节点
#CSS选择器
#.select()
soup.select('title')#[<title>The Dormouse's story</title>]
soup.select('html head title')#通过标签逐层查找
soup.select('body a')
#逐层查找
soup.select('p > a')#p标签下的直接子标签a
soup.select('body > title')
soup.select('p > #link1')#id属性值加#
soup.select('p > .sister')#class属性值加.
#查找兄弟标签
soup.select('#link1 ~ .sister')#满足条件的所有兄弟标签
soup.select('#link1 + .sister')#满足条件的第一个兄弟标签
#通过CSS的class属性查找
soup.select('.sister')
soup.select('[class~=sister]')
#通过id属性查找
soup.select('#link1')#查找属性id='link1'的所有标签
soup.select('a#link2')#查找属性id='link2'的a标签
#多中CSS选择器查询元素
soup.select('#link1,#link2')
soup.select('#link1,.title')
#是否存在某个属性查找
soup.select('a[href]')
#通过某个属性值查找
soup.select('a[href="http://example.com/elsie"]')#属性值完全匹配
soup.select('a[href^="http://example.com"]')#属性值以http://example.com开头
soup.select('a[href$="elsie"]')#属性值以elsie结尾
soup.select('a[href*=".com/el"]')#属性值包含.com/el
#.select_one():返回查找到的第一个元素
soup.select_one('.sister')
#修改文档树
#修改Tag的名称和属性
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = soup.b
tag.name= 'a'#修改b标签名
tag['class']='aaa'#修改a标签的class属性值
tag['id']=1#a标签添加id属性
del tag['id']#删除a标签的id属性
#修改.string
soup = BeautifulSoup('<a href="http://example.com/">I linked to <i>example.com</i></a>')
soup.a.string='new link text'#a标签中的子标签也被覆盖了
soup.a#<a href="http://example.com/">new link text</a>
#.append():标签中追加内容
soup.a.append(',请点我')
soup.a#<a href="http://example.com/">new link text,请点我</a>
soup.a.contents#['new link text', ',请点我']
from bs4.element import NavigableString
soup.a.append(NavigableString(' hello,你好!'))
from bs4 import Comment
soup.a.append(soup.new_string('nice to ....',Comment))#添加注释信息
soup.a
#new_tag():新增标签
soup1 = BeautifulSoup('<b></b>')
soup1.b['class']='bbbb'
soup1.b.string='hello world'
soup1.b.append(soup1.new_tag('a'))
soup1.b.a.append('aaaa dddg')
soup1.b
#insert():在指定位置追加内容
soup1.b.insert(0,'hi world! ')
#insert_before():在当前节点或字符串节点前插入内容
soup1.b.a.insert_before('!!!!!world')
soup1.b
#insert_after():在当前节点或字符串节点后插入内容
soup1.b.a.insert_after(' hello ')
soup1.b
#clear():移除当前标签的内容
soup1.a.clear()#将a标签中的内容移除
soup1.b
#extract():将标签移除文档树
soup1.a.extract()#<a></a>
soup1.b#<b class="bbbb">hi world! hello world!!!!!world hello </b>
#decompose():将当前节点移除文档树并完全销毁
soup1.b.append(soup1.new_tag('a'))
soup1.b.a.append('aaaa dddg')
soup1.a.decompose()#返回None
soup1.b
#replace_with():用新标签或字符串替换文档树中的内容
new_tag = soup1.new_tag('c')
new_tag.string = 'cccc'
soup1.b.append(soup1.new_tag('a'))
soup1.b.a.append('aaaa dddg')
soup1.a.replace_with(new_tag)#返回a标签<a>aaaa dddg</a>
soup1.b#a标签替换成c标签<b class="bbbb">hi world! hello world!!!!!world hello <c>cccc</c></b>
soup1.c.string.replace_with('ddddd')#返回被替换的字符串cccc
soup1.b#<b class="bbbb">hi world! hello world!!!!!world hello <c>ddddd</c></b>
#wrap():对指定标签元素进行包装,返回包装后的结果
soup1.c.string.wrap(soup1.new_tag('d'))#<d>ddddd</d>
soup1.b.wrap(soup1.new_tag('tr'))#<tr><b class="bbbb">hi world! hello world!!!!!world hello <c><d>ddddd</d></c></b></tr>
#unwrap():移除指定标签,只是移除标签名称,其内容不会移除
soup1.b
soup1.d.unwrap()#<c></c>
soup1.b
#prettify():格式化输出,将文档树格式化后以utf-8编码输出,每个xml/html标签独占一行
soup1.prettify()
print(soup1.prettify())#bs对象调用
print(soup1.b.prettify())#标签节点也可以调用
#str()和unicode()压缩输出
str(soup1)
#get_text():获取标签的文本内容,包含子孙标签中的内容,以unicode字符串格式返回
soup1.b.get_text()
soup1.b.get_text(',')
soup1.b.find_all(string=True)
#解析部分文档:使用SoupStrainer对象作为parse_only参数传给BeautifulSoup的构造方法,也可以作为搜索文档树的参数
html_doc = """
<html><head><title>The Dormouse's story</title></head>
<body>
<p class="title"><b>The Dormouse's story</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>
"""
from bs4 import BeautifulSoup
from bs4 import SoupStrainer
only_a_tags = SoupStrainer('a')
soup = BeautifulSoup(html_doc,'html.parser',parse_only=only_a_tags)
print(soup.prettify())
def is_short_string(string):
return len(string)<10
only_short_strings = SoupStrainer(is_short_string)
soup.find_all(only_short_strings)