Beautiful Soup基础入门
- Requests 库
- 遍历文档树
- 搜索文档树
- 标签基本元素
- Beautiful Soup 库解析器
一、Beautiful Soup简介
就是一个可以从HTML或XML文件中提取数据的Python库。实例:在最好大学网爬取2021年软科类世界大学排名的数据。
二、基本步骤
用chrome浏览器去访问该网站,然后审查元素,定位相关信息对应的代码。整个实验的关键就在于如何遍历tbody标签的孩子标签,获取tr标签里的td标签的数据。
确定好之后,接下来使用requests.get()来获取整个页面的内容。用import requests来导入Requests库。
1、准备工作
import requests
r = requests.get("https://labfile.oss.aliyuncs.com/courses/2184/2019%E8%BD%AF%E7%A7%91%E4%B8%96%E7%95%8C%E5%A4%A7%E5%AD%A6%E5%AD%A6%E6%9C%AF%E6%8E%92%E5%90%8D.html")
print(r.status_code)
print(r.encoding)
r.encoding = r.apparent_encoding
print(r.encoding)
2、获取相应信息
r.text #获取整个页面内容
r.headers #获取页面头信息
html = r.text
print(html)
header = r.headers
print(header)
'''
{'Server': 'AliyunOSS', 'Date': 'Thu, 29 Apr 2021 12:38:13 GMT', 'Content-Type': 'text/html', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding', 'x-oss-request-id': '608AA8B555A1A637340A18C1', 'Last-Modified': 'Fri, 24 Apr 2020 08:55:54 GMT', 'x-oss-object-type': 'Normal', 'x-oss-hash-crcecma': '15463410703954662493', 'x-oss-storage-class': 'Standard', 'Cache-Control': 'no-cache', 'Content-MD5': 'UT34YnbEGFbQ5LT+UwuhyA==', 'x-oss-server-time': '15', 'Content-Encoding': 'gzip'}
'''
3、解析HTML页面
Beautiful Soup库有专门的解析器,解析器的作用简单来说,就是用来解析和提取HTML或XML页面的数据。它有四种解析器:
第一种Python自带,后三种需自行安装
下面使用python标准库的解析器,使用 from bs4 import BeautifulSoup 导入 BeautifulSoup 库。使用 BeautifulSoup(markup, "html.parser") 去解析页面。
from bs4 import BeautifulSoup
soup = BeautifulSoup(html, "html.parser")
print(soup)
4、遍历和搜索文档树
每个标签都有一个名字,每个标签可以有0个或者多个属性,标签之间的字符串是非属性字符串或者注释,如下图所示:
我们的实验任务是要获取页面上的三类数据,分别是学校排名、学校名字和学校总分。所以,我们需要遍历标签树,搜索到这三类数据并保存到列表中。从上面的内容我们已经知道,所需要的数据是在 tbody 的子标签里,所以我们需要使用 find() 去遍历 tbody 标签的孩子标签。
data = soup.find("tbody").children
print(data)
上面的代码中,find() 是搜索文档树中的一种方法,它能够返回第一个匹配的元素。它的完整参数形式为:find( name , attrs , recursive , string , **kwargs )。参数 name 是用标签名去检索字符串,参数 attrs 是用标签属性值去检索字符串,参数 recursive 是否对子孙全部检索,默认为 True,参数 string 是检索标签中的非属性字符串。
.children 是标签下行遍历的一种属性。标签一共有三种遍历形式,分别是下行遍历、上行遍历和平行遍历。
下行遍历的三个属性:
- .children 是循环遍历儿子节点
- .descendants 是循环遍历所有子孙节点
- .contents 是将该标签中所有儿子节点存入列表
上行遍历有以下两个属性:
- .parent 是访问该节点的父节点标签
- .parents 是循环遍历所有先辈节点
平行遍历有以下四个属性:
- .next_sibling 是返回下一个平行节点的标签
- .previous_sibling 是返回上一个平行节点的标签
- .next_siblings 是返回后面所有平行节点的标签
- .previous_siblings 是返回前面所有平行节点的标签
现在我们已经获取了 tbody 标签中所有孩子标签了,由于返回的是一个迭代器,你可以使用 list(data) 以列表的形式输出看一看获取到的数据结果。我们这里直接使用 for 语句去遍历 tr 标签。
for tr in data:
print(tr)
运行结果后,可以看到每一对 tr 标签都被遍历了,但是我们需要的td标签中的非属性字符串。这里使用 isinstance(tr, bs4.element.Tag) 去判断 tr 是否是 bs4 标签类型的元素。再用搜索文档树的另一种方法 find_all() 查询到所有td标签并保存到列表 tds 里。
import bs4
info = []
for tr in soup.find('tbody').children:
if isinstance(tr, bs4.element.Tag):
tds = tr.findall('td')
info.append([tds[0].string, tds[1].string, tds[4].string])
print(info)
'''
[['1', '哈佛大学', '100.0'],
['2', '斯坦福大学', '75.1'],
['3', '剑桥大学', '72.3'],
['4', '麻省理工学院', '69.0'],
['5', '加州大学-伯克利', '67.9'],
['6', '普林斯顿大学', '60.0'],
['7', '牛津大学', '59.7'],
['8', '哥伦比亚大学', '59.1'],
['9', '加州理工学院', '58.6'],
['10', '芝加哥大学', '55.1'],
['11', '加州大学-洛杉矶', '50.8'],
['11', '耶鲁大学', '50.8'],
......]
'''
find_all() 它能够查询所有符合条件的元素,以列表的形式返回查询结果。它的完整参数形式与 find() 相同,这里就不在赘述了,若忘记,请回看以上内容。现在所有的 td 标签都保存在 tds 里面,我们用 tag.string 去取出标签中的非属性字符串。这是 Tag 标签的基本属性之一,称为 NavigableString。
完整代码
import requests
import bs4 import BeautifulSoup
import bs4
r = requests.get("https://labfile.oss.aliyuncs.com/courses/2184/2019%E8%BD%AF%E7%A7%91%E4%B8%96%E7%95%8C%E5%A4%A7%E5%AD%A6%E5%AD%A6%E6%9C%AF%E6%8E%92%E5%90%8D.html")
r.encoding = r.apparent_encoding
html = r.text
soup = BeautifulSoup(html, "html.parser")
data = soup.find("tbody").children
info = []
for tr in soup.find('tbody').children:
if isinstance(tr, bs4.element.Tag):
tds = tr.find_all('td')
info.append([tds[0].string, tds[1].string, tds[4].string])
print(info)
三、实例
爬取课程名称:
import requests
import bs4
from bs4 import BeautifulSoup
try:
url = "https://www.lanqiao.cn/courses/"
r = requests.get(url)
print(r.raise_for_status)
r.encoding = r.apparent_encoding
demo = r.text
except:
print("未能获取页面内容")
soup = BeautifulSoup(demo, 'html.parser')
div = soup.find('body').div
a = div.find_all('a','link block')
href_list = []
div_list = []
for i in a:
href_list.append("https://www.lanqiao.cn"+i.get('href'))
div_list.append(i.find('div', 'course-cover relative'))
img_list = []
names = []
info_dict = {}
for i in div_list:
img_list.append(i.find('img'))
for i in img_list:
names.append(i.get('alt'))
for i in range(0, len(names)):
info_dict[names[i]] = href_list[i]
print(info_dict)
学完两个爬虫实例了,感觉重点在于对返回页面的结构分析上,还有遍历和取数据的一个思路。以前都是零散的学,现在算是系统的学了一边,麻雀虽小五脏俱全,基本的思路算是掌握了。