关于爬虫学习的一些小小记录(三)——BeautifulSoup

关于爬虫学习的一些小小记录(三)——BeautifulSoup

前面讲了一些访问页面和提取数据的基础方法,学会了挥锤子就该造刀剑了
但 Python 的哲学就是 “不要重复造轮子”,神兵利器都已经被大神们造好了,我们会用就可以了
这次我们就把白板装丢开,谈一个学习爬虫必不可少的工具Beautiful Soup

Beautiful Soup

Beautiful Soup库是 Python 的第三方库,可以解析 html 或 xml 文件,提供了许多可以高效提取数据的方法,让提取数据变得十分简单、灵活。而且 Beautiful Soup 可以自动把 html 和 xml 文件编码格式转化成 Unicode,输出时转化成 utf-8,不需要再手动转码
老规矩,这是一份中文版的 Beautiful Soup 的官方文档
食不惯中文版的童鞋可以品尝英文版

这里列出最常用的,也是我最喜欢的find_all()方法,该方法用于搜索当前 tag 的所有子孙结点,并以列表形式返回匹配到的所有内容

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

name,查找所有名字为 name 的 tag,自动忽略字符串对象。可接受任一数据类型,如字符串,正则表达式,列表,True
attrs,按照 CSS 类名搜索 tag,因为 class 是 Python 的关键字,使用 class_ 代替使用
recursive,当值为 False 时,find_all() 只搜索当前 tag 的直接子结点
text,搜索文档中的字符串内容,同样可以接受任一数据类型
kwargs,可选的,当字典的 key 不是内置的参数名时,作为当前 tag 的属性名进行搜索

另外find()的用法跟find_all()差不多,但返回的内容是匹配到的第一个 tag,并不是只有一个 tag 的列表

使用 Beautiful Soup 修改代码

在上一篇中,我们写了一个从豆瓣爬取 2019 版《倚天屠龙记》演职员数据信息的爬虫程序,这是最终扩展后的代码

# 爬虫--爬取豆瓣 2019版 《倚天屠龙记》 全体演职员

import re
from urllib import request

url = 'https://movie.douban.com/subject/25865815/celebrities'

response = request.urlopen(url)  # 访问 url
page = response.read().decode()  # 以 utf-8 的格式读取数据

names = re.findall('" class="name">(.*)</a></span>', page)  # 正则表达式匹配
roles = re.findall('span class="role" title="(.*)">', page)  # 匹配职位
imgs = re.findall('style="background-image: url\((.*)\)">', page)  # 匹配图片链接

i = 0
while i < len(names):
	role_list = roles[i].split(' ')  # 避免因文件名过长无法建立,只好从这里切短
	role = role_list[0] + ' (' + role_list[-1]  # 切碎了重新拼一下
	img_name = r'19版《倚天屠龙记》演职员/' + names[i] + ' ' + role + r'.jpg'
	img = request.urlretrieve(imgs[i], img_name)
	i += 1

现在,我们使用 Beautiful Soup 来精简一下这个代码
还是事先分析一波
网页源码1
演职员姓名和职位都在span标签中,CSS 类名分别为namerole,而图片链接在div标签中,CSS 类名为avatar,都可以直接使用find_all()方法匹配

使用 Beautiful Soup 精简后的代码如下

# 爬虫--爬取豆瓣 2019版 《倚天屠龙记》 全体演职员——美丽汤修改版

from bs4 import BeautifulSoup
from urllib import request

url = 'https://movie.douban.com/subject/25865815/celebrities'

response = request.urlopen(url)  # 访问 url
page = response.read().decode()  # 以 utf-8 的格式读取数据

soup = BeautifulSoup(page, 'html.parser')  # 使用 Python 内置的 html.parser 解析器

names = soup.find_all('span', 'name')  # tag 名和 CSS 类名匹配姓名
roles = soup.find_all('span', 'role')  # 匹配职位
imgs = soup.find_all('div', 'avatar')  # 匹配图片链接

i = 0
while i < len(names):
	role_list = roles[i].string.split(' ')  # 避免因文件名过长无法建立,只好从这里切短
	role = role_list[0] + ' (' + role_list[-1]  # 切碎了重新拼一下
	img_name = r'19版《倚天屠龙记》演职员1/' + names[i].string + ' ' + role + r'.jpg'
	img_url = imgs[i].get('style').split('(')[1].split(')')[0]  # 选取括号中的部分
	img = request.urlretrieve(img_url, img_name)
	i += 1

运行结果跟修改前的一样,这里就不给出了

黑猫白猫

想来机智的小伙伴们也发现了,Beautiful Soup 在匹配查找 tag 时十分方便,因为匹配方式多样,而且返回的就是 tag 类型数据。但如果匹配的是 tag 的部分字节时,需要通过匹配到的 tag,对属性进行调用来间接获取,不能像正则表达式一般直接返回匹配的内容

比如在上面的程序中,提取图片链接时,imgs 列表中存储的是 div 标签。我们需要使用 imgs[i].get(‘style’) 获取 tag 中的 style 属性值,然而这还不是一个可以访问的 url。我们要使用 split 把这个值进一步分割,取出括号中的 url。这才算成功提取,显然要比正则表达式麻烦许多。

这样看来,这次选择的例子并不合适来凸显美丽汤的高效简便。

当然,这也说明,我们应当实事求是。美丽汤虽有不足,正则表达式在某些情况也可能出现匹配不精准的情况,我们可以结合使用。黑猫白猫都可以捉到老鼠

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值