|
BeautifulSoup1.BeautifulSoup简介BeautifulSoup尝试化平淡为神奇。它通过定位HTML标签来格式化和组织复杂的网页信息,用简单易用的Python对象为我们展现XML结构信息。2.安装BeautifulSoup由于BeautifulSoup库不是Python标准库,因此需要单独安装。如果你安装过Python库,可以使用你最喜爱的安装器并略过本小节;我们将使用BeautifulSoup4(也叫BS4)。Linux系统上的基本安装方法是:sudoapt-getinstallpython-bs41对于macOS系统,首先用以下命令安装Python的包管理器pip:sudoeasy_installpip1然后运行以下命令安装库:pipinstallbeautifulsoup41windows下可以直接运行以下命令:pipinstallbeautifulsoup41这样就可以了,BeautifulSoup将被当作设备上的一个Python库。你可以在Python终端里导入它测试一下:如果没有错误,说明导入成功了。3.运行BeautifulSoupBeautifulSoup库最常用的对象恰好就是BeautifulSoup对象。让我们运行以下代码看看:fromurllib.requestimporturlopenfrombs4importBeautifulSouphtml=urlopen('http://www.pythonscraping.com/pages/page1.html')bs=BeautifulSoup(html.read(),'html.parser')print(bs.h1)123456输出结果是:
TotallyNormalGifts
1这里仅仅返回了页面上的第一个h1标签实例。通常情况下,一个页面也只有一个h1标签,但是在Web中这个惯例经常被打破,因此你应该意识到这里仅仅检索了该标签的第一个实例,而不一定是你寻找的那个。和前面网页抓取的例子一样,你导入urlopen函数,然后调用html.read()获取网页的HTML内容。除了文本字符串,BeautifulSoup还可以使用urlopen直接返回的文件对象,而不需要先调用.read()函数:bs=BeautifulSoup(html,'html.parser')1这样你就可以把HTML内容传递到BeautifulSoup对象,转换成下面的结构:html→……—head→AUsefulPage——title→AUsefulPage—body→AnInt…Loremip…——h1→AnInterestingTitle——div→LoremIpsumdolor…可以看出,我们从网页提取的标签被嵌在BeautifulSoup对象结构的第二层(html→body→h1)。但是,当我们从对象里提取h1标签的时候,可以直接调用它:bs.h11其实,下面的所有函数调用都可以产生相同的结果:bs.html.body.h1bs.body.h1bs.html.h1123当你创建一个BeautifulSoup对象时,需要传入两个参数:bs=BeautifulSoup(html.read(),'html.parser')1第一个参数是该对象所基于的HTML文本,第二个参数指定了你希望BeautifulSoup用来创建该对象的解释器。在大多数情况下,你选择任何一个解释器都差别不大(html.parser是Python3中的一个解释器,不需要单独安装)。4.可靠的网络连接以及异常的处理Web是十分复杂的。网页数据格式不友好、网站服务器死机、目标数据的标签找不到了,都是很麻烦的事情。网页抓取最痛苦的遭遇之一,就是爬虫运行的时候你该洗洗睡了,想着第二天一早数据就都会抓取好放在数据库里,结果第二天醒来,你看到的却是一个因某种数据格式异常导致运行错误的爬虫。那个时候,你可能会骂发明网站(以及那些奇葩的网络数据格式)的人,但你真正应该训斥的人是你自己,为什么不在一开始就估计可能发生的异常!让我们看看爬虫import语句后的第一行代码,看看如何处理可能出现的异常:html=urlopen('http://www.pythonscraping.com/pages/page1.html')1这行代码主要会发生两种异常:网页在服务器上不存在(或者获取页面的时候出现错误)服务器不存在发生第一种异常时,程序会返回HTTP错误。HTTP错误可能是“404PageNotFound”“500InternalServerError”等。对于所有类似情形,urlopen函数都会抛出HTTPError异常。我们可以用下面的方式处理这种异常:fromurllib.requestimporturlopenfromurllib.errorimportHTTPErrortry: html=urlopen('http://www.pythonscraping.com/pages/page1.html')exceptHTTPErrorase: print(e) #返回空值,中断程序,或者执行另一个方案else: #程序继续。注意:如果你已经在上面异常捕捉那一段代码里返回或中断(break), #那么就不需要使用else语句了,这段代码也不会执行1234567891011如果程序返回HTTP错误代码,程序就会显示错误内容,不再执行else语句后面的代码。如果服务器不存在(就是说链接http://www.pythonscraping.com打不开,或者是URL链接写错了),urlopen会抛出一个URLError异常。你可以增加以下检查代码:fromurllib.requestimporturlopenfromurllib.errorimportHTTPErrorfromurllib.errorimportURLErrortry: html=urlopen('http://www.pythonscraping.com/pages/page1.html')exceptHTTPErrorase: print(e)exceptURLErrorase: print('Theservercouldnotbefound')else: print('Itworked!')123456789101112'运行运行当然,即使从服务器成功获取网页,如果网页上的内容并非完全是我们所期望的那样,仍然可能会出现异常。每当你调用BeautifulSoup对象里的一个标签时,增加一个检查条件以保证标签确实存在是很聪明的做法。如果你想要调用的标签不存在,BeautifulSoup就会返回None对象。不过,如果再调用这个None对象下面的子标签,就会发生AttributeError错误。下面这行代码(nonExistentTag是虚拟的标签,BeautifulSoup对象里其实没有)print(bs.nonExistentTag)1会返回一个None对象。处理和检查这个对象是十分必要的。如果你不检查,直接调用这个None对象的子标签,就会有麻烦,如下所示:print(bs.nonExistentTag.someTag)1这时就会返回一个异常:AttributeError:'NoneType'objecthasnoattribute'someTag'1那么怎么才能避免这两种情形的异常呢?最简单的方式就是对这两种情形进行检查:try: badContent=bs.nonExistentTag.anotherTagexceptAttributeErrorase: print('Tagwasnotfound')else: ifbadContent==None: print('Tagwasnotfound') else: print(badContent)123456789初看这些检查与处理错误的代码会觉得有点累赘,但是我们可以重新简单组织一下代码,让它变得不那么难写(更重要的是,不那么难读)。例如,下面的代码是上面爬虫的另一种写法:fromurllib.requestimporturlopenfromurllib.errorimportHTTPErrorfrombs4importBeautifulSoupdefgetTitle(url): try: html=urlopen(url) exceptHTTPErrorase: returnNone try: bs=BeautifulSoup(html.read(),'html.parser') title=bs.body.h1 exceptAttributeErrorase: returnNone returntitle title=getTitle('http://www.pythonscraping.com/pages/page1.html')iftitle==None: print('Titlecouldnotbufound')else: print(title) 123456789101112131415161718192021在这个例子中,我们创建了一个getTitle函数,它可以返回网页的,如果获取网页的时候遇到问题就返回一个None对象。在getTitle函数里面,我们像前面那样检查了HTTPError,还检查了由于URL输入错误引起的URLError,然后把两行BeautifulSoup代码封装在一个try语句里面。这两行中的一行有问题,都可能抛出AttributeError(如果服务器不存在,html就是一个None对象,html.read()就会抛出AttributeError)。在写爬虫的时候,思考代码的总体格局,让代码既可以捕捉异常又容易阅读,这是很重要的。如果你还希望重用大量代码,那么拥有像getSiteHTML和getTitle这样的通用函数(具有周密的异常处理功能)会让快速、稳定地抓取网页变得简单易行。
|
|