ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

BeautifulSoup4的简单应用

2021-12-14 14:30:01  阅读:190  来源: 互联网

标签:string 节点 soup tag 应用 简单 字符串 BeautifulSoup4 find


Install BS4

/usr/bin/pip3 install BeautifulSoup4
/usr/bin/pip3 install lxml

Parse XML

#!/usr/bin/python3
/usr/bin/python3

# 将一段文档传入BeautifulSoup 的构造方法,就能得到一个文档的对象, 可以传入一段字符串或一个文件句柄
from bs4 import BeautifulSoup

soup = BeautifulSoup(open("index.html"))
soup = BeautifulSoup("<html>data</html>")

#我这次要解析的是XML文档
soup = BeautifulSoup(open("test.xml"))

#Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种: Tag , NavigableString , BeautifulSoup , Comment 

Basic knowledge

  • tag

tag.name # 每个tag都有自己的名字,通过 .name 来获取
tag.name = "blockquote" # 如果改变了tag的name,那将影响所有通过当前Beautiful Soup对象生成的HTML文档
tag['class'] # 一个tag可能有很多个属性,tag的属性的操作方法与字典相同
tag.attrs  # 也可以直接”点”取属性, 比如: .attrs,将会返回键值对
#tag的属性可以被添加,删除或修改. 再说一次, tag的属性操作方法与字典一样
  • NavigableString

#字符串常被包含在tag内.Beautiful Soup用 NavigableString 类来包装tag中的字符串
tag.string
#一个 NavigableString 字符串与Python中的Unicode字符串相同,并且还支持包含在 遍历文档树 和 搜索文档树 中的一些特性.
# 通过 unicode() 方法可以直接将 NavigableString 对象转换成Unicode字符串
# tag中包含的字符串不能编辑,但是可以被替换成其它的字符串,用 replace_with() 方法
tag.string.replace_with("No longer bold")

#其实还有append 、 insert 、clear等方法,这里没有提及

# 如果想在Beautiful Soup之外使用 NavigableString 对象,需要调用 unicode() 方法,将该对象转换成普通的Unicode字符串,否则就算Beautiful Soup已方法已经执行结束,该对象的输出也会带有对象的引用地址.这样会浪费内存
  • 子节点

# 一个Tag可能包含多个字符串或其它的Tag,这些都是这个Tag的子节点.Beautiful Soup提供了许多操作和遍历子节点的属性.
# 注意: Beautiful Soup中字符串节点不支持这些属性,因为字符串没有子节点
soup.head #操作文档树最简单的方法就是告诉它你想获取的tag的name.如果想获取 <head> 标签
soup.body.b # ,可以在文档树的tag中多次调用这个方法.下面的代码可以获取<body>标签中的第一个<b>标签

# 通过点取属性的方式只能获得当前名字的第一个tag
soup.a
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
soup.find_all('a') #获取所有a tag,返回一个list


# tag的 .contents 属性可以将tag的子节点以列表的方式输出

# 通过tag的 .children 生成器,可以对tag的子节点进行循环
for child in title_tag.children:
    print(child)
    # The Dormouse's story
# .contents 和 .children 属性仅包含tag的直接子节点 **************

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

    
# 如果tag只有一个 NavigableString 类型子节点,那么这个tag可以使用 .string 得到子节点
tag.string
# 如果一个tag仅有一个子节点,那么这个tag也可以使用 .string 方法,输出结果与当前唯一子节点的 .string 结果相同
# 如果tag包含了多个子节点,tag就无法确定 .string 方法应该调用哪个子节点的内容, .string 的输出结果是 None

# 如果tag中包含多个字符串,可以使用 .strings 来循环获取
for string in soup.strings:
    print(repr(string))

#输出的字符串中可能包含了很多空格或空行,使用 .stripped_strings 可以去除多余空白内容
for string in soup.stripped_strings:
    print(repr(string))
    

# 通过 .parent 属性来获取某个元素的父节点.在例子“爱丽丝”的文档中,<head>标签是<title>标签的父节点
title_tag.parent
# 通过元素的 .parents 属性可以递归得到元素的所有父辈节点,下面的例子使用了 .parents 方法遍历了<a>标签到根节点的所有节点
link = soup.a
link
# <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>
for parent in link.parents:
    if parent is None:
        print(parent)
    else:
        print(parent.name)

