网络是十分复杂的。网页数据格式不友好,网站服务器宕机,目标数据的标签找不到,都
是很麻烦的事情。网络数据采集最痛苦的遭遇之一,就是爬虫运行的时候你洗洗睡了,梦
想着明天一早数据就都会采集好放在数据库里,结果第二天醒来,你看到的却是一个因某
种数据格式异常导致运行错误的爬虫,在前一天当你不再盯着屏幕去睡觉之后,没过一会
儿爬虫就不再运行了。那个时候,你可能想骂发明互联网(以及那些奇葩的网络数据格
式)的人,但是你真正应该斥责的人是你自己,为什么一开始不估计可能会出现的异常!
- html = urlopen("http://www.pythonscraping.com/pages/page1.html")
这行代码主要可能会发生两种异常:
网页在服务器上不存在(或者获取页面的时候出现错误)
服务器不存在
第一种异常发生时,程序会返回 HTTP 错误。HTTP 错误可能是 "404 Page Not Found""500
Internal Server Error"等。所有类似情形,urlopen 函数都会抛出"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 会返回一个 None 对象。这个对象与其他编程语言中的 null 类似。我们
可以增加一个判断语句检测返回的 html 是不是 None:
- if html is None:
- print("URL is not found")
- else:
- # 程序继续
当然,即使网页已经从服务器成功获取,如果网页上的内容并非完全是我们期望的那样,
仍然可能会出现异常。每当你调用 BeautifulSoup 对象里的一个标签时,增加一个检查条件
保证标签确实存在是很聪明的做法。如果你想要调用的标签不存在,BeautifulSoup 就会返
初见网络爬虫 | 9
回 None 对象。不过,如果再调用这个 None 对象下面的子标签,就会发生 AttributeError
错误。
下面这行代码(nonExistentTag 是虚拟的标签,BeautifulSoup 对象里实际没有)
print(bsObj.nonExistentTag)
会返回一个 None 对象。处理和检查这个对象是十分必要的。如果你不检查,直接调用这个
None 对象的子标签,麻烦就来了。如下所示。
print(bsObj.nonExistentTag.someTag)
这时就会返回一个异常:
AttributeError: 'NoneType' object has no attribute 'someTag'
那么我们怎么才能避免这两种情形的异常呢?最简单的方式就是对两种情形进行检查:
- try:
- badContent = bsObj.nonExistingTag.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:
- bsObj = BeautifulSoup(html.read())
- title = bsObj.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 be found")
- else:
- print(title)
在这个例子中,我们创建了一个 getTitle 函数,可以返回网页的标题,如果获取网页
的时候遇到问题就返回一个 None 对象。在 getTitle 函数里面,我们像前面那样检查了
HTTPError,然后把两行 BeautifulSoup 代码封装在一个 try 语句里面。这两行中的任何一
行有问题,AttributeError 都可能被抛出(如果服务器不存在,html 就是一个 None 对象,
html.read() 就会抛出 AttributeError)。其实,我们可以在 try 语句里面放任意多行代码,
或者放一个在任意位置都可以抛出 AttributeError 的函数。
来源: http://www.bubuko.com/infodetail-1986626.html