BeautifulSoup总结

BeautifulSoup总结,直接上代码:

from bs4 import BeautifulSoup
import bs4
import lxml
html_str = """ <html><head><title> The Dormouse's story </title></head>
<body>
 <p class ="title story" name='pname'><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"  name=a1><!--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>
   </html>
   """

soup = BeautifulSoup(html_str, 'lxml')

# 1、直接调用tag对象,只匹配第一个。
print("title",soup.title)
print("a_tag:",soup.a)
print("p_tag:",soup.p)
# Tag中有两个最重要的属性:name和attributes。每个Tag都有自己的名字,通过. name来获取。示例如下:
# soup对象比较特殊,他的name是 [document],对于其他内部标签,输出的值为标签本身。
print("soup.name>>>",soup.name)   # get  [document]
print("soup.title.name>>>",soup.title.name)  # get  title
print("soup.a.name>>>",soup.a.name)  # a

# 对于标签的属性,和python中字典的调用方式一致
print("soup.a.[attributes]>>>",soup.a['name'])  # 第一个a标签中有一个自定义属性name="a1",
print("soup.a.[attributes]>>>",soup.a['href'])  # 得到url:http:// example.com/ elsie
print("soup.a.[attributes]>>>",soup.a['id'])  # 得到id的值
# print("soup.p.[attributes]>>>",soup.p['id'])  # 没有id 属性,所以报错,跟字典一样没有相应的键,报键错误KeyError: 'id'
print("soup.p.[attributes]>>>",soup.p['class'])  # ['', 'title']

# 另外一种获取方式是.attrs,用于获取Tag中所有的属性,返回值是一个字典,属性名是键,属性值的字典的值
print("soup.a.[attrs]>>>",soup.a.attrs)  # 'href': 'http:// example.com/ elsie', 'class': ['', 'sister'], 'id': ' link1', 'name': 'a1'}
print("soup.p.[attributes]>>>",soup.p.attrs)  #  {'class': ['title', 'story']}

# 2、NavigableString
# 我们已经得到了标记的内容,要想获取标记内部的文字怎么办呢?需要使用到.string
print(soup.p.string)  # The Dormouse's story
print(soup.a.string)  # Elsie
# BeatuifulSoup 使用NavigableString对象来包装Tag中的字符串
# 一个NavigableString字符床与Python中的Unicode字符串相同,通过unicode()方法可以将NavigableString转换成Unicode字符串

# 3 BeautifulSoup对象表示的是一个文档的全部内容,大部分时候可以把它当作Tag对象,是一个特殊的tag,
# 因为BeautifulSoup对象并不是真正的HTML或XML的对象,所以他
# 没有name和attribute属性。但是依然可以获取它的name和attribute属性
print(type(soup.name))  # <class 'str'>
print(soup.name)  # [document]
print(soup.attrs)  #{}

# 4、Comment 注释对象
print(soup.a.string)
if type(soup.a.string)== bs4.element.Comment:
    print(soup.a.string)

# 5遍历文档树
# 1)子节点
# 首先说一下直接子节点,Tag中的.contents和children是非常重要的。
# Tag的.content属性可以将Tag子节点以列表方式输出
print(soup.head.contents)
print(soup.head.contents[0].string)
print(soup.p.contents)
print(soup.p.contents[0].string)
#.children返回一个生成器,可以通过循环获取Tag的子节点
for child in soup.head.children:
    print(child)

#.descendants属性可以对所有tag的子孙节点进行递归循环
for child in soup.head.descendants:
    print("descendants>>>",child)


# 获取子节点的内容
# .string:如果一个标签里没有没有标签了。那么.string就返回标签里面的内容。
# 如果标签里面只有唯一一个标记了,那么.sting也会返回最里面的内容。
# 如果tag包含了多个子节点,tag就无法确定string方法调用的是哪个子节点的内容,.string的输出结果是None
print(soup.head.string)
print(soup.title.string)
print(soup.html.string)
# .strings 属性主要用于tag中包含多个字符串的情况,可以进行遍历循环
for string in soup.strings:
    print("strings>>>",repr(string))

# .striped_strings属性可以去掉输出字符串中包含的空格或空行
for string in soup.stripped_strings:
    print(string)


# 2)父节点
# 通过.parent属性来获取某个元素的父节点。html_str中,<head>标记是<title>的父节点
print("title>>>",soup.title)
print("title's parent>>>",soup.title.parent)
#通过.parents属性可以递归得到元素的所以父辈节点
print(soup.a)
for parent in soup.a.parents:
    if parent is None:
        print("parent is none>>>",parent)
    else:
        print("have parent>>>",parent.name)

