首页 文章资讯内容详情

Python爬虫小白入门(三)BeautifulSoup库

2026-06-01 4 花语

本文内容纲要:

-一、前言 -二、运行环境 -三、模块安装 -四、BeautifulSoup库的使用 -4.1BeautifulSoup对象的类型 -4.1.1Tag -4.1.2NavigableString -4.1.3BeautifulSoup -4.1.4Comment -4.2BeautifulSoup遍历方法 -4.2.1节点和标签名 -4.2.2搜索文档树 -五、继续上一篇实例 -六、后语

一、前言

上一篇演示了如何使用requests模块向网站发送http请求,获取到网页的HTML数据。这篇来演示如何使用BeautifulSoup模块来从HTML文本中提取我们想要的数据。

updateon2016-12-28:之前忘记给BeautifulSoup的官网了,今天补上,顺便再补点BeautifulSoup的用法。

updateon2017-08-16:很多网友留言说Unsplash网站改版了,很多内容是动态加载的。所以建议动态加载的内容使用PhantomJS而不是Request库进行请求,如果使用PhantomJS请看我的下一篇博客,如果是定位html文档使用的class等名字更改的话,建议大家根据更改后的内容进行定位,学爬虫重要的是爬取数据的逻辑,逻辑掌握了网站怎么变都不重要啦。

二、运行环境

我的运行环境如下:

系统版本

Windows10。 Python版本

Python3.5,推荐使用Anaconda这个科学计算版本,主要是因为它自带一个包管理工具,可以解决有些包安装错误的问题。去Anaconda官网,选择Python3.5版本,然后下载安装。 IDE

我使用的是PyCharm,是专门为Python开发的IDE。这是JetBrians的产品,点我下载。

三、模块安装

BeautifulSoup有多个版本,我们使用BeautifulSoup4。详细使用看BeautifuSoup4官方文档。

使用管理员权限打开cmd命令窗口,在窗口中输入下面的命令即可安装:

condainstallbeautifulsoup4

直接使用Python3.5没有使用Anaconda版本的童鞋使用下面命令安装:

pipinstallbeautifulsoup4

然后我们安装lxml,这是一个解析器,BeautifulSoup可以使用它来解析HTML,然后提取内容。

Anaconda使用下面命令安装lxml:

condainstalllxml

使用Python3.5的童鞋们直接使用pip安装会报错(所以才推荐使用Anaconda版本),安装教程看这里。

如果不安装lxml,则BeautifulSoup会使用Python内置的解析器对文档进行解析。之所以使用lxml,是因为它速度快。

文档解析器对照表如下:

解析器 使用方法 优势 劣势 Python标准库 BeautifulSoup(markup,"html.parser") 1.Python的内置标准库

2.执行速度适

3.中文档容错能力强 Python2.7.3or3.2.2)前的版本中文档容错能力差 lxmlHTML解析器 BeautifulSoup(markup,"lxml") 1.速度快

2.文档容错能力强 需要安装C语言库 lxmlXML解析器 BeautifulSoup(markup,["lxml-xml"])

BeautifulSoup(markup,"xml") 1.速度快

2.唯一支持XML的解析器 需要安装C语言库 html5lib BeautifulSoup(markup,"html5lib") 1.最好的容错性

2.以浏览器的方式解析文档

3.生成HTML5格式的文档 速度慢,不依赖外部扩展

四、BeautifulSoup库的使用

网上找到的几个官方文档:BeautifulSoup4.4.0中文官方文档,BeautifulSoup4.2.0中文官方文档。不同版本的用法差不多,几个常用的语法都一样。

首先来看BeautifulSoup的对象种类,在使用的过程中就会了解你获取到的东西接下来应该如何操作。

4.1BeautifulSoup对象的类型

BeautifulSoup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象。所有对象可以归纳为4种类型:Tag,NavigableString,BeautifulSoup,Comment。下面我们分别看看这四种类型都是什么东西。

4.1.1Tag

这个就跟HTML或者XML(还能解析XML?是的,能!)中的标签是一样一样的。我们使用find()方法返回的类型就是这个(插一句:使用find-all()返回的是多个该对象的集合,是可以用for循环遍历的。)。返回标签之后,还可以对提取标签中的信息。

提取标签的名字:

tag.name

提取标签的属性:

tag[attribute]

我们用一个例子来了解这个类型:

