BeautifulSoup
CSS 可以让 HTML 元素呈现出差异化,
使那些具有完全相同修饰的元素呈现出不同的样式。比如,有一些标签看起来是这样:
<span class="green"></span>
和
<span class="red"></span>
网络爬虫可以通过 class 属性的值,轻松地区分出两种不同的标签。例如,它们可以用
BeautifulSoup 抓取网页上所有的红色文字,而绿色文字一个都不抓。因为 CSS 通过属性准
确地呈现网站的样式,所以你大可放心,大多数新式网站上的 class 和 id 属性资源都非常
丰富。
下面让我们创建一个网络爬虫来抓取 http://www.baidu.com
这个网页。
<div id="u1"><a href="http://news.baidu.com" name="tj_trnews" class="mnav">新闻</a><a href="http://www.hao123.com" name="tj_trhao123" class="mnav">hao123</a><a href="http://map.baidu.com" name="tj_trmap" class="mnav">地图</a><a href="http://v.baidu.com" name="tj_trvideo" class="mnav">视频</a><a href="http://tieba.baidu.com" name="tj_trtieba" class="mnav">贴吧</a><a href="http://xueshu.baidu.com" name="tj_trxueshu" class="mnav">学术</a><a href="https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F&sms=5" name="tj_login" class="lb" onclick="return false;">登录</a><a href="http://www.baidu.com/gaoji/preferences.html" name="tj_settingicon" class="pf">设置</a><a href="http://www.baidu.com/more/" name="tj_briicon" class="bri" style="display: block;">更多产品</a><div class="bdnuarrow bdbriarrow" style="display: none;"></div></div>
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 22 07:20:19 2018
@author:
"""
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.baidu.com")
bsObj = BeautifulSoup(html, "html.parser")
nameList = bsObj.findAll("a", {"class":"mnav"})
for name in nameList:
print(name.get_text())
输出结果
新闻
hao123
地图
视频
贴吧
学术
之前,我们调用 bsObj.tagName
只能获取页面中的第一个指定的标签。现在,我们
调用 bsObj.findAll(tagName, tagAttributes)
可以获取页面中所有指定的标签,不再只是
第一个了。
获取namelist
列表之后,程序遍历列表中所有的name
,然后打印name.get_text()
,就可以把标
签中的内容分开显示了。
get_text()
会把你正在处理的 HTML 文档中所有的标签都清除,然后返回
一个只包含文字的字符串。假如你正在处理一个包含许多超链接、段落和标
签的大段源代码,那么 .get_text() 会把这些超链接、段落和标签都清除掉,
只剩下一串不带标签的文字。
用BeautifulSoup
对象查找你想要的信息,比直接在 HTML 文本里查找信
息要简单得多。通常在你准备打印、存储和操作数据时,应该最后才使
用 .get_text() 。一般情况下,你应该尽可能地保留 HTML 文档的标签结构。
BeautifulSoup的 find() 和 findAll()
BeautifulSoup 里的 find() 和 findAll() 可能是你最常用的两个函数。借助它们,你可以通
过标签的不同属性轻松地过滤 HTML 页面,查找需要的标签组或单个标签。
findAll(tag, attributes, recursive, text, limit, keywords)
find(tag, attributes, recursive, text, keywords)
注解
tag
标签参数,前面已经介绍过——你可以传一个标签的名称或多个标签名称组成的 Python
列表做标签参数。例如,下面的代码将返回一个包含 HTML 文档中所有标题标签的列表:
.findAll({"h1","h2","h3","h4","h5","h6"})
attributes
属性参数 ,是用一个 Python 字典封装一个标签的若干属性和对应的属性值,
例
如,下面这个函数会返回 HTML 文档里红色与绿色两种颜色的 span 标签:
.findAll("span", {"class":{"green", "red"}})
recursive
递归参数,是一个布尔变量,如果 recursive
设置为False
, findAll
就只查找文档的一级标签。 findAll
默认是支持递归查找的( recursive
默认值是 True
)
text
文本参数,有点不同,它是用标签的文本内容去匹配,而不是用标签的属性。假如我们
想查找前面网页中包含“the prince”内容的标签数量,我们可以把之前的 findAll 方法换
成下面的代码:
nameList = bsObj.findAll(text="学术")
print(len(nameList))
输出结果为“1”。
limit
范围限制参数,显然只用于 findAll 方法。 find 其实等价于 findAll 的 limit 等于
1 时的情形。
keyword
关键词参数,可以让你选择那些具有指定属性的标签。例如:
allText = bsObj.findAll(id="text")
print(allText[0].get_text())
注意
下面两行代码是完全一样的:
bsObj.findAll(id="text")
bsObj.findAll("", {"id":"text"})
用 keyword 偶尔会出现问题,尤其是在用 class 属性查找标签的时候,
因为 class 是 Python 中受保护的关键字。
bsObj.findAll(class=“green”)
正确的姿势
bsObj.findAll(class_=“green”)
bsObj.findAll("", {“class”:“green”})
导航树
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 22 07:46:57 2018
@author:
"""
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.baidu.com")
bsObj = BeautifulSoup(html, "html.parser")
print(bsObj.html.body.a)
输出
<a href="/" id="result_logo" onmousedown="return c({'fm':'tab','tab':'logo'})"><img alt="到百度首页" src="//www.baidu.com/img/baidu_jgylogo3.gif" title="到百度首页"/></a>
处理子标签
百度部分代码
<html><body>
<div id="u1">
<a href="http://news.baidu.com" name="tj_trnews" class="mnav">新闻</a>
<a href="http://www.hao123.com" name="tj_trhao123" class="mnav">hao123</a>
<a href="http://map.baidu.com" name="tj_trmap" class="mnav">地图</a>
<a href="http://v.baidu.com" name="tj_trvideo" class="mnav">视频</a>
<a href="http://tieba.baidu.com" name="tj_trtieba" class="mnav">贴吧</a>
<a href="http://xueshu.baidu.com" name="tj_trxueshu" class="mnav">学术</a>
<a href="https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F&sms=5" name="tj_login" class="lb" onclick="return false;">登录</a>
<a href="http://www.baidu.com/gaoji/preferences.html" name="tj_settingicon" class="pf">设置</a><a href="http://www.baidu.com/more/" name="tj_briicon" class="bri" style="display: block;">更多产品</a>
<div class="bdnuarrow bdbriarrow" style="display: none;"></div>
</div>
</body></html>
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 22 07:46:57 2018
@author:
"""
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.baidu.com")
bsObj = BeautifulSoup(html,"lxml")
for child in bsObj.find("div",{"id":"u1"}).children:
print(child)
输出结果
<a class="mnav" href="http://news.baidu.com" name="tj_trnews">新闻</a>
<a class="mnav" href="http://www.hao123.com" name="tj_trhao123">hao123</a>
<a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图</a>
<a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频</a>
<a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧</a>
<a class="mnav" href="http://xueshu.baidu.com" name="tj_trxueshu">学术</a>
<a class="lb" href="https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F&sms=5" name="tj_login" onclick="return false;">登录</a>
<a class="pf" href="http://www.baidu.com/gaoji/preferences.html" name="tj_settingicon">设置</a>
<a class="bri" href="http://www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品</a>
处理兄弟标签
BeautifulSoup 的 next_siblings()
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 22 07:46:57 2018
@author:
"""
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen("http://www.baidu.com")
bsObj = BeautifulSoup(html, "html.parser")
for sibling in bsObj.find("div",{"id":"u1"}).a.next_siblings:
print(sibling)
<a class="mnav" href="http://www.hao123.com" name="tj_trhao123">hao123</a>
<a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图</a>
<a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频</a>
<a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧</a>
<a class="mnav" href="http://xueshu.baidu.com" name="tj_trxueshu">学术</a>
<a class="lb" href="https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F&sms=5" name="tj_login" onclick="return false;">登录</a>
<a class="pf" href="http://www.baidu.com/gaoji/preferences.html" name="tj_settingicon">设置</a>
<a class="bri" href="http://www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品</a>
和next_siblings
一样,如果你很容易找到一组兄弟标签中的最后一个标签,那么previous_siblings
函数也会很有用。
处理父元素
同理如上
关键字parent