【Python 爬虫基础】BeautifulSoup

本文介绍了BeautifulSoup库的基本使用,包括安装、运行示例、HTML标签解析以及如何处理网络连接异常和标签查找失败。作者强调了在编写爬虫时异常处理的重要性,提倡编写可重用、易于阅读且健壮的代码。
摘要由CSDN通过智能技术生成

BeautifulSoup

1. BeautifulSoup 简介

BeautifulSoup 尝试化平淡为神奇。它通过定位 HTML 标签来格式化和组织复杂的网页信息,用简单易用的 Python 对象为我们展现 XML 结构信息。

2. 安装 BeautifulSoup

由于 BeautifulSoup 库不是 Python 标准库,因此需要单独安装。如果你安装过 Python 库,可以使用你最喜爱的安装器并略过本小节;

我们将使用 BeautifulSoup 4(也叫 BS4 )。
Linux 系统上的基本安装方法是:

sudo apt-get install python-bs4

对于 macOS 系统,首先用以下命令安装 Python 的包管理器 pip:

sudo easy_install pip

然后运行以下命令安装库:

pip install beautifulsoup4

windows 下可以直接运行以下命令:

pip install beautifulsoup4

这样就可以了,BeautifulSoup 将被当作设备上的一个 Python 库。你可以在 Python 终端里导入它测试一下:
在这里插入图片描述
如果没有错误,说明导入成功了。

3. 运行 BeautifulSoup

BeautifulSoup 库最常用的对象恰好就是 BeautifulSoup 对象。让我们运行以下代码看看:

from urllib.request import urlopen
from bs4 import BeautifulSoup

html = urlopen('http://www.pythonscraping.com/pages/page1.html')
bs = BeautifulSoup(html.read(), 'html.parser')
print(bs.h1)

输出结果是:

<h1>Totally Normal Gifts</h1>

这里仅仅返回了页面上的第一个 h1 标签实例。通常情况下,一个页面也只有一个 h1 标签,但是在 Web 中这个惯例经常被打破,因此你应该意识到这里仅仅检索了该标签的第一个实例,而不一定是你寻找的那个。

和前面网页抓取的例子一样,你导入 urlopen 函数,然后调用 html.read() 获取网页的 HTML 内容。除了文本字符串,BeautifulSoup 还可以使用 urlopen 直接返回的文件对象,而不需要先调用 .read() 函数:

bs = BeautifulSoup(html, 'html.parser')

这样你就可以把 HTML 内容传递到 BeautifulSoup 对象,转换成下面的结构:

  • html → < html>< head>…< /head>< body>…< /body>< html>
    head→ < head>< title>A Useful Page< /title>< /head>
    —— title→ < title>A Useful Page< /title>
    body→ < body>< h1>An Int…< /h1>< div>Lorem ip…< /div>< /body>
    —— h1→ < h1>An Interesting Title< /h1>
    —— div→ < div>Lorem Ipsum dolor…< /div>
    可以看出,我们从网页提取的 < h1> 标签被嵌在 BeautifulSoup 对象结构的第二层(html → body → h1)。但是,当我们从对象里提取 h1 标签的时候,可以直接调用它:
bs.h1

其实,下面的所有函数调用都可以产生相同的结果:

bs.html.body.h1
bs.body.h1
bs.html.h1

当你创建一个 BeautifulSoup 对象时,需要传入两个参数:

bs = BeautifulSoup(html.read(), 'html.parser')

第一个参数是该对象所基于的 HTML 文本,第二个参数指定了你希望 BeautifulSoup 用来创建该对象的解释器。在大多数情况下,你选择任何一个解释器都差别不大(html.parser 是 Python 3 中的一个解释器,不需要单独安装)。

4.可靠的网络连接以及异常的处理

Web 是十分复杂的。网页数据格式不友好、网站服务器死机、目标数据的标签找不到了,都是很麻烦的事情。网页抓取最痛苦的遭遇之一,就是爬虫运行的时候你该洗洗睡了,想着第二天一早数据就都会抓取好放在数据库里,结果第二天醒来,你看到的却是一个因某种数据格式异常导致运行错误的爬虫。那个时候,你可能会骂发明网站(以及那些奇葩的网络数据格式)的人,但你真正应该训斥的人是你自己,为什么不在一开始就估计可能发生的异常!