frombs4importBeautifulSoup html_doc=""" <html><head><title>TheDormousesstory</title></head> <body> <pclass="title"><b>TheDormousesstory</b></p> <pclass="story">Onceuponatimetherewerethreelittlesisters;andtheirnameswere <ahref="http://example.com/elsie"class="sister"id="link1">Elsie</a>, <ahref="http://example.com/lacie"class="sister"id="link2">Lacie</a>and <ahref="http://example.com/tillie"class="sister"id="link3">Tillie</a>; andtheylivedatthebottomofawell.</p> <pclass="story">...</p> """ soup=BeautifulSoup(html_doc,lxml)#声明BeautifulSoup对象 find=soup.find(p)#使用find方法查到第一个p标签 print("findsreturntypeis",type(find))#输出返回值类型 print("findscontentis",find)#输出find获取的值 print("findsTagNameis",find.name)#输出标签的名字 print("findsAttribute(class)is",find[class])#输出标签的class属性值

4.1.2NavigableString

NavigableString就是标签中的文本内容(不包含标签)。获取方式如下:

tag.string

还是以上面那个例子,加上下面这行,然后执行:

print(NavigableStringis:,find.string)

4.1.3BeautifulSoup

BeautifulSoup对象表示一个文档的全部内容。支持遍历文档树和搜索文档树。

4.1.4Comment

这个对象其实就是HTML和XML中的注释。

markup="<b><!--Hey,buddy.Wanttobuyausedparser?--></b>" soup=BeautifulSoup(markup) comment=soup.b.string type(comment) #<classbs4.element.Comment>

有些时候,我们并不想获取HTML中的注释内容,所以用这个类型来判断是否是注释。

iftype(SomeString)==bs4.element.Comment: print(该字符是注释) else: print(该字符不是注释)

4.2BeautifulSoup遍历方法

4.2.1节点和标签名

可以使用子节点、父节点、及标签名的方式遍历:

soup.head#查找head标签 soup.p#查找第一个p标签 #对标签的直接子节点进行循环 forchildintitle_tag.children: print(child) soup.parent#父节点 #所有父节点 forparentinlink.parents: ifparentisNone: print(parent) else: print(parent.name) #兄弟节点 sibling_soup.b.next_sibling#后面的兄弟节点 sibling_soup.c.previous_sibling#前面的兄弟节点 #所有兄弟节点 forsiblinginsoup.a.next_siblings: print(repr(sibling)) forsiblinginsoup.find(id="link3").previous_siblings: print(repr(sibling))

4.2.2搜索文档树

最常用的当然是find()和find_all()啦,当然还有其他的。比如find_parent()和find_parents()、find_next_sibling()和find_next_siblings()、find_all_next()和find_next()、find_all_previous()和find_previous()等等。

我们就看几个常用的,其余的如果用到就去看官方文档哦。

find_all()

搜索当前tag的所有tag子节点,并判断是否符合过滤器的条件。返回值类型是bs4.element.ResultSet。

完整的语法:

find_all(name,attrs,recursive,string,**kwargs)

这里有几个例子

soup.find_all("title")

[TheDormousesstory]

soup.find_all("p","title")

[TheDormousesstory]

soup.find_all("a")

[Elsie,

Lacie,

Tillie]

soup.find_all(id="link2")

[Lacie]

importre soup.find(string=re.compile("sisters"))

uOnceuponatimetherewerethreelittlesisters;andtheirnameswere\n

name参数:可以查找所有名字为name的tag。

attr参数:就是tag里的属性。

string参数:搜索文档中字符串的内容。

recursive参数:调用tag的find_all()方法时,BeautifulSoup会检索当前tag的所有子孙节点。如果只想搜索tag的直接子节点,可以使用参数recursive=False。

find()

与find_all()类似,只不过只返回找到的第一个值。返回值类型是bs4.element.Tag。

完整语法:

find(name,attrs,recursive,string,**kwargs)

看例子:

soup.find(title)

TheDormousesstory

soup.find("head").find("title")

TheDormousesstory

基本功已经练完,开始实战!

五、继续上一篇实例

继续上一篇的网站Unsplash,我们在首页选中图片,查看html代码。发现所有的图片都在a标签里,并且class都是cV68d,如下图。

通过仔细观察,发现图片的链接在style中的background-image中有个url。这个url就包含了图片的地址,url后面跟了一堆参数,可以看到其中有&w=XXX&h=XXX,这个是宽度和高度参数。我们把高度和宽度的参数去掉,就能获取到大图。下面,我们先获取到所有的含有图片的a标签,然后在循环获取a标签中的style内容。