# 在文档树中,使用 .next_sibling 和 .previous_sibling 属性来查询兄弟节点
sibling_soup.b.next_sibling
sibling_soup.c.previous_sibling
# 通过 .next_siblings 和 .previous_siblings 属性可以对当前节点的兄弟节点迭代输出


# .next_element 属性指向解析过程中下一个被解析的对象(字符串或tag),结果可能与 .next_sibling 相同,但通常是不一样的
# .previous_element 属性刚好与 .next_element 相反,它指向当前被解析的对象的前一个解析对象
# 通过 .next_elements 和 .previous_elements 的迭代器就可以向前或向后访问文档的解析内容,就好像文档正在被解析一样

搜索文档树

过滤器

  • 字符串

#最简单的过滤器是字符串.在搜索方法中传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容,下面的例子用于查找文档中所有的<b>标签
soup.find_all('b')
  • 正则表达式

#如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的 match() 来匹配内容
#下面例子中找出所有以b开头的标签,这表示<body>和<b>标签都应该被找到
import re
for tag in soup.find_all(re.compile("^b")):
    print(tag.name)
    
for tag in soup.find_all(re.compile("t")):
    print(tag.name)
  • 列表

#如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回.下面代码找到文档中所有<a>标签和<b>标签
soup.find_all(["a", "b"])
  • True

#True 可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点
  • 方法

...

find_all()

#find_all( name , attrs , recursive , string , **kwargs )
#find_all() 方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件
soup.find_all("title") #tag.name == title 
soup.find_all("p", "title") #tag.name == p and tag.attrs == title
soup.find_all(id="link2") # 如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索
data_soup.find_all(attrs={"data-foo": "value"}) #通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的tag

#name 参数可以查找所有名字为 name 的tag,字符串对象会被自动忽略掉
#搜索 name 参数的值可以使任一类型的 过滤器 ,字符窜,正则表达式,列表,方法或是 True 
#如果一个指定名字的参数不是搜索内置的参数名,搜索时会把该参数当作指定名字tag的属性来搜索
#搜索指定名字的属性时可以使用的参数值包括 字符串 , 正则表达式 , 列表, True

#按照CSS类名搜索tag的功能非常实用,但标识CSS类名的关键字 class 在Python中是保留字,使用 class 做参数会导致语法错误.从Beautiful Soup的4.1.1版本开始,可以通过 class_ 参数搜索有指定CSS类名的tag
soup.find_all("a", class_="sister")
#class_ 参数同样接受不同类型的 过滤器 ,字符串,正则表达式,方法或 True :
soup.find_all(class_=re.compile("itl"))

#通过 string 参数可以搜搜文档中的字符串内容
#string 参数接受 字符串 , 正则表达式 , 列表, True
soup.find_all(string="Elsie")
soup.find_all(string=re.compile("Dormouse"))
soup.find_all(string=["Tillie", "Elsie", "Lacie"])
soup.find_all("a", string="Elsie")

#find_all() 方法返回全部的搜索结构,如果文档树很大那么搜索会很慢.如果我们不需要全部结果,可以使用 limit 参数限制返回结果的数量
soup.find_all("a", limit=2)

#调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False
soup.html.find_all("title", recursive=False)

#记住: 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()

输出

  • 格式化输出
soup.prettify()
#prettify() 方法将Beautiful Soup的文档树格式化后以Unicode编码输出,每个XML/HTML标签都独占一行
  • 压缩输出
#如果只想得到结果字符串,不重视格式,那么可以对一个 BeautifulSoup 对象或 Tag 对象使用Python的 unicode() 或 str() 方法
#如果想在Beautiful Soup之外使用 NavigableString 对象,需要调用 unicode() 方法,将该对象转换成普通的Unicode字符串,否则就算Beautiful Soup已方法已经执行结束,该对象的输出也会带有对象的引用地址.这样会浪费内存

get_text()

#如果只想得到tag中包含的文本内容,那么可以调用 get_text() 方法,这个方法获取到tag中包含的所有文版内容包括子孙tag中的内容,并将结果作为Unicode字符串返回
soup.get_text()
soup.get_text("|") # 可以通过参数指定tag的文本内容的分隔符
soup.get_text("|", strip=True) #还可以去除获得文本内容的前后空白及特殊字符

#或者使用 .stripped_strings 生成器,获得文本列表后手动处理列表
[text for text in soup.stripped_strings]
# [u'I linked to', u'example.com']

标签:string,节点,soup,tag,应用,简单,字符串,BeautifulSoup4,find
来源: https://blog.csdn.net/jiangshandaiyou/article/details/121925789

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有