# 3)兄弟节点
#.nwxt_sibling属性可以获取该节点的下一个兄弟节点。.previous_sibling则与之相反,如果节点不存在则返回None
print("p's next_sibling>>>",soup.p.next_sibling)
print("p's prev_sibling>>>",soup.p.prev_sibling)
print("next,next>>>",soup.p.next_sibling.next_sibling)

# 通过next_siblings 和previous_siblings属性可以对当前节点的兄弟节点进行迭代输出
for sibling in soup.a.next_siblings:
    print(repr(sibling))

# 4) 前后节点
# 前后节点需要使用next_element、previous_element这两个属性,它针对的是所以节点不分层次
# 例如<head><title>The Dormouser's story</title></head>中下一个节点是title
print(soup.head)
print("head's next tag>>>",soup.head.next_element)
# 如果想遍历所有的前后节点,使用.next_elements和.previous_elements的迭代器就可以向前或向后访问文档的解析内容
for element in soup.a.next_elements:
    print("all tags>>>",repr(element))

# 6 搜索文档树
# find_all(),用于搜索当前Tag的所有Tag子节点,并判断是否符合过滤器的条件
# find_all(name, attrs, recursive, text ,**kwargs)
# 1)name参数,可以查找所以名字为name的标签,字符串对象会被自动忽略。name参数取值可以是字符串、正则表达式、列表、True和方法
print("find all 'b' tag >>>",soup.find_all('b'))  # 查找文档中所以的<b>标签,返回列表
# 如果传入正则表达式作为参数,BeautifulSoup会通过正则表达式的match()来匹配内容

# 找到以b开头的标签,本例则是<body>和<b>标签都应该被找到
import re
for tag in soup.find_all(re.compile("^b")):
    print("find all tag start with 'b'>>>",tag.name)

# 如果传入列表参数,BeautifulSoup会将与列表中任一元素匹配的内容返回。
# 下面代码找到所有的<a>和<b>标签:

print("find all a & b>>>",soup.find_all(["a", "b"]),len(soup.find_all(["a", "b"])))
# 如果传入True,True代表可以匹配任何值
# 下面代码查找所有的tag,但是不会返回字符串节点:
for tag in soup.find_all(True):
    print("find all tags except string>>>",tag.name)

# 如果没有合适的过滤器,那么还可以定义一个方法
# 方法只接受一个元素参数Tag节点,如果这个方法返回True,表示当前元素匹配并且被找到,如果不是则返回False:
# 比如过滤包含class属性,也包含id属性的元素,代码如下:
def hasClass_id(tag):
    return tag.has_attr('class') and tag.has_attr('id')

def hasClass_Name(tag):
    return tag.has_attr('class') and tag.has_attr('name')
print("has class & id >>>",soup.find_all(hasClass_id))
print("has class & name>>>",soup.find_all(hasClass_Name))
# 2) kwargs参数
# kwargs 参数在Python中表示为keyword参数。如果一个指定名字的参数不是搜索内置的参数名,
# 搜索是会把该参数当作指定名Tag的属性来搜索。搜索指定名字的属性时可以使用的参数
# 值包括字符串、正则表达式、列表、True
# 如果包含id参数,BeautifulSoup会搜索每个tag的“id”属性
print("find id == link2>>",soup.find_all(id='link2'))

# 如果传入href参数,BeautifulSoup会搜索每个Tag的“href”属性
# 比如查找href属性中含有“elsie”的tag
print(soup.find_all(href=re.compile("elsie")))
# 下面代码在文档树中查找所有包含id属性的tag,无论id值是什么
print("has id attr>>>",soup.find_all(id=True))

# 使用class_可以过滤class属性
# class为“sister”的a标签
print(soup.find_all("a",class_="sister"))

# 使用多个指定名字参数可以同时过滤tag的多个属性
print("同时过滤多个参数》》》",soup.find_all(href=re.compile("elsie"),id='link1'))

