zoukankan      html  css  js  c++  java
  • Python3---Beautiful Soup

    转载文章:https://www.cnblogs.com/zhangxinqi/p/9218395.html

    Beautiful Soup是python的一个HTML或XML的解析库,我们可以用它来方便的从网页中提取数据,它拥有强大的API和多样的解析方式。

    Beautiful Soup的三个特点:

    • Beautiful Soup提供一些简单的方法和python式函数,用于浏览,搜索和修改解析树,它是一个工具箱,通过解析文档为用户提供需要抓取的数据
    • Beautiful Soup自动将转入稳定转换为Unicode编码,输出文档转换为UTF-8编码,不需要考虑编码,除非文档没有指定编码方式,这时只需要指定原始编码即可
    • Beautiful Soup位于流行的Python解析器(如lxml和html5lib)之上,允许您尝试不同的解析策略或交易速度以获得灵活性。

    1、Beautiful Soup4的安装配置

    Beautiful Soup4通过PyPi发布,所以可以通过系统管理包工具安装,包名字为beautifulsoup4

    $easy_install beautifulsoup4
    或者
    $pip install beautifulsoup4

    也可用通过下载源码包来安装:

    复制代码
    #wget  https://www.crummy.com/software/BeautifulSoup/bs4/download/4.0/beautifulsoup4-4.1.0.tar.gz
    #tar xf beautifulsoup4-4.1.0.tar.gz
    #cd beautifulsoup4
    #python setup.py install
    复制代码

    Beautiful Soup在解析时实际上是依赖解析器的,它除了支持python标准库中的HTML解析器外还支持第三方解析器如lxml

    Beautiful Soup支持的解析器,以及它们的优缺点:

    解析器使用方法优势劣势
    Python标准库 BeautifulSoup(markup,"html.parser")
    • Python的内置标准库
    • 执行速度适中
    • 文档容错能力强
    • Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差
    lxml HTML 解析器 BeautifulSoup(markup,"lxml")
    • 速度快
    • 文档容错能力强
    • 需要安装C语言库
    lxml XML 解析器

    BeautifulSoup(markup,["lxml", "xml"])

    BeautifulSoup(markup,"xml")

    • 速度快
    • 唯一支持XML的解析器
    • 需要安装C语言库
    html5lib BeautifulSoup(markup,"html5lib")
    • 最好的容错性
    • 以浏览器的方式解析文档
    • 生成HTML5格式的文档
    • 速度慢
    • 不依赖外部扩展

    安装解析器:

    $pip install lxml
    $pip install html5lib

    推荐使用lxml作为解析器,因为效率更高. 在Python2.7.3之前的版本和Python3中3.2.2之前的版本,必须安装lxml或html5lib, 因为那些Python版本的标准库中内置的HTML解析方法不够稳定

    2、BeautifulSoup的基本用法

    通过传入一段字符或一个文件句柄,BeautifulSoup的构造方法就能得到一个文档的对象,选择合适的解析器来解析文档,如手动指定将选择指定的解析器来解析文档,Beautiful Soup将复杂的HTML文档转换成一个复杂的树形结构,每个节点都是python对象,所有对象可以归纳为4种:Tag、NavigableString、BeautifulSoup、Comment

    注意:BeautifulSoup版本4的包是在bs4中引入的

    复制代码
    from bs4 import 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>
    """
    markup
    ="<b><!--Hey, buddy. Want to buy a used parser?--></b>"
    soup
    =BeautifulSoup(html_doc,"lxml")
    soup1
    =BeautifulSoup(markup,"lxml")
    tag
    =soup.a
    navstr
    =tag.string
    comment
    =soup1.b.string
    print(type(tag)) #Tag标签对象
    print(type(comment)) #Comment对象包含文档注释内容
    print(type(navstr)) #NavigableString对象包装字符串内容
    print(type(soup)) #BeautifulSoup对象为文档的全部内容

    #
    <class 'bs4.element.Tag'>
    <class 'bs4.element.Comment'>
    <class 'bs4.element.NavigableString'>
    <class 'bs4.BeautifulSoup'>

    复制代码

    (1)节点选择器(tag)

    直接调用节点的名称就可以选择节点元素,节点可以嵌套选择返回的类型都是bs4.element.Tag对象

    soup=BeautifulSoup(html_doc,'lxml')
    print(soup.head)  #获取head标签
    print(soup.p.b) #获取p节点下的b节点
    print(soup.a.string) #获取a标签下的文本,只获取第一个

    name属性获取节点名称:

    soup.body.name

    attrs属性获取节点属性,也可以字典的形式直接获取,返回的结果可能是列表或字符串类型,取决于节点类型

    soup.p.attrs    #获取p节点所有属性
    soup.p.attrs['class']  #获取p节点class属性
    soup.p['class']  #直接获取p节点class属性

    string属性获取节点元素包含的文本内容:

    soup.p.string   #获取第一个p节点下的文本内容

    contents属性获取节点的直接子节点,以列表的形式返回内容

    soup.body.contents   #是直接子节点,不包括子孙节点

    children属性获取的也是节点的直接子节点,只是以生成器的类型返回

    soup.body.children

    descendants属性获取子孙节点,返回生成器

    soup.body.descendants

    parent属性获取父节点,parents获取祖先节点,返回生成器

    soup.b.parent
    soup.b.parents

    next_sibling属性返回下一个兄弟节点,previous_sibling返回上一个兄弟节点,注意换行符也是一个节点,所以有时候在获取兄弟节点是通常是字符串或者空白

    soup.a.next_sibling
    soup.a.previous_sibling

    next_siblings和previous_sibling分别返回前面和后面的所有兄弟节点,返回生成器

    soup.a.next_siblings
    soup.a.previous_siblings

    next_element和previous_element属性获取下一个被解析的对象,或者上一个

    soup.a.next_element
    soup.a.previous_element

    next_elements和previous_elements迭代器向前或者后访问文档解析内容

    soup.a.next_elements
    soup.a.previous_elements

    (2)方法选择器

    前面使用的都是通过节点属性来选择的,这种方法非常快,但在进行比较复杂的选择时就不够灵活,幸好Beautiful Soup还为我们提供了一些查询方法,如fang_all()和find()等

    find_all(name,attrs,recursive,text,**kwargs):查询所有符合条件的元素,其中的参数

    name表示可以查找所有名字为name的标签(tag),也可以是过滤器,正则表达式,列表或者是True

    attrs表示传入的属性,可以通过attrs参数以字典的形式指定如常用属性id,attrs={'id':'123'},由于class属性是python中的关键字,所有在查询时需要在class后面加上下划线即class_='element',返回的结果是tag类型的列表

    text参数用来匹配节点的文本,传入的形式可以是字符串也可以是正则表达式对象

    recursive表示,如果只想搜索直接子节点可以将参数设为false:recursive=Flase

    limit参数,可以用来限制返回结果的数量,与SQL中的limit关键字类似

    复制代码
    import re
    from bs4 import 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>
    ddd
    <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>
    <span>中文</span>
    """

    soup=BeautifulSoup(html_doc,'lxml')
    print(type(soup))
    print(soup.find_all('span')) #标签查找
    print(soup.find_all('a',id='link1')) #属性加标签过滤
    print(soup.find_all('a',attrs={'class':'sister','id':'link3'})) #多属性
    print(soup.find_all('p',class_='title')) #class特殊性,此次传入的参数是**kwargs
    print(soup.find_all(text=re.compile('Tillie'))) #文本过滤
    print(soup.find_all('a',limit=2)) #限制输出数量

    #
    <class 'bs4.BeautifulSoup'>
    [
    <span>中文</span>]
    [
    <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
    [
    <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
    [
    <p class="title"><b>The Dormouse's story</b></p>]
    ['Tillie']
    [
    <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>, <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

    复制代码

    find( name , attrs , recursive , text , **kwargs ):它返回的是单个元素,也就是第一个匹配的元素,类型依然是tag类型

    参数同find_all()一样

    另外还有许多查询方法,其用法和前面介绍的find_all()方法完全相同,只不过查询范围不同,参数也一样

    find_parents(name , attrs , recursive , text , **kwargs )和find_parent(name , attrs , recursive , text , **kwargs ):前者返回所有祖先节点,后者返回直接父节点

    find_next_siblings(name , attrs , recursive , text , **kwargs )和find_next_sibling(name , attrs , recursive , text , **kwargs ):对当前tag后面的节点进行迭代,前者返回后面的所有兄弟节点,后者返回后面第一个兄弟节点

    find_previous_siblings(name , attrs , recursive , text , **kwargs )和find_previous_sibling(name , attrs , recursive , text , **kwargs ):对当前tag前面的节点进行迭代,前者返回前面的所有兄弟节点,后者返回前面的第一个兄弟节点

    find_all_next(name , attrs , recursive , text , **kwargs )和find_next(name , attrs , recursive , text , **kwargs ):对当前tag之后的tag和字符串进行迭代,前者返回所有符合条件的节点,后者返回第一个符合条件的节点

    find_all_previous()和find_previous():对当前tag之前的tag和字符串进行迭代,前者返回节点后所有符合条件的节点,后者返回第一个符合条件的节点

    (3)CSS选择器

    Beautiful Soup还提供了CSS选择器,如果多CSS选择器不熟悉可以参考下http://www.w3school.com.cn/cssref/css_selectors.asp

    在 Tag 或 BeautifulSoup 对象的 .select()方法中传入字符串参数,即可使用CSS选择器的语法找到tag:

    In [10]: soup.select('title')
    Out[10]: [<title>The Dormouse's story</title>]

    通过tag标签逐层查找:

    复制代码
    In [12]: soup.select('body a')
    Out[12]: 
    [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
     <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
     <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
    复制代码

    查找某个tag标签下的直接子标签:

    In [13]: soup.select('head > title')
    Out[13]: [<title>The Dormouse's story</title>]

    查找兄弟节点标签:

    In [14]: soup.select('#link1 ~ .sister')
    Out[14]: 
    [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
     <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

    通过CSS类名查找:

    复制代码
    In [15]: soup.select('.title')
    Out[15]: [<p class="title"><b>The Dormouse's story</b></p>]
    
    In [16]: soup.select('[class~=title]')
    Out[16]: [<p class="title"><b>The Dormouse's story</b></p>]
    复制代码

    通过tag的id查找:

    复制代码
    In [17]: soup.select('#link1')
    Out[17]: [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
    

    In [18]: soup.select('a#link2')
    Out[
    18]: [<a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>]

    复制代码

    通过是否存在某个属性来查找:

    复制代码
    In [20]: soup.select('a[href]')
    Out[20]: 
    [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
     <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
     <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]
    复制代码

    通过属性的值来查找匹配:

    复制代码
    In [22]: soup.select('a[href="http://example.com/elsie"]')
    Out[22]: [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]
    

    In [23]: soup.select('a[href^="http://example.com/"]') #匹配值的开头
    Out[23]:
    [
    <a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>,
    <a class="sister" href="http://example.com/lacie" id="link2">Lacie</a>,
    <a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

    In [24]: soup.select('a[href$="tillie"]') #匹配值的结尾
    Out[24]: [<a class="sister" href="http://example.com/tillie" id="link3">Tillie</a>]

    In [25]: soup.select('a[href*=".com/el"]') #模糊匹配
    Out[25]: [<a class="sister" href="http://example.com/elsie" id="link1">Elsie</a>]

    复制代码

    tag节点查找,方法选择器查找和CSS选择器查找三种方法的实现方式基本相似,tag相对于其他两种所有最快速的查找方式,但方法选择器提供更便利更复杂的查找方式,使用更如有上手。

    (4)tag修改方法

    Beautiful Soup的强项是文档的搜索功能,修改功能使用场景不是很多只做简单介绍,要了解更多修改方法请前往Beautiful Soup官方文档查看。

    Beautiful Soup可以实现改变tag标志的属性的值,添加或删除属性和内容,下面介绍一些常用的方法

    复制代码
    In [26]: markup='<a href="http://www.baidu.com/">baidu</a>'
    In [28]: soup=BeautifulSoup(markup,'lxml')
    In [29]: soup.a.string='百度'
    In [30]: soup.a
    Out[30]: <a href="http://www.baidu.com/">百度</a>
    #如果a节点下包括子也将被覆盖掉
    复制代码

    Tag.append() 方法想tag中添加内容,就好像Python的列表的 .append() 方法:

    复制代码
    In [30]: soup.a
    Out[30]: <a href="http://www.baidu.com/">百度</a>
    

    In [31]: soup.a.append('一下')

    In [32]: soup.a
    Out[
    32]: <a href="http://www.baidu.com/">百度一下</a>

    复制代码

    new_tag()方法用于创建一个tag标签

    复制代码
    In [33]: soup=BeautifulSoup('<b></b>','lxml')
    

    In [34]: new_tag=soup.new_tag('a',href="http://www.python.org") #创建tag,第一个参数必须为tag的名称

    In [
    35]: soup.b.append(new_tag) #添加到b节点下

    In [
    36]: new_tag.string='python' #为tag设置值

    In [
    37]: soup.b
    Out[
    37]: <b><a href="http://www.python.org">python</a></b>

    复制代码

    其他方法:

    insert()将元素插入到指定的位置

    inert_before()在当前tag或文本节点前插入内容

    insert_after()在当前tag或文本节点后插入内容

    clear()移除当前tag的内容

    extract()将当前tag移除文档数,并作为方法结果返回

    prettify()将Beautiful Soup的文档数格式化后以Unicode编码输出,tag节点也可以调用

    get_text()输出tag中包含的文本内容,包括子孙tag中的内容

    soup.original_encoding 属性记录了自动识别的编码结果

    from_encoding:参数在创建BeautifulSoup对象是可以用来指定编码,减少猜测编码的运行速度

    #解析部分文档,可以使用SoupStrainer类来创建一个内容过滤器,它接受同搜索方法相同的参数

    复制代码
    from bs4 import BeautifulSoup,SoupStrainer
    

    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>
    ddd
    <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>
    <span>中文</span>
    """

    only_a_tags = SoupStrainer('a') #顾虑器

    soup
    =BeautifulSoup(html_doc,'lxml',parse_only=only_a_tags)

    print(soup.prettify())

    #
    <a class="sister" href="http://example.com/elsie" id="link1">
    Elsie
    </a>
    <a class="sister" href="http://example.com/lacie" id="link2">
    Lacie
    </a>
    <a class="sister" href="http://example.com/tillie" id="link3">
    Tillie
    </a>

    复制代码

    #Beautiful Soup异常处理:

    HTMLParser.HTMLParseError:malformed     start    tag  

    HTMLParser.HTMLParseError:bad   end   tag 这个两个异常都是解析器引起的,解决方法是安装lxml或者html5lib

    更多内容...

    官方文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/

    中文文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc.zh

    PyPI:https://pypi.org/project/beautifulsoup4/

  • 相关阅读:
    cpanel 定时运行sh/php
    zencart 后台目录产品黄色icon_yellow_on.gif 解决方案
    字符串编码---hash函数的应用
    Tiling_easy version(填2 x N的格子的种类)
    n行m列的网格中含有的矩形数
    Openstack
    Docker
    Tornado模块
    LAMP应用部署
    数据库管理
  • 原文地址:https://www.cnblogs.com/aaron456-rgv/p/12123238.html
Copyright © 2011-2022 走看看