让我们看看爬虫 import 语句后的第一行代码,看看如何处理可能出现的异常:

html = urlopen('http://www.pythonscraping.com/pages/page1.html')

这行代码主要会发生两种异常:

  • 网页在服务器上不存在(或者获取页面的时候出现错误)
  • 服务器不存在

发生第一种异常时,程序会返回 HTTP 错误。HTTP 错误可能是“404 Page Not Found” “500 Internal Server Error” 等。对于所有类似情形,urlopen 函数都会抛出 HTTPError 异常。我们可以用下面的方式处理这种异常:

from urllib.request import urlopen
from urllib.error import HTTPError

try:
	html = urlopen('http://www.pythonscraping.com/pages/page1.html')
except HTTPError as e:
	print(e)
	#返回空值,中断程序,或者执行另一个方案
else:
	#程序继续。 注意:如果你已经在上面异常捕捉那一段代码里返回或中断(break),
	#那么就不需要使用 else 语句了,这段代码也不会执行

如果程序返回 HTTP 错误代码,程序就会显示错误内容,不再执行 else 语句后面的代码。

如果服务器不存在(就是说链接 http://www.pythonscraping.com 打不开,或者是 URL 链接写错了),urlopen 会抛出一个 URLError 异常。你可以增加以下检查代码:

from urllib.request import urlopen
from urllib.error import HTTPError
from urllib.error import URLError

try:
	html = urlopen('http://www.pythonscraping.com/pages/page1.html')
except HTTPError as e:
	print(e)
except URLError as e:
	print('The server could not be found')
else:
	print('It worked!')

当然,即使从服务器成功获取网页,如果网页上的内容并非完全是我们所期望的那样,仍然可能会出现异常。每当你调用 BeautifulSoup 对象里的一个标签时,增加一个检查条件以保证标签确实存在是很聪明的做法。如果你想要调用的标签不存在,BeautifulSoup 就会返回 None 对象。不过,如果再调用这个 None 对象下面的子标签,就会发生 AttributeError 错误。

下面这行代码(nonExistentTag 是虚拟的标签,BeautifulSoup 对象里其实没有)

print(bs.nonExistentTag)

会返回一个 None 对象。处理和检查这个对象是十分必要的。如果你不检查,直接调用这个 None 对象的子标签,就会有麻烦,如下所示:

print(bs.nonExistentTag.someTag)

这时就会返回一个异常:

AttributeError: 'NoneType' object has no attribute 'someTag'

那么怎么才能避免这两种情形的异常呢?最简单的方式就是对这两种情形进行检查:

try:
	badContent = bs.nonExistentTag.anotherTag
except AttributeError as e:
	print('Tag was not found')
else:
	if badContent == None:
		print('Tag was not found')
	else:
		print(badContent)

初看这些检查与处理错误的代码会觉得有点累赘,但是我们可以重新简单组织一下代码,让它变得不那么难写(更重要的是,不那么难读)。例如,下面的代码是上面爬虫的另一种写法:

from urllib.request import urlopen
from urllib.error import HTTPError
from bs4 import BeautifulSoup

def getTitle(url):
	try:
		html = urlopen(url)
	except HTTPError as e:
		return None
	try:
		bs = BeautifulSoup(html.read(), 'html.parser')
		title = bs.body.h1
	except AttributeError as e:
		return None
	return title
	
title = getTitle('http://www.pythonscraping.com/pages/page1.html')
if title == None:
	print('Title could not bu found')
else:
	print(title)	

在这个例子中,我们创建了一个 getTitle 函数,它可以返回网页的标题,如果获取网页的时候遇到问题就返回一个 None 对象。在 getTitle 函数里面,我们像前面那样检查了 HTTPError,还检查了由于 URL 输入错误引起的 URLError,然后把两行 BeautifulSoup 代码封装在一个 try 语句里面。这两行中的一行有问题,都可能抛出 AttributeError(如果服务器不存在,html 就是一个 None 对象,html.read() 就会抛出AttributeError)。

在写爬虫的时候,思考代码的总体格局,让代码既可以捕捉异常又容易阅读,这是很重要的。如果你还希望重用大量代码,那么拥有像 getSiteHTML 和 getTitle 这样的通用函数(具有周密的异常处理功能)会让快速、稳定地抓取网页变得简单易行。

  • 28
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

QuantumStack

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值