目录
一、BeautifulSoup4库
二、安装和文档
三、几大解析工具对比
四、简单使用
五、四个常用的对象(了解)
1、Tag
3、BeautifulSoup
4、Comment
总结
六、遍历文档树
1、contents 和 children
2、strings 和 stripped_strings
七、搜索文档树
1. find和find_all方法
例子
总结
2. select方法
例子
总结
八、中国天气网爬虫
一、BeautifulSoup4库
和 lxml 一样,Beautiful Soup 也是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据。
lxml 只会局部遍历,而Beautiful Soup 是基于HTML DOM(document Object Model)的,会载入整个文档,解析整个DOM树,因此时间和内存开销都会大很多,所以性能要低于lxml。
BeautifulSoup 用来解析 HTML 比较简单,API非常人性化,支持css选择器、Python标准库中的HTML解析器,也支持 lxml 的 XML解析器。
Beautiful Soup 3 目前已经停止开发,推荐现在的项目使用Beautiful Soup 4。
安装:pip install bs4 , python3 使用 pip3 install bs4
中文文档:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html
三、几大解析工具对比
解析工具 | 解析速度 | 使用难度 |
---|---|---|
BeautifulSoup | 最慢 | 最简单 |
lxml | 快 | 简单 |
正则 | 最快 | 最难 |
四、简单使用
from bs4 import BeautifulSoupHTML = """<HTML> <head><Title>The Dormouse's story</Title></head> <body> <div > <p ID="pID1" >python</p> <p >广州</p> <p >python研发工程师</p> </div> <div> <p >java</p> <p >深圳</p> <p >java研发工程师</p> <a ID="test" herf="http://www.baIDu.com">http://www.baIDu.com</a> </div> </body></HTML>"""# 这里使用 lxml, 需要先安装 lxml模块soup = BeautifulSoup(HTML, "lxml")print(soup.prettify())
五、四个常用的对象(了解)
Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:
Tag
NavigatableString
BeautifulSoup
Comment
下面四个类的代码基于如下代码进行测试:
from bs4 import BeautifulSoupHTML = """<HTML> <head><Title>The Dormouse's story</Title></head> <body> <div > <p ID="pID1" >python</p> <p >广州</p> <p >python研发工程师</p> <p ID="p1"> <!-- 这是一个注释 --> </p> <p ID="p2"><!-- 这是一个注释 --></p> </div> </body></HTML>"""soup = BeautifulSoup(HTML, "lxml")
1、TagTag 通俗点讲就是 HTML 中的一个个标签。我们可以利用 soup 加标签名轻松地获取这些标签的内容,这些对象的类型是bs4.element.Tag。
# Tagp = soup.select("p")[0]print(type(p)) # <class 'bs4.element.Tag'>
2、NavigableString如果拿到标签后,还想获取标签中的内容。那么可以通过tag.string获取标签中的文字。示例代码如下:
# NavigableStringp = soup.select("p")[0]print(type(p.string)) # <class 'bs4.element.NavigableString'>
3、BeautifulSoupBeautifulSoup 对象表示的是一个文档的全部内容.大部分时候,可以把它当作 Tag 对象,它支持 遍历文档树 和 搜索文档树 中描述的大部分的方法.
因为 BeautifulSoup 对象并不是真正的HTML或XML的tag,所以它没有name和attribute属性.但有时查看它的 .name 属性是很方便的,所以 BeautifulSoup 对象包含了一个值为 “[document]” 的特殊属性 .name
# BeautifulSoupsoup = BeautifulSoup(HTML, "lxml")print(type(soup)) # <class 'bs4.BeautifulSoup'>print(soup.name) # [document]
4、CommentTag , NavigableString , BeautifulSoup 几乎覆盖了HTML和xml中的所有内容,但是还有一些特殊对象.容易让人担心的内容是文档的注释部分:
Comment 对象是一个特殊类型的 NavigableString 对象:
# Commentp1 = soup.select("p#p2")[0]print(p1.string) # 这是一个注释print(type(p1.string)) # <class 'bs4.element.Comment'>
总结 常见的四种对象
1、Tag:BeautifulSoup 中所有的标签都是 Tag 类型, 并且 BeautifulSoup 的对象本质上也是一个 Tag 类型。所有一些方法比如 find、find_all 并不是 BeautifulSoup de ,而是 Tag 的。
2、NavigableString :继承自 python 的 str, 用起来和python str 一样。
3、BeautifulSoup : 继承自 Tag, 用来生成 BeautifulSoup 树。
4、Comment : 继承自NavigableString
contents 和 children:
返回某个标签下的直接子元素,其中也包括字符串。
contents: 返回的是一个列表
children:返回的是一个迭代器
六、遍历文档树 1、contents 和 children
from bs4 import BeautifulSoupHTML = """<HTML> <head><Title>The Dormouse's story</Title></head> <body> <div > <p ID="pID1" >python</p> <p >广州</p> <p >python研发工程师</p> <p ID="p1"> <!-- 这是一个注释 --> </p> <p ID="p2"><!-- 这是一个注释 --></p> </div> </body></HTML>"""soup = BeautifulSoup(HTML, "lxml")print("===============================")div = soup.find("div")# div.contents 返回所有子节点列表for p in div.contents: print(p)print("===============================")div = soup.find("div")# div.contents 返回所有子节点的生成器for p in div.children: print(p)
2、strings 和 stripped_strings如果tag中包含多个字符串 ,可以使用 .strings 来循环获取:
for string in soup.strings: print(repr(string)) # u"The Dormouse's story" # u'\n\n' # u"The Dormouse's story" # u'\n\n' # u'Once upon a time there were three little sisters; and their names were\n' # u'ElsIE' # u',\n' # u'LacIE' # u' and\n' # u'TillIE' # u';\nand they lived at the bottom of a well.' # u'\n\n' # u'...' # u'\n'
输出的字符串中可能包含了很多空格或空行,使用 .stripped_strings 可以去除多余空白内容:
for string in soup.stripped_strings: print(repr(string)) # u"The Dormouse's story" # u"The Dormouse's story" # u'Once upon a time there were three little sisters; and their names were' # u'ElsIE' # u',' # u'LacIE' # u'and' # u'TillIE' # u';\nand they lived at the bottom of a well.' # u'...
七、搜索文档树1. find和find_all方法
搜索文档树,一般用得比较多的就是两个方法,一个是find
,一个是find_all
。
find
方法是找到第一个满足条件的标签后就立即返回,只返回一个元素。
find_all
方法是把所有满足条件的标签都选到,然后返回回去。使用这两个方法,最常用的用法是出入name
以及attr
参数找出符合要求的标签。
soup.find_all("a",attrs={"ID":"link2"})
或者是直接传入属性的的名字作为关键字参数:
soup.find_all("a",ID='link2')
例子HTML = """<HTML> <head><Title>The Dormouse's story</Title></head> <body> <div > <p ID="pID1" >python</p> <p >广州</p> <p >python研发工程师</p> </div> <div > <p >java</p> <p >深圳</p> <p >java研发工程师</p> <a ID="test" href="http://www.baIDu.com">http://www.baIDu.com</a> </div> </body></HTML>"""# 1、获取所有 p 标签# 2、获取第二个 p 标签# 3、获取所有 class 等于 even 的 p 标签# 4、获取所有 ID 等于 test, class 等于 test 的 a 标签# 5、获取所有 a 标签的 herf 属性# 6、获取所有的职位信息(纯文本)soup = BeautifulSoup(HTML, "lxml")# print(soup.prettify())# 1、获取所有 p 标签ps = soup.find_all("p")# print(type(ps[0])) # <class 'bs4.element.Tag'>for p in ps: print(p)# 2、获取第二个 p 标签p = soup.find_all("p", limit=2)[1]p = soup.find_all("p")[1]print(p)# 3、获取所有 class 等于 even 的 p 标签ps = soup.find_all("p", class_="even")ps = soup.find_all("p", attrs={"class": "even"})for p in ps: print(p)# 4、获取所有 ID 等于 test, class 等于 test 的 a 标签aList = soup.find_all("a", class_="test", ID="test")aList = soup.find_all("a", attrs={"class": "test", "ID": "test"})for a in aList: print(a)# 5、获取所有 a 标签的 href 属性aList = soup.find_all("a")for a in aList: # 1、通过下标 *** 作的方式 print(a["href"]) # 2、通过 attrs 属性的方式 print(a.attrs["href"])# 6、获取所有的职位信息(纯文本)divs = soup.find_all("div")positions = []for div in divs: # 通过 tag.string 获取内容 position = {} ps = div.find_all("p") language = ps[0].string address = ps[1].string name = ps[2].string position['language'] = language position['address'] = address position['name'] = name positions.append(position) # 通过 strings 获取内容 gen = div.strings # 返回的是一个生成器 # print(type(gen)) # <class 'generator'> infos = List(div.strings) # 生成的列表带有空白数据 positions.append(infos) # [['\n', 'python', '\n', '广州', '\n', 'python研发工程师', '\n'], # ['\n', 'java', '\n', '深圳', '\n', 'java研发工程师', '\n', 'http://www.baIDu.com', '\n']] # 通过 stripped_strings 获取内容 gen = div.stripped_strings # 返回的是一个生成器 # print(type(gen)) # <class 'generator'> infos = List(div.stripped_strings) # 生成的列表没有有空白数据 positions.append(infos) # [['python', '广州', 'python研发工程师'], # ['java', '深圳', 'java研发工程师', 'http://www.baIDu.com']] # 通过 get_text 获取内容 print(type(div.get_text())) # <class 'str'> print(div.get_text())print(positions)
总结find_all 的作用 1、在提取标签的时候,第一个参数是标签的名字。然后如果在提取标签的时候想要使用标签的属性进行过滤,那么可以在这个地方通过关键字参数的形式,将属性的名字以及对应的值传进去。或者使用 atrs 属性, 将所有的属性以及对应的值放进一个字典传给 attrs 属性。 2、有些时候,在提取标签的时候,不像提取那么多,那么可以使用 limit 参数,限制提取多少个。find 与 find_all 的区别 1、find:找到第一个满足条件的标签就返回。只会返回一个元素 2、find_all:将所有满足条件的标签都返回 使用 find 和 find_all 的过滤条件 1、关键字参数:将属性的名字作为关键字参数的 key ,属性的值作为关键字参数的 value。 2、attrs 参数:将属性条件放到一个字典中,传给 attrs 参数 获取标签的属性: 1、通过下标获取:通过标签的下标方式: href = a["href"] 2、通过 attrs 属性获取 href = a.attrs["href"]string、strings、stripped_strings 和 get_text 方法: 1、string:获取某个标签下的非标签字符串,返回的是一个字符串。如果这个标签下有多行字符,那么就不能获取到。 2、strings:获取某个标签下的子孙非标签字符串,返回的是一个生成器 3、stripped_strings:获取某个标签下的子孙非标签字符串,去掉空白字符串。返回的是一个生成器 4、get_text:获取某个标签下的子孙非标签字符串。以普通字符串返回
2. select方法使用以上方法可以方便的找出元素。但有时候使用CSS
选择器的方式可以更加的方便。使用CSS
选择器的语法,应该使用select
方法。以下列出几种常用的CSS
选择器方法:
(1)通过标签名查找:
print(soup.select('a'))
(2)通过类名查找:
通过类名,则应该在类的前面加一个.
。比如要查找class=sister
的标签。示例代码如下:
print(soup.select('.sister'))
(3)通过ID查找:
通过ID查找,应该在ID的名字前面加一个#号。示例代码如下:
print(soup.select("#link1"))
(4)组合查找:
组合查找即和写 class 文件时,标签名与类名、ID名进行的组合原理是一样的,例如查找 p 标签中,ID 等于 link1的内容,二者需要用空格分开:
print(soup.select("p #link1"))
直接子标签查找,则使用 > 分隔:
print(soup.select("head > Title"))
(5)通过属性查找:
查找时还可以加入属性元素,属性需要用中括号括起来,注意属性和标签属于同一节点,所以中间不能加空格,否则会无法匹配到。示例代码如下:
print(soup.select('a[href="http://example.com/elsIE"]'))
(6)获取内容
以上的 select 方法返回的结果都是列表形式,可以遍历形式输出,然后用 get_text() 方法来获取它的内容。
soup = BeautifulSoup(HTML, 'lxml')print type(soup.select('Title'))print soup.select('Title')[0].get_text()for Title in soup.select('Title'): print Title.get_text()
例子from bs4 import BeautifulSoupHTML = """<HTML> <head><Title>The Dormouse's story</Title></head> <body> <div > <p ID="pID1" >python</p> <p >广州</p> <p >python研发工程师</p> </div> <div > <p >java</p> <p >深圳</p> <p >java研发工程师</p> <a ID="test" href="http://www.baIDu.com">http://www.baIDu.com</a> </div> </body></HTML>"""# 1、获取所有 p 标签# 2、获取第二个 p 标签# 3、获取所有 class 等于 even 的 p 标签# 4、获取所有 a 标签的 herf 属性# 5、获取所有的职位信息(纯文本)soup = BeautifulSoup(HTML, "lxml")# print(soup.prettify())# 1、获取所有 p 标签ps = soup.select("p")# print(type(ps[0])) # <class 'bs4.element.Tag'>for p in ps: print(p)# 2、获取第二个 p 标签pList = soup.select("p")print(type(pList)) # <class 'bs4.element.ResultSet'>print(type(pList[0])) # <class 'bs4.element.Tag'>p2 = pList[1]print(p2) # <p >广州</p># 3、获取所有 class 等于 even 的 p 标签# pList = soup.select("p.even")pList = soup.select("p[class='even']")for p in pList: print(p)# 4、获取所有 a 标签的 href 属性aList = soup.select("a")for a in aList: print(a["href"]) # http://www.baIDu.com# 5、获取所有的职位信息(纯文本)# 可以使用 string、strings、stripped_strings、get_text 方法divs = soup.select("div")for div in divs: print(List(div.stripped_strings))"""['python', '广州', 'python研发工程师']['java', '深圳', 'java研发工程师', 'http://www.baIDu.com']"""
总结在 BeautifulSoup 中,要使用 CSS 选择器,那么应该使用 soup.select() 方法。应该传递一个 CSS 选择器的字符串给 select 方法。
八、中国天气网爬虫爬取中国天气网全国所有城市当前最低温度;将数据排序后,将温度最高的10个城市通过图标显示出来。
代码
import requestsfrom bs4 import BeautifulSoupfrom pyecharts import options as optsfrom pyecharts.charts import barfrom pyecharts.faker import FakerheaderS = { "User-Agent": "Mozilla/5.0 (windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36", "Referer": "http://www.weather.com.cn/textFC/db.sHTML",}def parse_page(url): # 获取天气预报页面 response = requests.get(url=url, headers=headerS) text = response.content.decode("utf-8") # print(text) # 通过 BeautifulSoup 解析HTML 页面,并获取到面所有 table 标签内容 # 使用 HTML5lib 代替 lxml: 由于 gat.HTML 页面的天气数据,只有 <table>, 没有 </table>, # lxml 解析不了,会报错,但是通过 浏览器解析后我们看到的HTML , 浏览器已经帮我们补全所以看出是少了闭合标签 # 如果通过 HTML5lib解析器 解析, 返回的 table 会帮程序补全闭合标签 # 安装命令: pip3 install HTML5lib soup = BeautifulSoup(text, "HTML5lib") # 页面会有7天的数据(默认使用第一个(今天)) conMIDtab = soup.find("div", class_="conMIDtab") tables = conMIDtab.find_all("table") # 解析每个表格的数据 citIEs = [] for table in tables: # print(table) trs = table.find_all("tr")[2:] # 第一二行为表头 # 解析每一行的数据 for index, tr in enumerate(trs): tds = tr.find_all("td") td = tds[0] if index == 0: td = tds[1] # 数据的第一行的第一列是省份,第二列才是城市 city = List(tds[0].stripped_strings)[0] min_temp = List(tds[-2].stripped_strings)[0] citIEs.append({"city": city, "min_temp": int(min_temp)}) return citIEsdef creat_HTML(xdata, ydata): bar = bar() bar.add_xaxis(xdata) bar.add_yaxis("城市", ydata) bar.set_global_opts( Title_opts=opts.TitleOpts(title="城市最低温度排序后10名", subtitle="我是副标题"), # brush_opts=opts.BrushOpts(), ) # 渲染数据并保存到HTML 页面 bar.render("bar_with_brush.HTML")def main(): all_data = [] url_List = [ "http://www.weather.com.cn/textFC/hb.sHTML", "http://www.weather.com.cn/textFC/db.sHTML", "http://www.weather.com.cn/textFC/hd.sHTML", "http://www.weather.com.cn/textFC/hz.sHTML", "http://www.weather.com.cn/textFC/hn.sHTML", "http://www.weather.com.cn/textFC/xb.sHTML", "http://www.weather.com.cn/textFC/xn.sHTML", "http://www.weather.com.cn/textFC/gat.sHTML", ] for url in url_List: datas = parse_page(url) all_data.extend(datas) # 通过匿名函数设置排序的key all_data.sort(key=lambda data: data["min_temp"]) # url = "http://www.weather.com.cn/textFC/gat.sHTML" # datas = parse_page(url) # all_data.extend(datas) # all_data.sort(key=lambda data: data["min_temp"]) # 通过 pyecharts 将 城市最低温度 排序 最高 的10个城市显示成 HTML show_data = all_data[-10:] citIEs = List(map(lambda data: data["city"], show_data)) min_temps = List(map(lambda data: data["min_temp"], show_data)) creat_HTML(citIEs, min_temps) print("all_data: ", all_data)if __name__ == '__main__': main()
结果:
总结以上是内存溢出为你收集整理的python_爬虫 06 BeautifulSoup4库全部内容,希望文章能够帮你解决python_爬虫 06 BeautifulSoup4库所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)