Python爬虫库-Beautiful Soup的使用
Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库,简单来说,它能将HTML的标签文件解析成树形结构,然后方便地获取到指定标签的对应属性。
如在上一篇文章通过爬虫爬取漫画图片,获取信息纯粹用正则表达式进行处理,这种方式即复杂,代码的可阅读性也低。通过Beautiful Soup库,我们可以将指定的class或id值作为参数,来直接获取到对应标签的相关数据,这样的处理方式简洁明了。
当前最新的 Beautiful Soup 版本为4.4.0,Beautiful Soup 3 当前已停止维护。
Beautiful Soup 4 可用于 Python2.7 和 Python3.0,本文示例使用的Python版本为2.7。
博主使用的是Mac系统,直接通过命令安装库:
sudo easy_install beautifulsoup4
安装完成后,尝试包含库运行:
from bs4 import BeautifulSoup
若没有报错,则说明库已正常安装完成。
开始
本文会通过这个网页http://reeoo.com来进行示例讲解,如下图所示
BeautifulSoup 对象初始化
将一段文档传入 BeautifulSoup 的构造方法,就能得到一个文档对象。如下代码所示,文档通过请求url获取:
#coding:utf-8
from bs4 import BeautifulSoup
import urllib2
url = 'http://reeoo.com'
request = urllib2.Request(url)
response = urllib2.urlopen(request, timeout=20)
content = response.read()
soup = BeautifulSoup(content, 'html.parser')
request 请求没有做异常处理,这里暂时先忽略。BeautifulSoup 构造方法的第二个参数为文档解析器,若不传入该参数,BeautifulSoup会自行选择最合适的解析器来解析文档,不过会有警告提示。
也可以通过文件句柄来初始化,可先将HTML的源码保存到本地同级目录 reo.html,然后将文件名作为参数:
soup = BeautifulSoup(open('reo.html'))
可以打印 soup,输出内容和HTML文本无二致,此时它为一个复杂的树形结构,每个节点都是Python对象。
Ps. 接下来示例代码中所用到的 soup 都为该soup。
Tag
Tag对象与HTML原生文档中的标签相同,可以直接通过对应名字获取
tag = soup.title
print tag
打印结果:
<title>Reeoo - web design inspiration and website gallery</title>
Name
通过Tag对象的name属性,可以获取到标签的名称
print tag.name
# title
Attributes
一个tag可能包含很多属性,如id、class等,操作tag属性的方式与字典相同。
例如网页中包含缩略图区域的标签 article
...
<article class="box">
<div id="main">
<ul id="list">
<li id="sponsor"><div class="sponsor_tips"></div>
<script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?zoneid=1696&serve=CVYD42T&placement=reeoocom" id="_carbonads_js"></script>
</li>
...
获取它 class 属性的值
tag = soup.article
c = tag['class']
print c
# [u'box']
也可以直接通过 .attrs 获取所有的属性
tag = soup.article
attrs = tag.attrs
print attrs
# {u'class': [u'box']}
ps. 因为class属于多值属性,所以它的值为数组。
tag中的字符串
通过 string 方法获取标签中包含的字符串
tag = soup.title
s = tag.string
print s
# Reeoo - web design inspiration and website gallery
文档树的遍历
一个Tag可能包含多个字符串或其它的Tag,这些都是这个Tag的子节点。Beautiful Soup提供了许多操作和遍历子节点的属性。
子节点
通过Tag的 name 可以获取到对应标签,多次调用这个方法,可以获取到子节点中对应的标签。
如下图:
我们希望获取到 article 标签中的 li
tag = soup.article.div.ul.li
print tag
打印结果:
<li id="sponsor"><div class="sponsor_tips"></div>
<script async="" id="_carbonads_js" src="//cdn.carbonads.com/carbon.js?zoneid=1696&serve=CVYD42T&placement=reeoocom" type="text/javascript"></script>
</li>
也可以把中间的一些节点省略,结果也一致
tag = soup.article.li
通过 . 属性只能获取到第一个tag,若想获取到所有的 li 标签,可以通过 find_all() 方法
ls = soup.article.div.ul.find_all('li')
获取到的是包含所有li标签的列表。
tag的 .contents 属性可以将tag的子节点以列表的方式输出:
tag = soup.article.div.ul
contents = tag.contents
打印 contents 可以看到列表中不仅包含了 li 标签内容,还包括了换行符 '\n'
过tag的 .children 生成器,可以对tag的子节点进行循环
tag = soup.article.div.ul
children = tag.children
print children
for child in children:
print child
可以看到 children 的类型为 <listiterator object at 0x109cb1850>
.contents 和 .children 属性仅包含tag的直接子节点,若要遍历子节点的子节点,可以通过 .descendants 属性,方法与前两者类似,这里不列出来了。
父节点
通过 .parent 属性来获取某个元素的父节点,article 的 父节点为 body。
tag = soup.article
print tag.parent.name
# body
或者通过 .parents 属性遍历所有的父辈节点。
tag = soup.article
for p in tag.parents:
print p.name
兄弟节点
.next_sibling 和 .previous_sibling 属性用来插叙兄弟节点,使用方式与其他的节点类似。
文档树的搜索
对树形结构的文档进行特定的搜索是爬虫抓取过程中最常用的操作。
find_all()
find_all(name , attrs , recursive , string , * kwargs)*
name 参数
查找所有名字为 name 的tag
soup.find_all('title')
# [<title>Reeoo - web design inspiration and website gallery</title>]
soup.find_all('footer')
# [<footer id="footer">\n<div class="box">\n<p> ... </div>\n</footer>]
keyword 参数
如果指定参数的名字不是内置的参数名(name , attrs , recursive , string),则将该参数当成tag的属性进行搜索,不指定tag的话则默认为对所有tag进行搜索。
如,搜索所有 id 值为 footer 的标签
soup.find_all(id='footer')
# [<footer id="footer">\n<div class="box">\n<p> ... </div>\n</footer>]
加上标签的参数
soup.find_all('footer', id='footer')
# [<footer id="footer">\n<div class="box">\n<p> ... </div>\n</footer>]
# 没有id值为'footer'的div标签,所以结果返回为空
soup.find_all('div', id='footer')
# []
获取所有缩略图的 div 标签,缩略图用 class 为 thumb 标记
soup.find_all('div', class_='thumb')
这里需要注意一点,因为 class 为Python的保留关键字,所以作为参数时加上了下划线,为“class_”。
指定名字的属性参数值可以包括:字符串、正则表达式、列表、True/False。
True/False
是否存在指定的属性。
搜索所有带有 target 属性的标签
soup.find_all(target=True)
搜索所有不带 target 属性的标签(仔细观察会发现,搜索结果还是会有带 target 的标签,那是不带 target 标签的子标签,这里需要注意一下。)
soup.find_all(target=False)
可以指定多个参数作为过滤条件,例如页面缩略图部分的标签如下所示:
...
<li>
<div class="thumb">
<a href="http://reeoo.com/aim-creative-studios">![AIM Creative Studios](//upload-images.jianshu.io/upload_images/1346917-f6281ffe1a8f0b18.gif?imageMogr2/auto-orient/strip)</a>
</div>
<div class="title">
<a href="http://reeoo.com/aim-creative-studios">AIM Creative Studios</a>
</div>
</li>
...
搜索 src 属性中包含 reeoo 字符串,并且 class 为 lazy 的标签:
soup.find_all(src=re.compile("reeoo.com"), class_='lazy')
搜索结果即为所有的缩略图 img 标签。
有些属性不能作为参数使用,如 data-* 属性。在上面的例子中,data-original 不能作为参数使用,运行起来会报错,SyntaxError: keyword can't be an expression。
attrs 参数
定义一个字典参数来搜索对应属性的tag,一定程度上能解决上面提到的不能将某些属性作为参数的问题。
例如,搜索包含 data-original 属性的标签
print soup.find_all(attrs={'data-original': True})
搜索 data-original 属性中包含 reeoo.com 字符串的标签
soup.find_all(attrs={'data-original': re.compile("reeoo.com")})
搜索 data-original 属性为指定值的标签
soup.find_all(attrs={'data-original': 'http://media.reeoo.com/Bersi Serlini Franciacorta.png!page'})
string 参数
和 name 参数类似,针对文档中的字符串内容。
搜索包含 Reeoo 字符串的标签:
soup.find_all(string=re.compile("Reeoo"))
打印搜索结果可看到包含3个元素,分别是对应标签里的内容,具体见下图所示
limit 参数
find_all() 返回的是整个文档的搜索结果,如果文档内容较多则搜索过程耗时过长,加上 limit 限制,当结果到达 limit 值时停止搜索并返回结果。
搜索 class 为 thumb 的 div 标签,只搜索3个
soup.find_all('div', class_='thumb', limit=3)
打印结果为一个包含3个元素的列表,实际满足结果的标签在文档里不止3个。
recursive 参数
find_all() 会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False。
find()
find(name , attrs , recursive , string , * kwargs)*
find() 方法和 find_all() 方法的参数使用基本一致,只是 find() 的搜索方法只会返回第一个满足要求的结果,等价于 find_all() 方法并将limit设置为1。
soup.find_all('div', class_='thumb', limit=1)
soup.find('div', class_='thumb')
搜索结果一致,唯一的区别是 find_all() 返回的是一个数组,find() 返回的是一个元素。
当没有搜索到满足条件的标签时,find() 返回 None, 而 find_all() 返回一个空的列表。
CSS选择器
Tag 或 BeautifulSoup 对象通过 select() 方法中传入字符串参数, 即可使用CSS选择器的语法找到tag。
语义和CSS一致,搜索 article 标签下的 ul 标签中的 li 标签
print soup.select('article ul li')
通过类名查找,两行代码的结果一致,搜索 class 为 thumb 的标签
soup.select('.thumb')
soup.select('[class~=thumb]')
通过id查找,搜索 id 为 sponsor 的标签
soup.select('#sponsor')
通过是否存在某个属性来查找,搜索具有 id 属性的 li 标签
soup.select('li[id]')
通过属性的值来查找查找,搜索 id 为 sponsor 的 li 标签
soup.select('li[id="sponsor"]')
其他
其他的搜索方法还有:
find_parents() 和 find_parent()
find_next_siblings() 和 find_next_sibling()
find_previous_siblings() 和 find_previous_sibling()
...
参数的作用和 find_all()、find() 差别不大,这里就不再列举使用方式了。这两个方法基本已经能满足绝大部分的查询需求。
还有一些方法涉及文档树的修改。对于爬虫来说大部分工作只是检索页面的信息,很少需要对页面源码做改动,所以这部分的内容也不再列举。
具体详细信息可直接参考Beautiful Soup库的官方说明文档
【完】。 :)
Python爬虫库-Beautiful Soup的使用的更多相关文章
- Python爬虫之Beautiful Soup解析库的使用(五)
Python爬虫之Beautiful Soup解析库的使用 Beautiful Soup-介绍 Python第三方库,用于从HTML或XML中提取数据官方:http://www.crummv.com/ ...
- python 爬虫利器 Beautiful Soup
python 爬虫利器 Beautiful Soup Beautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文 ...
- [Python爬虫] 使用 Beautiful Soup 4 快速爬取所需的网页信息
[Python爬虫] 使用 Beautiful Soup 4 快速爬取所需的网页信息 2018-07-21 23:53:02 larger5 阅读数 4123更多 分类专栏: 网络爬虫 版权声明: ...
- python爬虫之Beautiful Soup基础知识+实例
python爬虫之Beautiful Soup基础知识 Beautiful Soup是一个可以从HTML或XML文件中提取数据的python库.它能通过你喜欢的转换器实现惯用的文档导航,查找,修改文档 ...
- python爬虫之Beautiful Soup的基本使用
1.简介 简单来说,Beautiful Soup是python的一个库,最主要的功能是从网页抓取数据.官方解释如下: Beautiful Soup提供一些简单的.python式的函数用来处理导航.搜索 ...
- python标准库Beautiful Soup与MongoDb爬喜马拉雅电台的总结
Beautiful Soup标准库是一个可以从HTML/XML文件中提取数据的Python库,它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式,Beautiful Soup将会节省数小 ...
- python 爬虫5 Beautiful Soup的用法
1.创建 Beautiful Soup 对象 from bs4 import BeautifulSoup html = """ <html><head& ...
- Python爬虫之Beautiful Soup库的基本使用
- 小白学 Python 爬虫(21):解析库 Beautiful Soup(上)
小白学 Python 爬虫(21):解析库 Beautiful Soup(上) 人生苦短,我用 Python 前文传送门: 小白学 Python 爬虫(1):开篇 小白学 Python 爬虫(2):前 ...
随机推荐
- 洛谷 P1731 [NOI1999]生日蛋糕
P1731 [NOI1999]生日蛋糕 题目背景 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层 生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1<=i<=M ...
- 【TFS 2017 CI/CD系列 - 03】-- Release篇
为Project创建Release必须要先创建Build,若还没有Build definition请看上一篇文章:[TFS 2017 CI/CD系列 - 02]-- Build篇 一.创建Releas ...
- java下XML与JSON互相转换的Utils类
原文:http://heipark.iteye.com/blog/1394844 需要json-lib-2.1-jdk15.jar和xom-1.2.5.jar,maven pom.xml如下: < ...
- Oracle 行转列小结
近期在工作中.对行转列进行了应用,在此做一个简单的小结. 转换步骤例如以下: 1.创建表结构 CREATE TABLE RowToCol ( ID NUMBER(10) not null, U ...
- [教程]Delphi 中三种回调函数形式解析
Delphi 支持三种形式的回调函数 全局函数这种方式几乎是所有的语言都支持的,类的静态函数也可以归为此类,它保存的只是一个函数的代码起始地址指针( Pointer ).在 Delphi 中声明一般为 ...
- 深入源代码解析Android中的Handler,Message,MessageQueue,Looper
本文主要是对Handler和消息循环的实现原理进行源代码分析.假设不熟悉Handler能够參见博文< Android中Handler的使用>,里面对Android为何以引入Handler机 ...
- Android自带的分享功能案例
MainActivity的代码 package com.hpsvse.weiboshare; import java.io.File; import android.net.Uri; import a ...
- android 浮动窗体学习笔记及个人理解(仿360手机助手)
很感谢原文作者 http://blog.csdn.net/guolin_blog/article/details/8689140 经自己理解 程序执行界面例如以下图: 1.程序入口界面 2.小浮动窗体 ...
- CXF拦截器(Interceptor)LoggingInInterceptor
Interceptor是CXF架构中一个重要的功能.你可以在不对核心模块进行修改的情况下,动态添加很多功能(你可以想象Struts2拦截器的优点).这对于CXF这个以处理消息为中心的服务框架来说是非常 ...
- C++不能在栈上申请动态内存,而只能依靠指针
以下三种情况皆错,都编译不过: int main(int argc, char* argv[]) { int a; int b[a]; } int main(int argc, char* argv[ ...