基础学习——BeautifulSoup篇(1)

2019-03-18  本文已影响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篇学习还没有结束,后面还会继续

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

上一篇 下一篇

猜你喜欢

热点阅读