# 有些tag属性在搜索不能使用,比如html5中的data-*属性
# data_soup = BeautifulSoup('<div data-foo="value">foo!</div>')
# data_soup.find_all(data-foo="value")
# 只能通过find_all()方法的attrs参数顶一个字典参数来搜索包含特殊属性的tag
data_soup = BeautifulSoup('<div data-foo="value">foo!</div>','lxml')
print("比如html5中的data-*属性>>",data_soup.find_all(attrs={"data-foo":"value"}))
# 3) text参数可以搜索文档中的字符串内容
#与name参数的可选值一样,text参数接受字符串、正则表达式、列表、True
print("The tag has text 'Elsie'>>>",soup.find_all(text="Elsie"))
print("tags has ...list>>>",soup.find_all(text=['Tillie','Elsie','Lacie']))
print("has text Dormouse>>>",soup.find_all(text=re.compile("Dormouse")))
# 虽然text参数用于搜索字符串,还可以与其他参数混合使用来过滤tag。
# BeautifulSoup会找到.string方法与text参数值相符的tag.
# 下面搜索包含“Elsie”的<a>标签
print("搜索包含“Elsie”的<a>标签>>>",soup.find_all("a", text="Elsie"))

# 4)limit 参数
# find_all()方法返回全部的搜索结果,如果文档树很大,那么搜索会很慢,如果不需要全部结果,可以使用limit参数限制返回结果的数量。
# 效果与SQL中的limit关键字类似,当搜索到的结果数量到limit的限制,就停止搜索返回结果
#下面代码中,文档树中有3个tag符合搜索条件,但是限制了返回2个
print("limit example>>>",soup.find_all("a",limit=2))

# 5) recursive参数
# 调用tag的find_all()方法时,BeautifulSoup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以设置参数
# recursive=False
print("all sub tag in title incudle grandson>>>",soup.find_all("title"))
print("all direction tag>>>",soup.find_all("title",recursive=False))

# 其他方法
# find(name,attrs,recursive,text,**kwargs),
# 与find_all用法类似,唯一区别是find_all()方法返回结果是所有满足要求的值组成的列表,而find()方法
# 直接返回find_all()搜索结果中的第一个值

# find_parents(name,attrs,recursive,text,**kwargs)
# find_parent(name,attrs,recursive,text,**kwargs)
# find_all()和find()只搜索当前节点的所有子节点,孙节点等。
# find_parents()和find_parent()用来搜索当前节点的父辈节点,搜索方法与普通tag的搜索方法相同,搜索文档包含的内容

# find_next_siblings(name,attrs,recursive,text,**kwargs)
# find_next_sibling(name,attrs,recursive,text,**kwargs)
# 这两个方法通过next_siblings属性对当前tag的所有后满解析的兄弟tag节点镜像迭代,find_next_siblings()
# 方法返回所有符合条件的后面的兄弟节点,find_next_sibling只返回符合条件的第一个tag节点

# find_all_next(name,attrs,recursive,text,**kwargs)
# find_next(name,attrs,recursive,text,**kwargs)

# find_all_previous(name,attrs,recursive,text,**kwargs)
# find_previous(name,attrs,recursive,text,**kwargs)

# 7、CSS选择器
# 使用soup.select()方法,返回类型是list。
# 1)通过标签名称查找
# 通过标签名称可以直接查找、逐层查找,也可以找到某个标签下的直接子标签和兄弟节点标签,
print(soup.select("title"))  # 查找title标签
print(soup.select("html head title"))  # 逐层查找title标签
# 查找直接子节点
# 查找head下的title标签
print("查找head下的title标签>>>",soup.select("head > title"))  # 注意 一定要有空格
print(" 查找p下的 id='link1'的标签>>>",soup.select("p > #link1"))  # 查找p下的 id="link1"的标签
# 查找兄弟节点
# 查找id="link1"之后class=sister的所有兄弟标签
print("id='link1'之后class=sister的所有兄弟标签>>>",soup.select("#link1 ~ .sister"))
# 查找紧跟着id="link1"之后class=sister的子标签
print("查找紧跟着id='link1'之后class=sister的子标签>>>",soup.select("#link1 + .sister"))

# 2)、通过CSS的类名查找
# 实例:
print("类名查找1>>>",soup.select(".sister"))
print("类名查找2>>>",soup.select("[class~=sister]"))
# 3)通过tag的id查找
print("通过tag的id查找1>>>",soup.select("#link1"))
print("通过tag的id查找2>>>",soup.select("a#link1"))
#4)通过是否存在某个属性查找
print("存在href属性的a>>>",soup.select('a[href]'))
# 5)通过属性值来查找
print(soup.select('a[href="http://example.com/elsie"]'))
print(soup.select('a[href^="http://example.com/"]'))
print(soup.select('a[href$="tillie"]'))
print(soup.select('a[href*=".com/el"]'))
print("last>>>",soup.select('a[href*=".com/el"]')[0].attrs['href'],type(soup.select('a[href*=".com/el"]')[0]))

搞定。

猜你喜欢

转载自blog.csdn.net/sinat_35886587/article/details/80553629