其实在图片的右下方有一个下载按钮,按钮的标签中有一个下载链接,但是该链接并不能直接请求到图片,需要跳转几次,通过获取表头里的Location才能获取到真正的图片地址。后续我再以这个角度获取图片写一篇博文,咱们现根据能直接获取到的url稍做处理来获取图片。小伙伴儿们也可能会发现其他的方式来获取图片的url,都是可以的,尽情的尝试吧!

importrequests#导入requests模块 frombs4importBeautifulSoup#导入BeautifulSoup模块 headers={User-Agent:Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/54.0.2840.99Safari/537.36}#给请求指定一个请求头来模拟chrome浏览器 web_url=https://unsplash.comr=requests.get(web_url,headers=headers)#像目标url地址发送get请求,返回一个response对象 all_a=BeautifulSoup(r.text,lxml).find_all(a,class_=cV68d)#获取网页中的class为cV68d的所有a标签 forainall_a: print(a[style])#循环获取a标签中的style

这里的find_all(a,class_=cV68d)是找到所有class为cV68d的a标签,返回的是一个list,所以可以用for循环获取每个a标签。

还有,get请求使用了headers参数,这个是用来模拟浏览器的。如何知道‘User-Agent’是什么呢?

在你的Chrome浏览器中,按F12,然后刷新网页,看下图就可以找到啦。

OK,我们来执行以下上面的代码,结果如下:

接下来的任务是在一行的文本中取到图片的url。仔细看每一行的字符串,两个双引号之间的内容就是图片的url了,所以我们Python的切片功能来截取这中间的内容。

改写for循环中的内容:

forainall_a: img_str=a[style]#a标签中完整的style字符串 print(img_str[img_str.index(")+1:img_str.index(",img_str[img_str.index(")+1)])#使用Python的切片功能截取双引号之间的内容

获取到url后还要把宽度和高度的参数去掉。

forainall_a: img_str=a[style]#a标签中完整的style字符串 print(a标签的style内容是:,img_str) first_pos=img_str.index(")+1 second_pos=img_str.index(",first_pos) img_url=img_str[first_pos:second_pos]#使用Python的切片功能截取双引号之间的内容 width_pos=img_url.index(&w=) height_pos=img_url.index(&q=) width_height_str=img_url[width_pos:height_pos] print(高度和宽度数据字符串是:,width_height_str) img_url_final=img_url.replace(width_height_str,) print(截取后的图片的url是:,img_url_final)

有了这些图片的url,就可以通过继续发请求的方式获取图片啦。接下来我们先来封装一下发请求的代码。

先创建一个类: classBeautifulPicture(): def__init__(self):#类的初始化操作 self.headers={User-Agent:Mozilla/5.0(WindowsNT10.0;Win64;x64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/55.0.2883.87Safari/537.36}#给请求指定一个请求头来模拟chrome浏览器 self.web_url=https://unsplash.com#要访问的网页地址 self.folder_path=D:\BeautifulPicture#设置图片要存放的文件目录

然后封装request请求:

defrequest(self,url):#返回网页的response r=requests.get(url)#像目标url地址发送get请求,返回一个response对象 returnr

我们在文件目录下保存图片的话,要先创建文件目录。所以再添加一个创建目录的方法:

要先引入os库哦。

importos

然后是方法定义: defmkdir(self,path):##这个函数创建文件夹 path=path.strip() isExists=os.path.exists(path) ifnotisExists: print(创建名字叫做,path,的文件夹) os.makedirs(path) print(创建成功!) else: print(path,文件夹已经存在了,不再创建)

再然后是保存图片啦。

defsave_img(self,url,name):##保存图片 print(开始保存图片...) img=self.request(url) time.sleep(5) file_name=name+.jpg print(开始保存文件) f=open(file_name,ab) f.write(img.content) print(file_name,文件保存成功!) f.close()

工具方法都已经准备完毕,开始我们的逻辑部分:

defget_pic(self): print(开始网页get请求) r=self.request(self.web_url) print(开始获取所有a标签) all_a=BeautifulSoup(r.text,lxml).find_all(a,class_=cV68d)#获取网页中的class为cV68d的所有a标签 print(开始创建文件夹) self.mkdir(self.folder_path)#创建文件夹 print(开始切换文件夹) os.chdir(self.folder_path)#切换路径至上面创建的文件夹 i=1#后面用来给图片命名 forainall_a: img_str=a[style]#a标签中完整的style字符串 print(a标签的style内容是:,img_str) first_pos=img_str.index(")+1 second_pos=img_str.index(",first_pos) img_url=img_str[first_pos:second_pos]#使用Python的切片功能截取双引号之间的内容 width_pos=img_url.index(&w=) height_pos=img_url.index(&q=) width_height_str=img_url[width_pos:height_pos] print(高度和宽度数据字符串是:,width_height_str) img_url_final=img_url.replace(width_height_str,) print(截取后的图片的url是:,img_url_final) self.save_img(img_url_final,str(i)) i+=1

