上一篇博客2.urllib库学习、反爬虫网页源码爬取介绍了如何爬取网页源码,这一篇博客介绍如何对爬取到的html文件进行解析
使用 Beautiful Soup 解析 html 文件
1.先爬取到百度首页网页源码保存到本地
import pickle # 保存html文件
import urllib.request
url = "http://www.baidu.com"
response = urllib.request.urlopen(url)
pickle.dump(response.read(),open('./baidu.html','wb'))
如果有一天,baidu不再是那个百度,本博客可以下载以下html源码进行后续教程的学习
2021.02.02.12:57爬取baidu首页源码:https://wwx.lanzoui.com/i5QOvl7peyb
2.使用html.parser进行解析
from bs4 import BeautifulSoup
file = open("./baidu.html", "rb")
html = file.read() # 读取文本
bs = BeautifulSoup(html, "html.parser") # bs对象来解析,使用html.parser解析器
bs是创建的一个BeautifulSoup解析对象,bs是<class ‘bs4.BeautifulSoup’>类型,BeautifulSoup4将复杂HTML文档转换为一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:
-
1.Tag
-
2.NavigableString
-
3.BeautifulSoup
-
4.Comment
1. tag:标签(包含标签内的内容),只能拿到所找到的第一个匹配的标签
print(bs.title)
print(type(bs.title))
bs.title匹配第一个title是:
百度一下,你就知道
type(bs.title)是:<class ‘bs4.element.Tag’>
解析对象.标签,得到的是标签及其内容
2. NavigableString:标签里的内容
print(bs.title.string)
print(type(bs.title.string)) # NavigableString
bs.title匹配第一个title是:
百度一下,你就知道 扫描二维码关注公众号,回复: 12501490 查看本文章
bs.title.string就是:百度一下,你就知道
type(bs.title.string)是:<class ‘bs4.element.NavigableString’>
解析对象.标签.string是标签的中间的内容
除了获取标签及其内容、获取标签的内容、还可以获取标签的属性attributes:
print(bs.a)
print(bs.a.attrs)
print(type(bs.a.attrs)) # <class 'dict'>
bs.a是:百度首页
bs.a.attrs是:{‘class’: [‘toindex’], ‘href’: ‘/’}
type(bs.a.attrs)是:<class ‘dict’>
解析对象.标签.attrs是标签的所有属性(attrs可以打印a标签的class、href和name等),返回包含所有属性键值对的字典。
3. BeautifulSoup:表示整个文档
print(bs) # 打印的就是整个文档
print(type(bs))
print(bs.name) # [document]
print(bs.a.name)
print(bs) 打印的就是整个html文档内容
type(bs)是:<class ‘bs4.BeautifulSoup’>
bs.name是:[document]
bs.a.name是:a
解析对象.标签.name是标签的类型,或者解析对象.name是解析对象的类型
5.Comment:是一个特殊的NavigableString,输出的内容不包含注释
要看到Comment,请手动将baidu.html中百度首页修改成
注意:再次执行时请频闭爬取并保存baidu.html部分的代码
print(bs.a)
print(bs.a.string)
print(type(bs.a.string)) # Comment
bs.a.string是:百度首页
type(bs.a.string)是:<class ‘bs4.element.Comment’>
发现解析对象.标签.string只要标签中的内容带注释,那么注释便会自动屏蔽掉。并且解析对象.标签.string变成了<class ‘bs4.element.Comment’>类型,简单总结Comment是BeautifulSoup的一种特殊情况
实战应用
解析器将html源码,组织管理成树状数据结构的内容,对于所有节点的获取采用遍历的方式
节点获取:遍历
print(bs.head.contents)
print(bs.head.contents[1])
bs.head.contents是head标签中的所有一级标签
bs.head.contents[1]拿到head标签中的所有一级标签中的第二个
析对象.head.contents拿到了head标签中的所有一级标签,采用列表返回
文档的搜索:针对性(指定div)
1.find_all
字符串过滤,匹配与字符串完全匹配的所有标签内容,返回结果列表,举个栗子:
t_list = bs.find_all("a")
print(t_list)
查找所有的a标签,返回结果列表
2.正则表达式搜索:使用search方法来匹配内容
还是上面的栗子,查找所有的带a字符的内容
t_list = bs.find_all(re.compile("a"))
printf(t_list)
t_list = bs.find_all(text=re.compile("\d")) # 包含数字的字符串
for it in t_list:
print(it)
re.compile(“a”)创建了一个匿名模式对象,查找的是标签及内容。正则表达式的模式对象也可以赋值给text,text=re.compile("\d"),查找的是含数字的内容(不包含标签本身)
3.方法:传入一个函数(方法),根据函数的要求来搜索
首先定义一个函数,返回标签是否有name属性的真值1
def name_is_exists(tag):
return tag.has_attr("name")
t_list = bs.find_all(name_is_exists) # 查询所有有name属性的标签
print(t_list)
bs.find_all(name_is_exists)查找所有带name属性的标签
4.kwargs 参数
t_list = bs.find_all(id="head") # id是head的标签
print(it)
t_list = bs.find_all(class_=True) # 有class属性值的标签
print(it)
t_list = bs.find_all(href="http://news.baidu.com") # 查找href="http://news.baidu.com"
print(it)
5.text参数: 特定文本
查找含"hao123"文本的内容
t_list = bs.find_all(text="hao123")
# 参数可以是列表,结果是并集
t_list = bs.find_all(text=["hao123","地图","贴吧"])
for it in t_list:
print(it)
可以同时匹配多个文本内容
6.limit参数:得到前limit个匹配元素
t_list = bs.find_all("a", limit=3)
for it in t_list:
print(it)
上述例子得到了前三个a标签
7.CSS选择器:页面中的嵌套,通过id或者class快速定位,参数可以是标签id和class—用法类似于jQuery
# 按标签查找,返回所有匹配的标签
print(bs.select('title'))
# 按类名查找,返回所有匹配的标签
print(bs.select('.mnav'))
# 按id查找,返回所有匹配的标签
print(bs.select('#u1'))
# 筛选某个标签的属性或者id等于什么,返回所有匹配的标签
print(bs.select("a[class='s-set-hotsearch set-show']")) # 筛选class是's-set-hotsearch set-show'的a标签
# 通过层级结构查找子标签
res = bs.select("head > link")# 查找head标签中的所有link子标签,不包含孙标签
print(res)
print(len(res))
for it in res:
print(it)
# 查找兄弟标签,特点是只能往后查找
t_list = bs.select(".toindex ~ .pf") # 先找到class是toindex的标签,然后向后查找class是pf的同级标签
print(len(t_list))
print(t_list[0].get_text())
这个例子涉及到html源码中的如下内容
"""
<a class="toindex" href="/">百度首页</a>
<a href="javascript:;" name="tj_settingicon" class="pf">设置<i class="c-icon c-icon-triangle-down"></i></a>
<a href="https://passport.baidu.com/v2/?login&tpl=mn&u=http%3A%2F%2Fwww.baidu.com%2F&sms=5" name="tj_login" class="lb" onclick="return false;">登录</a>
<div class="bdpfmenu"></div>
"""
任务驱动型开发:将豆瓣Top250电影爬取的数据组织成树形结构数据
# import bs4 #只需要使用bs4中的BeautifulSoup因此可以如下写法:
from bs4 import BeautifulSoup # 网页解析,获取数据
import urllib.request, urllib.error # 指定url,获取网页数据
def main():
# 爬取的网页
baseurl = "https://movie.douban.com/top250?start="
# # 保存的路径
savepath = ".\\豆瓣电影Top250.xls" # 使用\\表示层级目录或者在整个字符串前加r“.\豆瓣电影Top250”
savepath2Db = "movies.db"
# # 1.爬取网页
# print(askURL(baseurl))
datalist = getData(baseurl)
print(datalist)
# 爬取网页
def getData(baseurl):
datalist = []
for i in range(0, 10): # 一页25条电影
url = baseurl + str(i*25)
html = askURL(url) # 保存获取到的网页源码
# print(html)
# 2.解析数据(逐一)
soup = BeautifulSoup(html, "html.parser") # 使用html.parser解析器解析html文档形成树形结构数据
# 解析...
return datalist
# 得到执行url的网页信息
def askURL(url):
# 头部信息 其中用户代理用于伪装浏览器访问网页
head = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/87.0.4280.88 Safari/537.36"}
req = urllib.request.Request(url, headers=head)
html = "" # 获取到的网页源码
try:
response = urllib.request.urlopen(req)
html = response.read().decode("utf-8")
except urllib.error.URLError as e:
if hasattr(e, "code"): # has attribute
print(e.code)
if hasattr(e, "reason"):
print(e.reason)
return html
if __name__ == '__main__':
main()
布尔 ↩︎