• Python网络爬虫与信息提取(二)—— BeautifulSoup


    BeautifulSoup官方介绍:

    Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.

    官方网站:https://www.crummy.com/software/BeautifulSoup/

    BeautifulSoup安装

    在"C:WindowsSystem32"中找到"cmd.exe",使用管理员身份运行,在命令行中输入:“pip install beautifulsoup4”运行。

    C:Windowssystem32>pip install beautifulsoup4
    Requirement already satisfied (use --upgrade to upgrade): beautifulsoup4 in c:usersleiappdatalocalprogramspythonp
    ython35libsite-packageseautifulsoup4-4.5.0-py3.5.egg
    You are using pip version 8.1.1, however version 9.0.1 is available.
    You should consider upgrading via the 'python -m pip install --upgrade pip' command.

    提示pip版本过低,使用 python -m pip install --upgrade pip 进行升级。

    Beautiful Soup库的安装测试:

    from bs4 import BeautifulSoup
    soup = BeautifulSoup('<p>data</p>','html.parser')

    演示HTML页面地址:http://www.cnblogs.com/yan-lei

    >>> import requests
    >>> from bs4 import BeautifulSoup
    >>> r = requests.get("http://www.cnblogs.com/yan-lei/")
    >>> demo = r.text
    >>> soup = BeautifulSoup(demo,"html.parser")
    >>> soup

    Beautiful Soup库的使用

    以HTML为例,任何HTML文件都是有一组"<>"组织起来的,其实就是标签,标签之间形成了上下游关系,形成了标签树。BeautifulSoup库是解析、遍历、维护“标签树”的功能库

    <p>..</p>:标签Tag

    • 标签Name一般成对出现
    • 属性Attributes 0个或多个

    Beautiful Soup库的引用

    Beautiful Soup库,也叫beautfulsoup4 或bs4。约定引用方式如下,即主要是用BeautifulSoup类。

    from bs4 import BeautifulSoup
    import bs4

    Beautiful Soup类

    将标签树转换为BeautifulSoup类,此时我们将HTML、标签树、BeautifulSoup类等价

    from bs4 import BeautifulSoup
    soup1 = BeautifulSoup("<html>data</html>","html.parser")
    soup2 = BeautifulSoup(open("D://demo.html",'rb'),"html.parser")

    使用 soup2 = BeautifulSoup(open("D://demo.html"),"html.parser") 报错:

    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "C:UsersleiAppDataLocalProgramsPythonPython35libsite-packageseautifulsoup4-4.5.0-py3.5.eggs4\__init_
    _.py", line 191, in __init__
    UnicodeDecodeError: 'gbk' codec can't decode byte 0xbf in position 2: illegal multibyte sequence

    BeautifulSoup对应一个HTML/XML文档的全部内容。

    Beautiful Soup库解析器

    解析器使用方法条件
    bs4的HTML解析器 BeautifulSoup(mk,'html.parser') 安装bs4库
    lxml的HTML解析器 BeautifulSoup(mk,'lxml') pip install lxml
    lxml的XML解析器 BeautifulSoup(mk,'xml') pip install lxml
    html5lib的解析器 BeautifulSoup(mk,'html5lib') pip install html5lib

    Beautiful Soup类的基本元素

    基本元素说明
    Tag 标签,最基本的信息组织单元,分别用<>和</>标明开头和结尾
    Name 标签的名字,<p>...</p>的名字是'p',格式:<tag>.name
    Attributes 标签的属性,字典形式的组织,格式:<tag>.attrs
    NavigleString 标签内非属性字符串,<>...</>中字符串,格式<tag>.string
    Comment 标签内字符串的注释部分,一种特殊的Comment类型
    • Tag标签:任何存在于HTML语法中的标签都可以用soup.<tag>访问获得;当HTML文档中存在多个相同<tag>对应内容时,soup.<tag>返回第一个。
    • Tag的名字(name):每个<tag>都有自己的名字,通过<tag>.name获取,字符串类型。
    • Tag的attrs(属性):一个<tag>可以有0个或多个属性,字典类型。
    • Tag的NavigableString:NavigableString可以跨越多个层次
    • Tag的Comment:Comment是一种特殊类型。
    >>> import requests
    >>> from bs4 import BeautifulSoup
    >>> r = requests.get('http://www.cnblogs.com/yan-lei/')
    >>> html = r.text
    >>> soup = BeautifulSoup(html,'html.parser')
    >>> soup.title
    <title>Python学习者 - 博客园</title>
    >>> soup.a
    <a name="top"></a>
    >>> soup.a.name
    'a'
    >>> soup.a.parent.name
    'body'
    >>> soup.a.attrs
    {'name': 'top'}
    >>> type(soup.a)
    <class 'bs4.element.Tag'>
    >>> type(soup.a.attrs)
    <class 'dict'>
    >>> soup.h1.string
    'Python学习者'
    >>> type(soup.h1.string)
    <class 'bs4.element.NavigableString'>

    基于bs4库的HTML内容遍历方法

    HTML中 <...>构成了所属关系,形成了标签的树形结构,有三种遍历方式。

    使用以下的HTML进行测试:E:BeautifulSoupTest.html

    <html>
        <head>
            <meta charset="utf-8">
            <title>BeautifulSoup</title>
        </head>
        <body>
            <div id="header">
                <h1  style="font-size:16px;text-align:center">这里是标题</h1>
            </div>
            <div id="nav">
                <h1>左导航</h1>
            </div>
            <div id="main">
                <p>第一段</p>
                <p>第二段</p>
                <img src="test.jpg"/>
                <p><a href="http://www.cnblogs.com/yan-lei/">博客园</a></p>
    
            </div>
            <div id="footer">
                <h1>底边</h1>
            </div>
    
        </body>
    </html>

    标签树的下行遍历

    属性说明
    .contents 子节点的列表,将<tag>所有儿子节点存入列表
    .contents 子节点的列表,将<tag>所有儿子节点存入列表
    .children 子节点的迭代类型,与.contents类似,用于循环遍历儿子节点
    .descendants 子孙节点的迭代类型,包含所有子孙节点,用于循环遍历

    BeautifulSoup类是标签树的根节点

    >>> from bs4 import BeautifulSoup
    >>> soup = BeautifulSoup(open('E:\BeautifulSoupTest.html','rb'),'html.parser')
    >>> soup.head.contents #返回的是列表
    ['
    ', <meta charset="utf-8">
    <title>BeautifulSoup</title>
    </meta>]
    >>> len(soup.body.contents)
    9
    >>> for child in soup.body.children:   # 遍历儿子节点
    ...     print(child)
    ...
    
    
    <div id="header">
    <h1 style="font-size:16px;text-align:center">这里是标题</h1>
    </div>
    
    
    <div id="nav">
    <h1>左导航</h1>
    </div>
    
    
    <div id="main">
    <p>第一段</p>
    <p>第二段</p>
    <img src="test.jpg">
    <p><a href="http://www.cnblogs.com/yan-lei/">博客园</a></p>
    </img></div>
    
    
    <div id="footer">
    <h1>底边</h1>
    </div>
    
    
    >>> for child in soup.body.descendants:  # 遍历子孙节点
    ...     print(child)
    ...
    
    
    <div id="header">
    <h1 style="font-size:16px;text-align:center">这里是标题</h1>
    </div>
    
    
    <h1 style="font-size:16px;text-align:center">这里是标题</h1>
    这里是标题
    
    
    
    
    <div id="nav">
    <h1>左导航</h1>
    </div>
    
    
    <h1>左导航</h1>
    左导航
    
    
    
    
    <div id="main">
    <p>第一段</p>
    <p>第二段</p>
    <img src="test.jpg">
    <p><a href="http://www.cnblogs.com/yan-lei/">博客园</a></p>
    </img></div>
    
    
    <p>第一段</p>
    第一段
    
    
    <p>第二段</p>
    第二段
    
    
    <img src="test.jpg">
    <p><a href="http://www.cnblogs.com/yan-lei/">博客园</a></p>
    </img>
    
    
    <p><a href="http://www.cnblogs.com/yan-lei/">博客园</a></p>
    <a href="http://www.cnblogs.com/yan-lei/">博客园</a>
    博客园
    
    
    
    
    <div id="footer">
    <h1>底边</h1>
    </div>
    
    
    <h1>底边</h1>
    底边
    for child in soup.body.children:   # 遍历儿子节点
        print(child)
    
    for child in soup.body.descendants:  # 遍历子孙节点
        print(child)

    标签树的上行遍历

    属性说明
    .parent 节点的父亲标签
    .parents 节点先辈标签的迭代类型,用于循环遍历先辈节点
    >>> for parent in soup.a.parents:
    ...     if parent is None:
    ...             print(parent)
    ...     else:
    ...             print(parent.name)
    ...
    p
    img
    div
    body
    html
    [document]
    # 判断所有先辈节点,包括soup本身,所以要区别判断
    for parent in soup.a.parents:
        if parent is None:
                print(parent)
        else:
                print(parent.name)

    标签树的平行遍历

    属性说明
    .next_sibling 返回按照HTML文本顺序的下一个平行节点标签
    .previous_sibling 返回按照HTML文本顺序的上一个平行节点标签
    .next_siblings 迭代类型,返回按照HTML文本顺序的后续所有平行节点标签
    .previous_siblings 迭代类型,返回按照HTML文本顺序的前续所有平行节点标签

    *所有的平行遍历发生在同一个父节点下的各节点间。

    # div标签下一个平行节点标签
    soup.div.next_sibling
    
    # div标签上一个平行节点标签
    soup.div.previous_sibling
    
    
    # 遍历后续节点
    for sibling in soup.div.next_sibling:
        print(sibling) 
    
    # 遍历前续节点
    for sibling in soup.div.previous_sibling:
        print(sibling) 

    基于bs4库的HTML格式输出

    bs4库的prettify()方法

    .prettify()为HTML文本<>及其内容增加' '

    .prettify()可用于标签,方法:<tag>.prettify()

    print(soup.prettify())

    bs4库将任何HTML输入都变成utf-8编码,Python 3.x默认支持编码是utf-8,解析无障碍。

    信息标记的三种形式

    信息的标记:

    • 标记后的信息可形成信息组织结构,增加了信息维度
    • 标记后的信息可用于通信、存储或展示
    • 标记的结构与信息一样具有重要价值
    • 标记后的信息更利于程序的理解和运用

    HTML的信息标记:

    HTML是WWW(World Wide Web)的信息组织方式。

    HTML通过预定义的<>...</>标签形式组织不同类型的信息。

    XML eXtensible Markup Language

    XML格式是基于HTML格式发展以来的一种通用的信息格式。

    • XML基本格式:<name> ... </name>
    • 空元素缩写形式:<name />
    • 注释书写形式:<!-- -->

    JSON JavaScript Object Notation

    有类型的键值对 key:value

    使用 "" 表达是字符串类型,没有字符串则是数字类型。

    YAML YAML Ain't Markup Language

    无类型键值对 key:value

    通过缩进表达所属关系

    • - 表达并列关系
    • | 表达整块数据
    • # 表示注释
    key : value
    key : #Comment
    -value1
    -value2
    key :
        subkey : subvalue

    三种信息标记形式的比较:

    XML 最早的通用信息标记语言,可扩展性好,但繁琐。Internet上的信息交互与传递。

    JSON 信息有类型,适合程序处理(js),较XML简洁。移动应用云端和节点的信息通信,无注释。

    YAML 信息无类型,文本信息比例最高,可读性好。各类系统的配置文件,有注释易读。

    信息提取的一般方法

    方法一:完整解析信息的标记形式,再提取关键信息。

    XML JSON YAML

    需要标记解析器 例如bs4库的标签树遍历

    优点:信息解析准确

    缺点:提取过程繁琐,速度慢。

    方法二:无视标记形式,直接搜索关键信息。

    搜索

    对信息的文本查找函数即可。

    优点:提取过程简介,速度较快。

    缺点:提取结果准确性与信息内容相关。

    方法三:融合方法

    融合方法:结合形式解析与搜索方法,提取关键信息。

    基于bs4库的HTML内容查找方法

    <>.find_all(name,attrs,recursive,string,**kwargs)

    返回一个列表类型,存储查找结果。

    • name:对标签名称的检索字符串。
    • attrs:对标签属性值的检索字符串,可标注属性检索。
    • recursive:是否对子孙全部检索,默认True。
    • string:<>...</>中字符串区域的检索字符串。

    <tag>(..) 等价于 <tag>.find_all(..)

    soup(..) 等价于 soup.find_all(..)

    >>> soup.div()
    [<h1 style="font-size:16px;text-align:center">这里是标题</h1>]
    >>> for tag in soup.find_all(True):  # 返回所有的标签
    ...     print(tag.name)
    ...
    html
    head
    meta
    title
    body
    div
    h1
    div
    h1
    div
    p
    p
    img
    p
    a
    div
    h1

    扩展方法

    方法说明
    <>.find() 搜索且只返回一个结果,自负串类型,同.find_all()参数
    <>.find_parents() 在先辈节点中搜索,返回列表类型,同find_all()参数
    <>.find_parent() 在先辈节点中返回一个结果,字符串类型,同.find()参数
    <>.find_next_siblings() 在后续平行节点中搜索,返回列表类型,同.find_all()参数
    <>.find_next_sibling() 在后续平行节点中返回一个结果,字符串类型,同.find()参数
    <>.find_previous_siblings() 在前序节点中搜索,返回列表类型,同.find_all()参数
    <>.find_previous_sibling() 在前序节点中返回一个结果,字符串类型,同.find()参数

    回到顶部

  • 相关阅读:
    TCP Three-Way handshake
    java 连接mysql 和sql server2008代码
    关于dispatch_sync死锁问题
    MacBook Pro使用初体验之Mac快捷键汇总(持续更新中)
    Java对象的内存布局
    Android之adb
    ADT开发中的一些优化设置:代码背景色、代码字体大小、代码自动补全
    实用的eclipse adt 快捷键
    python操作Excel读--使用xlrd
    解决ImportError: cannot import name HTTPConnection的方法
  • 原文地址:https://www.cnblogs.com/yan-lei/p/7615902.html
Copyright © 2020-2023  润新知