bs4库之所以能快速的定位我们想要的元素,是因为他用自己的方式将html文件解析了一遍 ,不同的解析器有不同的效果。下文将一一进行介绍。
网络爬虫的最终目的就是过滤选取网络信息,最重要的部分可以说是解析器。解析器的优劣决定了爬虫的速度和效率。bs4库除了支持我们上文用过的html.parser解析器外,还支持很多第三方的解析器,下面我们来对他们进行对比分析。
bs4库官方推荐我们使用的是lxml解析器,原因是它具有更高的效率,所以我们也将采用lxml解析器。
依旧采用pip安装工具来安装:
- pip install lxml
-
接下来,我们使用lxml解析器来解释网页
我们依旧以上一篇的 爱丽丝文档 为例子
- 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>
- """
-
代码如下:
- import bs4
-
- #首先我们先将html文件已lxml的方式做成一锅汤
- soup = bs4.BeautifulSoup(html_doc ,'lxml')
- #我们把结果输出一下,是一个很清晰的树形结构。
- print(soup.prettify())
-
输出如下
- <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 class="sister" href="http://example.com/elsie" id="link1">
- Elsie
- </a>
- ,
- <a class="sister" href="http://example.com/lacie" id="link2">
- Lacie
- </a>
- and
- <a class="sister" href="http://example.com/tillie" id="link3">
- Tillie
- </a>
- ;
- and they lived at the bottom of a well.
- </p>
- <p class="story">
- ...
- </p>
- </body>
- </html>
-
bs4 库首先将传入的字符串或文件句柄转换为 Unicode的类型,这样,我们在抓取中文信息的时候,就不会有很麻烦的编码问题了。当然,有一些生僻的编码 如:‘big5’,就需要我们手动设置编码:
soup = BeautifulSoup(markup, from_encoding=“编码方式”)
bs4 库将复杂的html文档转化为一个复杂的树形结构,每个节点都是Python对象 ,所有对象可以分为以下四个类型:Tag , NavigableString , BeautifulSoup , Comment
我们来逐一解释:
搜索文档树的最简单的方法就是搜索你想获取tag的的name
- soup.head
- # <head><title>The Dormouse's story</title></head>
-
- soup.title
- # <title>The Dormouse's story</title>
-
如果你还想更深入的获得更小的tag:例如我们想找到body下的被b标签包裹的部分
- soup.body.b
- # <b>The Dormouse's story</b>
-
但是这个方法只能找到按顺序第一个出现的tag,那么如何获取所有的标签呢?
这个时候需要find_all()方法,他返回一个列表类型
- tag=soup.find_all('a')
- # [<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>]
-
- #假设我们要找到a标签中的第二个元素:
- need = tag[1]
-
tag的.contents属性可以将tag的子节点以列表的方式输出:
- head_tag = soup.head
- head_tag
- # <head><title>The Dormouse's story</title></head>
-
- head_tag.contents
- [<title>The Dormouse's story</title>]
- title_tag = head_tag.contents[0]
- print(title_tag)
- # <title>The Dormouse's story</title>
- title_tag.contents
- # [u'The Dormouse's story']
-
另外通过tag的.children生成器,可以对tag的子节点进行循环:
- for child in title_tag.children:
- print(child)
- # The Dormouse's story
-
这种方式只能遍历出子节点。如何遍历出子孙节点呢?
子孙节点:比如 head.contents 的子节点是,这里title本身也有子节点:‘The Dormouse‘s story’ 。这里的‘The Dormouse‘s story’也叫作head的子孙节点
- for child in head_tag.descendants:
- print(child)
- # <title>The Dormouse's story</title>
- # The Dormouse's story
-
如何找到tag下的所有的文本内容呢?
我们可以用迭代的方式将其全部找出:
- for string in soup.strings:
- print(repr(string))
-
- # u"The Dormouse's story"
- # u'\n\n'
- # u"The Dormouse's story"
- # u'\n\n'
- # u'Once upon a time there were three little sisters; and their names were\n'
- # u'Elsie'
- # u',\n'
- # u'Lacie'
- # u' and\n'
- # u'Tillie'
- # u';\nand they lived at the bottom of a well.'
- # u'\n\n'
- # u'...'
- # u'\n'
-
好了,关于bs4库的基本使用,我们就先介绍到这。剩下来的部分:父节点、兄弟节点、回退和前进,都与上面从子节点找元素的过程差不多,想要具体了解可以去看一下官方文档.