python3爬虫(二)-使用beautiful soup 读取网页

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/changzoe/article/details/79086053

HTML常用标签

Beautiful Soup简介

简单来说,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据。官方解释如下:

Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。

Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时,Beautiful Soup就不能自动识别编码方式了。然后,你仅仅需要说明一下原始编码方式就可以了。

Beautiful Soup已成为和lxml、html6lib一样出色的python解释器,为用户灵活地提供不同的解析策略或强劲的速度。


Beautiful Soup四大对象

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

Tag
NavigableString
BeautifulSoup
Comment

创建Beautiful Soup对象

from bs4 import BeautifulSoup
from urllib import request

html = request.urlopen("https://movie.douban.com/")  
bs=BeautifulSoup(html,"lxml")    #将html对象转化为BeautifulSoup对象 
  • Tag

Tag通俗点讲就是HTML中的一个个标签,下面我们来感受一下怎样用 Beautiful Soup 来方便地获取 Tags。
我们可以利用 soup加标签名轻松地获取这些标签的内容,是不是感觉比正则表达式方便多了?不过有一点是,它查找的是在所有内容中的第一个符合要求的标签

print(bs.title)
<title>
        豆瓣电影
</title>
print(bs.head)

只写一部分返回

<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<meta content="webkit" name="renderer"/>
<meta content="always" name="referrer"/>
<title>
        豆瓣电影
</title>
<meta content="cZdR4xxR7RxmM4zE" name="baidu-site-verification"/>
<meta content="no-cache" http-equiv="Pragma"/>
<meta content="Sun, 6 Mar 2005 01:00:00 GMT" http-equiv="Expires"/>
<meta content="format=xhtml; url=http://m.douban.com/movie/" http-equiv="mobile-agent"/>
<meta content="13753521351564752166375" property="qc:admins"/>
<meta content="电影、经典电影、热映、电视剧、美剧、影评、电影院、电影票、排行、推荐" name="keywords"/>
<meta content="豆瓣电影提供最新的电影介绍及评论包括上映影片的影讯查询及购票服务。你可以记录想看、在看和看过的电影电视剧,顺便打分、写影评。根据你的口味,豆瓣电影会推荐好电影给你。" name="description"/>
print(bs.a)
#<a class="nav-login" href="https://www.douban.com/accounts/login?source=movie" rel="nofollow">登录</a>
print(bs.p)
<p class="appintro-title">豆瓣</p>

对于Tag,有两个重要的属性:name和attr
name
soup 对象本身比较特殊,它的 name 即为 [document],对于其他内部标签,输出的值便为标签本身的名称。

print(bs.name)
print(bs.title.name)
#[document]
#title

attrs

print(bs.a.attrs)

{'class': ['nav-login'], 'href': 'https://www.douban.com/accounts/login?source=movie', 'rel': ['nofollow']}

在这里,我们把 a 标签的所有属性打印输出了出来,得到的类型是一个字典。

如果我们想要单独获取某个属性,可以这样,例如我们获取a标签的class叫什么,两个等价的方法如下:

print(bs.a['class'])
print(bs.a.get('class'))

['nav-login']
  • NavigableString

既然我们已经得到了标签的内容,那么问题来了,我们要想获取标签内部的文字怎么办呢?很简单,用 .string 即可,例如

print(bs.a.string)

登录
  • BeautifulSoup

    BeautifulSoup 对象表示的是一个文档的全部内容.大部分时候,可以把它当作 Tag 对象,是一个特殊的 Tag,我们可以分别获取它的类型,名称,以及属性

  • Comment

    Comment对象是一个特殊类型的NavigableString对象,其实输出的内容仍然不包括注释符号,但是如果不好好处理它,可能会对我们的文本处理造成意想不到的麻烦。

from bs4 import element

if type(soup.li.string) == element.Comment:
     print(soup.li.string)

上面的代码中,我们首先判断了它的类型,是否为 Comment 类型,然后再进行其他操作,如打印输出。


遍历文档数

  • 直接子节点(不包含孙节点)
    contents:
    tag的content属性可以将tag的子节点以列表的方式输出:
    这里写图片描述
    输出方式为列表,我们可以用列表索引来获取它的某一个元素:
print(bs.body.contents[1])
#<script type="text/javascript">var _body_start = new Date();</script>

children
它返回的不是一个 list,不过我们可以通过遍历获取所有子节点,它是一个 list 生成器对象:
这里写图片描述

利用列表解析
这里写图片描述

  • 搜索文档树
find_all(name, attrs, recursive, text, limit, **kwargs):

find_all() 方法搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件。

1) name参数:
name 参数可以查找所有名字为 name 的tag,字符串对象会被自动忽略掉。

传递字符:

最简单的过滤器是字符串,在搜索方法中传入一个字符串参数,Beautiful Soup会查找与字符串完整匹配的内容,下面的例子用于查找文档中所有的标签:
这里写图片描述

传递正则表达式

如果传入正则表达式作为参数,Beautiful Soup会通过正则表达式的 match() 来匹配内容.下面例子中找出所有以b开头的标签,这表示body和b标签都应该被找到

这里写图片描述

传递列表:
如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回,下面代码找到文档中所有title标签和b标签:

print(bs.find_all(['title','b']))

[<title>
        豆瓣电影
</title>]

传递True:

True 可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点:

for tag in bs.find_all(True):
    print(tag.name)

这里写图片描述

上述图片均只取一部分

2)attrs参数

我们可以通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的tag。

print(bs.find_all(attrs={"class":"title"}))

这里写图片描述

  • 3)recursive参数

    调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False。

  • 4)text参数

    通过 text 参数可以搜搜文档中的字符串内容,与 name 参数的可选值一样, text 参数接受字符串 , 正则表达式 , 列表, True

print(bs.find_all(text="机器之血"))
['机器之血']
  • 5)limit参数

    find_all() 方法返回全部的搜索结构,如果文档树很大那么搜索会很慢.如果我们不需要全部结果,可以使用 limit 参数限制返回结果的数量.效果与SQL中的limit关键字类似,当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果。

print(bs.find_all('a',limit=5))
[<a class="nav-login" href="https://www.douban.com/accounts/login?source=movie" rel="nofollow">登录</a>, <a class="nav-register" href="https://www.douban.com/accounts/register?source=movie" rel="nofollow">注册</a>, <a class="lnk-doubanapp" href="https://www.douban.com/doubanapp/app?channel=top-nav">下载豆瓣客户端</a>, <a href="https://www.douban.com/doubanapp/redirect?channel=top-nav&amp;direct_dl=1&amp;download=iOS">iPhone</a>, <a class="download-android" href="https://www.douban.com/doubanapp/redirect?channel=top-nav&amp;direct_dl=1&amp;download=Android">Android</a>]

结果只返回了5个,因为我们限制了返回数量:
- 6)kwargs参数

如果传入 class 参数,Beautiful Soup 会搜索每个 class 属性为 title 的 tag 。kwargs 接收字符串,正则表达式
这里写图片描述

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

这里写图片描述
平行遍历
这里写图片描述
上行遍历
这里写图片描述
下行遍历
这里写图片描述

由find_all()扩展的七个方法
这里写图片描述

#传递一个ID,定位到导航栏
rev_bar = bs.find(id="reviews")
#遍历导航栏的后继
for d in rev_bar.descendants:
    print(d)

#到导航栏的最后一个后继,使用.previous_siblings来遍历导航元素的邻居
for s in d.previous_siblings:
    print(s)

这里写图片描述


参考文档

很好的文章
官方文档
bs4的遍历

展开阅读全文

没有更多推荐了,返回首页