美文网首页
基础学习——BeautifulSoup篇(1)

基础学习——BeautifulSoup篇(1)

作者: 老白和他的爬虫 | 来源:发表于2019-03-18 08:08 被阅读0次

    BeautifulSoup 是一个可以从HTML或XML文件中提取数据的Python库。它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。换句话说,它是我们解析网页的利器

    BeautifulSoup3 目前已经停止开发,今天学习的是BeautifulSoup4

    1.简单入手

    我们以豆瓣网为例,编辑下面这段代码

    from bs4 import BeautifulSoup
    import requests
    if __name__ == "__main__":
         req = requests.get("https://www.douban.com/") #获取豆瓣网址
         html = req.text #获得网页源代码
         soup = BeautifulSoup(html) 
         print(soup.prettify())
    

    首先通过一个requests.get()来获得目标网址的信息,再通过req.text获得网页源代码,之后就可以利用BeautifulSoup来对源码进行解析。这里进行操作后,你可能会有这样的疑问,print(html)print(soup.prettify())的输出结果不是一样吗?确实看输出结果是这样的,好像没什么区别,其实两者是不一样的,前者只是单纯的输出网页源码,后者是将网页源码解析后模块化输出,仔细看一下输出结果你会发现些许差别。没发现也没有关系,下面我们来对解析后的网页进行操作。

    接着上面的代码块操作

         print(soup.title) #输出<title>标签
         print(soup.title.name) #输出title的name
         print(soup.title.string) #输出title的内容
         print(soup.title.parent.name) #输出title父节点的name
         print(soup.p) #输出<p>标签
         print(soup.p['class']) #输出<p>标签的类
         print(soup.a) #输出<a>标签
         print(soup.find_all('a')) #找到所有的<a>标签
         print(soup.find(id="anony-time")) #找到所有的id为anony-time标签
         print(soup.find_all('p',class_="app-title")) #找到所有class为app-title的<a>标签
    

    自己操作实现一下,你就能对BeautifulSoup的功能有着更深入的了解。其实不限于此,BeautifulSoup能做的还有更多,比如它可以提取网页中的链接

         #提取网页所有<a>标签里的链接
         for link in soup.find_all('a'):
             print(link.get('href'))
    

    对这段代码稍加限定条件就可以提取到指定<a>标签的链接,比如soup.find_all('a',class_='lnk-book')就可以查找所有类别为lnk-book<a>标签

    我们也可以通过下面的操作来获得网页所有的文字内容

    print(soup.get_text())
    

    2.BeautifulSoup——解析器

    在前面的代码块中有一行代码是这样的soup = BeautifulSoup(html)这行代码其实不是很规范,一般会在后面补充一个解析器,变成这样soup = BeautifulSoup(html,'lxml')。BeautifulSoup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,它一共有这么几种

    解析器 使用方法 优势 劣势
    Python标准库 BeautifulSoup(markup, "html.parser") Python的内置标准库
    执行速度适
    文档容错能力强
    Python 2.7.3 or 3.2.2)前 的版本中文档容错能力差
    lxml HTML 解析器 BeautifulSoup(markup, "lxml") 速度快
    唯一支持XML的解析器
    需要安装C语言库
    lxml XML 解析器 BeautifulSoup(markup, ["lxml", "xml"])
    BeautifulSoup(markup, "xml")
    速度快
    唯一支持XML的解析器
    需要安装C语言库
    html5lib BeautifulSoup(markup, "html5lib") 最好的容错性
    以浏览器的方式解析文档
    生成HTML5格式的文档
    速度慢
    不依赖外部扩展

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

    3.对象

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

    3.1Tag

    在前面的操作中,实际上我们已经见识了解析后的tag,解析后的网页都是由一个个的tag组成的。

         soup = BeautifulSoup(html,'lxml')
         print(soup.title) #输出了<title>这个tag
    

    每一个tag都有自己的name,我们可以查看

         print(soup.title.name) #输出title的name
    

    每一个tag都有自己的属性,比如<li> <a target="_blank" class="lnk-book" href="[https://book.douban.com](https://book.douban.com/)">豆瓣读书</a></li>,我们可以查看

         soup = BeautifulSoup('<li> <a target="_blank" class="lnk-book" href=" 
         [https://book.douban.com](https://book.douban.com/)">豆瓣读书</a></li>','lxml') 
         print(soup.a['target']) #查看target属性
         print(soup.a['class']) #查看class属性
         print(soup.a['href']) #查看href属性
    

    这里也就是我们上面获取<a>标签里面链接的原理,也可以直接查看它的所有属性

         print(soup.a.attrs)
    

    另外,tag里面的属性也是可以操作的,可以删除和修改,和字典操作是一样的

         soup.a['target'] = 'white' #修改
         del soup.a['class'] #删除
         print(soup.a['target'])
         print(bool(soup.a['class'])) #这一步会报错,因为已经被删掉了
    

    熟悉html的童鞋还会知道另外一个问题,就是有些html会有多值属性,比如<a class="lnk-book ink-book">豆瓣读书</a>

         soup = BeautifulSoup('<a class="lnk-book ink-book">豆瓣读书</a>','lxml')    
         print(soup.a['class'])
    #['lnk-book', 'ink-book']
    

    会发现,BeautifulSoup会自动的区分开多值属性,并以list的形式返回,但是当你将tag转换为string字符串时,它就会自动将他们的多值属性合并到一起。

    3.2NavigableString

    NavigableString是一个类,用来包装tag中的字符串,一个 NavigableString 字符串与Python中的Unicode字符串相同。tag中包含的字符串不能编辑,但是可以被替换成其它的字符串。

    soup = BeautifulSoup('<a class="lnk-book ink-book">豆瓣读书</a>','lxml')    
    soup.a.string.replace_with('walt white')
    print(soup.a)
    #<a class="lnk-book ink-book">walt white</a>
    

    3.3BeautifulSoup

    BeautifulSoup 对象表示的是一个文档的全部内容。大部分时候,可以把它当作 Tag 对象。上一段代码中的soup就是一个BeautifulSoup对象。

    3.4Comment

    comment其实顾名思义就是注释的意思,它是NavigableString一个特殊子类,用来表示html中的注释

    soup = BeautifulSoup('<b><!--Hey, how you\'re doing ?--></b>','lxml')
    comment = soup.b.string
    print(comment)
    

    注意这段代码,输出结果是Hey, how you're doing ?,而不是html的代码中的``,已经自动过滤了注释标签了

    4.遍历文档树

    这里用一段官网给出的文档来做例子

    from bs4 import BeautifulSoup
    if __name__ == "__main__":
         html_doc = """
            <html><head><title>The Dormouse's story</title></head>
            <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>
            """
         soup = BeautifulSoup(html_doc,'lxml')
    

    4.1子节点

    我们可以通过这样的方法来获取节点中的子节点

         print(soup.body.b)
    

    这样通过点取的方法只能获取第一个元素,如果需要获取全部的标签,则需要通过另外一种方法

         print(soup.find_all('a'))
    

    它可以通过列表的形式输出所有的标签

    4.2.contents

    利用.contents可以来将子节点以列表的形式输出

         soup = BeautifulSoup(html_doc,'lxml')
         head_tag = soup.head
         title_tag = head_tag.contents[0]
         print(title_tag)
         print(title_tag.contents)
    

    通过结果可以看到.contents输出了了当前节点的子节点,并用列表的形式输出,直到到最后一个字符串节点,无法再往下遍历

    4.3.children

    利用.children操作也可以遍历子节点

         soup = BeautifulSoup(html_doc,'lxml')
         title_tag = soup.head.contents[0]
         for child in title_tag.children:
             print(child)
    

    4.4.descendants

    利用.descendants操作也可以遍历子孙节点

         for child in title_tag.descendants:
             print(child)
    

    4.5.string

    如果tag有且仅有一个子节点,利用.string可以得到子节点的内容,但是tag如果有多个子节点,那么会输出none

         print(title_tag.string)
         print(soup.string)
    #The Dormouse's story
    #None
    

    4.6.strings 和 stripped_strings

    如果tag中包含多个字符串 ,可以使用 .strings来循环获取

         for string in soup.strings:
             print(repr(string))
    #"The Dormouse's story"
    #'\n'
    #"The Dormouse's story"
    #'\n'
    #'Once upon a time there were three little sisters; and their names were\n        '
    #'Elsie'
    #',\n        '
    #'Lacie'
    #' and\n        '
    #'Tillie'
    #';\n        and they lived at the bottom of a well.'
    #'\n'
    #'...'
    #'\n'
    

    输出的字符串中可能包含了很多空格或空行,使用 .stripped_strings可以去除多余空白内容:

         for string in soup..stripped_strings:
             print(repr(string))
    #"The Dormouse's story"
    #"The Dormouse's story"
    #'Once upon a time there were three little sisters; and their names were'
    #'Elsie'
    #','
    #'Lacie'
    #'and'
    #'Tillie'
    #';\n        and they lived at the bottom of a well.'
    #'...'
    

    今天的学习就到这里了,BeautifulSoup篇学习还没有结束,后面还会继续

    欢迎关注公众号:老白和他的爬虫

    相关文章

      网友评论

          本文标题:基础学习——BeautifulSoup篇(1)

          本文链接:https://www.haomeiwen.com/subject/kqlnpqtx.html