最后就是执行啦:

beauty=BeautifulPicture()#创建一个类的实例 beauty.get_pic()#执行类中的方法

最后来一个完整的代码,对中间的一些部分进行了封装和改动,并添加了每部分的注释,一看就明白了。有哪块有疑惑的可以留言~~

importrequests#导入requests模块 frombs4importBeautifulSoup#导入BeautifulSoup模块 importos#导入os模块 classBeautifulPicture(): def__init__(self):#类的初始化操作 self.headers={User-Agent:Mozilla/5.0(WindowsNT6.1;WOW64)AppleWebKit/537.1(KHTML,likeGecko)Chrome/22.0.1207.1Safari/537.1}#给请求指定一个请求头来模拟chrome浏览器 self.web_url=https://unsplash.com#要访问的网页地址 self.folder_path=D:\BeautifulPicture#设置图片要存放的文件目录 defget_pic(self): print(开始网页get请求) r=self.request(self.web_url) print(开始获取所有a标签) all_a=BeautifulSoup(r.text,lxml).find_all(a,class_=cV68d)#获取网页中的class为cV68d的所有a标签 print(开始创建文件夹) self.mkdir(self.folder_path)#创建文件夹 print(开始切换文件夹) os.chdir(self.folder_path)#切换路径至上面创建的文件夹 forainall_a:#循环每个标签,获取标签中图片的url并且进行网络请求,最后保存图片 img_str=a[style]#a标签中完整的style字符串 print(a标签的style内容是:,img_str) first_pos=img_str.index(")+1 second_pos=img_str.index(",first_pos) img_url=img_str[first_pos:second_pos]#使用Python的切片功能截取双引号之间的内容 #获取高度和宽度的字符在字符串中的位置 width_pos=img_url.index(&w=) height_pos=img_url.index(&q=) width_height_str=img_url[width_pos:height_pos]#使用切片功能截取高度和宽度参数,后面用来将该参数替换掉 print(高度和宽度数据字符串是:,width_height_str) img_url_final=img_url.replace(width_height_str,)#把高度和宽度的字符串替换成空字符 print(截取后的图片的url是:,img_url_final) #截取url中参数前面、网址后面的字符串为图片名 name_start_pos=img_url.index(photo) name_end_pos=img_url.index(?) img_name=img_url[name_start_pos:name_end_pos] self.save_img(img_url_final,img_name)#调用save_img方法来保存图片 defsave_img(self,url,name):##保存图片 print(开始请求图片地址,过程会有点长...) img=self.request(url) file_name=name+.jpg print(开始保存图片) f=open(file_name,ab) f.write(img.content) print(file_name,图片保存成功!) f.close() defrequest(self,url):#返回网页的response r=requests.get(url,headers=self.headers)#像目标url地址发送get请求,返回一个response对象。有没有headers参数都可以。 returnr defmkdir(self,path):##这个函数创建文件夹 path=path.strip() isExists=os.path.exists(path) ifnotisExists: print(创建名字叫做,path,的文件夹) os.makedirs(path) print(创建成功!) else: print(path,文件夹已经存在了,不再创建) beauty=BeautifulPicture()#创建类的实例 beauty.get_pic()#执行类中的方法

执行的过程中可能会有点慢,这是因为图片本身比较大!如果仅仅是为了测试爬虫,则可以不把图片的宽度和高度替换掉,图片就没那么大啦,运行过程会快很多。

六、后语

伙伴儿们是不是发现,我们只获取到了10张图片,并没有把网站所有照片都下载下来。

这是因为咱们爬取的网站是下拉刷新的,下拉一次,刷新10张照片。那么,该如何爬取这种下拉刷新的网页呢?请看下一篇喽。

本文内容总结:一、前言,二、运行环境,三、模块安装,四、BeautifulSoup库的使用,4.1BeautifulSoup对象的类型,4.1.1Tag,4.1.2NavigableString,4.1.3BeautifulSoup,4.1.4Comment,4.2BeautifulSoup遍历方法,4.2.1节点和标签名,4.2.2搜索文档树,五、继续上一篇实例,六、后语,

原文链接:https://www.cnblogs.com/Albert-Lee/p/6232745.html