第02章 BeautifulSoup 入门

 

序言

1. 内容介绍

本章详细介绍了BeautifulSoup 的安装、 BeautifulSoup 对象创建、BeautifulSoup 对象相关节点选取等内容。

2. 理论目标

  • 了解 BeautifulSoup 的安装
  • 了解 BeautifulSoup 对象创建
  • 了解 BeautifulSoup 对象相关节点选取

3. 实践目标

  • 能掌握 BeautifulSoup 的安装及对象创建,完成网页关键信息选取

4. 实践案例

5. 内容目录

  • 1.BeautifulSoup 简介与安装

  • 2.BeautifulSoup 创建及对象种类

  • 3.BeautifulSoup 遍历文档树

  • 4.BeautifulSoup 搜索文档树

  • 5.BeautifulSoup CSS选择器


第1节 BeautifulSoup 简介与安装

1. BeautifulSoup 简介

Beautiful Soup 是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据。

通过解析文档为用户提供需要抓取的数据,已成为和lxml、html6lib 一样出色的python 解释器,为用户灵活地提供不同的解析策略或强劲的速度。

简单来说,就是把HTML/XML生成规范性文档,方便查找目标元素。

 

2. BeautifulSoup 安装

使用 BeautifulSoup,除了安装beautifulsoup4,最好也安装解析器 lxml

  • BeautifulSoup 安装:
pip install beautifulsoup4

51658daf7f93a500aafa37f23f4d21a3.png

  • 解析器 lxml 安装:
pip install lxml

c5111d548cf893675b581c9e87305527.png


第2节 BeautifulSoup 创建及对象种类

1. BeautifulSoup 创建

 

## 导入BeautifulSoup 库,Beautiful Soup 4 已经被移植到 BS4,因此导入时我们需要 import bs4 from bs4 import BeautifulSoup ## 导入html 文档 with open('example.html', 'rb') as f: html = f.read() print(type(html)) bs = BeautifulSoup(html, "lxml") #解析html 文档内容,创建对象 print(bs)

 

<class 'bytes'> <!DOCTYPE html> <html> <head> <meta content="text/html;charset=utf-8" http-equiv="content-type"/> <meta content="IE=Edge" http-equiv="X-UA-Compatible"/> <meta content="always" name="referrer"/> <link href="https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css" rel="stylesheet" type="text/css"/> <title>百度一下,你就知道 </title> </head> <body link="#0000cc"> <div id="wrapper"> <div id="head"> <div class="head_wrapper"> <div id="u1"> <a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a> <a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a> <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a> <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a> <a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a> <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a> </div> </div> </div> </div> </body> </html>

b0749bbcc451ce646fd48c45225a023b.png

  • Beautiful Soup 自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。

exampe.html 内容

 

<!DOCTYPE html> <html> <head> <meta content="text/html;charset=utf-8" http-equiv="content-type" /> <meta content="IE=Edge" http-equiv="X-UA-Compatible" /> <meta content="always" name="referrer" /> <link href="https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css" rel="stylesheet" type="text/css" /> <title>百度一下,你就知道 </title> </head> <body link="#0000cc"> <div id="wrapper"> <div id="head"> <div class="head_wrapper"> <div id="u1"> <a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!--新闻--> </a> <a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a> <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a> <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a> <a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a> <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a> </div> </div> </div> </div> </body> </html>

2. BeautifulSoup 对象种类

BeautifulSoup4将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:

  1. BeautifulSoup
  2. Tag
  3. NavigableString
  4. Comment

5c458162d9ba92df9e0baa97fbdbefad.png

BeautifulSoup

BeautifulSoup对象表示的是一个文档的内容,可以当作 Tag 对象。

 

print(bs) print(bs.name) print(type(bs.name)) print(bs.attrs)

 

<!DOCTYPE html> <html> <head> <meta content="text/html;charset=utf-8" http-equiv="content-type"/> <meta content="IE=Edge" http-equiv="X-UA-Compatible"/> <meta content="always" name="referrer"/> <link href="https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css" rel="stylesheet" type="text/css"/> <title>百度一下,你就知道 </title> </head> <body link="#0000cc"> <div id="wrapper"> <div id="head"> <div class="head_wrapper"> <div id="u1"> <a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a> <a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a> <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a> <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a> <a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a> <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a> </div> </div> </div> </div> </body> </html> [document] <class 'str'> {}

Tag

Tag通俗点讲就是HTML中的一个个标签。

soup 加标签名轻松地获取这些标签的内容,查找的是在所有内容中的第一个符合要求的标签

 

# 获取title标签的所有内容 print("这是一个title 标签:\n", bs.title) print("\n") # 获取head标签的所有内容 print("这是一个head 标签:\n", bs.head) print("\n") # 获取第一个a标签的所有内容 print("这是一个a 标签:\n", bs.a) print("\n") # 类型 print("这是一个a 标签的类型:\n", type(bs.a))

 

这是一个title 标签: <title>百度一下,你就知道 </title>

 

这是一个head 标签: <head> <meta content="text/html;charset=utf-8" http-equiv="content-type"/> <meta content="IE=Edge" http-equiv="X-UA-Compatible"/> <meta content="always" name="referrer"/> <link href="https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css" rel="stylesheet" type="text/css"/> <title>百度一下,你就知道 </title> </head>

 

这是一个a 标签: <a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>

 

这是一个a 标签的类型: <class 'bs4.element.Tag'>

Tag 有两个重要的属性

  • name
  • attrs
 

# bs 对象本身比较特殊,它的 name 即为 [document] print(bs.name) # 对于内部标签,输出的值便为标签本身的名称 print(bs.head.name) # 打印标签的所有属性,得到的类型是一个字典。 print(bs.a.attrs) # 获取属性内容 print(bs.a['class']) # 等价 bs.a.get('class') # 修改属性和内容,此处修改后就无法获取 bs.a['class'] = "newClass" print(bs.a) # 删除属性 del bs.a['class'] print(bs.a)

[document]
head
{'class': ['mnav'], 'href': 'http://news.baidu.com', 'name': 'tj_trnews'}
['mnav']
<a class="newClass" href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>
<a href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>

NavigableString

即标签内部的内容、文字。

 

## 获取标签及相应内容 print(bs.title) print(bs.title.string) print("\n类型是:") print(type(bs.title.string))

<title>百度一下,你就知道 </title>
百度一下,你就知道 

类型是:
<class 'bs4.element.NavigableString'>

Comment

Comment 对象是一个特殊类型的NavigableString 对象,其输出的内容不包括注释符号,但包括注释符号里面的内容。

可以简单认为,如果标签内部的内容、文字是注释内容(文档说明内容),即为Comment,否则为NavigableString(网页内容)。

如果不处理,可能会对我们的文本处理造成意想不到的麻烦。

 

# <a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a> print(bs.a) print(bs.a.string) # 新闻 print(type(bs.a.string)) # <class 'bs4.element.Comment'> print(str(type(bs.a.string)) == "<class 'bs4.element.Comment'>")

<a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>
 新闻 
<class 'bs4.element.Comment'>
True

第3节 BeautifulSoup 遍历文档树

BeautifulSoup 主要提供以下属性遍历文档树

序号属性作用说明
1.contents获取Tag的所有子节点,返回一个list
2.children获取Tag的所有子节点,返回一个生成器
3.descendants获取Tag的所有子孙节点
4.strings如果Tag包含多个字符串,即在子孙节点中有内容,可以用此获取,而后进行遍历
5.stripped_strings与strings用法一致,只不过可以去除掉那些多余的空白内容
6.parent获取Tag的父节点
7.parents递归得到父辈元素的所有节点,返回一个生成器
8.previous_sibling获取当前Tag的上一个节点,属性通常是字符串或空白,真实结果是当前标签与上一个标签之间的顿号和换行符
10.previous_siblings获取当前Tag的上面所有的兄弟节点,返回一个生成器
9.next_sibling获取当前Tag的下一个节点,属性通常是字符串或空白,真是结果是当前标签与下一个标签之间的顿号与换行符
11.next_siblings获取当前Tag的下面所有的兄弟节点,返回一个生成器
12.previous_element获取解析过程中上一个被解析的对象(字符串或tag),与previous_sibling不同,这里包括不同级的
14.previous_elements返回一个生成器,可以向前访问文档的解析内容
13.next_element获取解析过程中下一个被解析的对象(字符串或tag),与next_sibling不同,这里包括不同级的
15.next_elements返回一个生成器,可以向后访问文档的解析内容
16.has_attr判断Tag是否包含属性

1. 子孙标签

 

print(".contents:获取Tag的所有子节点,返回一个list(含换行符):\n") print(bs.head.contents) print("*"*50 + "此处为分隔符" + "*"*50 + "\n") print(".children:获取Tag的所有子节点,返回一个生成器(含换行符):\n") print(bs.head.children) print("\n遍历结果:") for i in bs.head.children: print(i) print("*"*50 + "此处为分隔符" + "*"*50 + "\n") print(".descendants:获取Tag的所有子孙节点,不同的是,.descendants对所有tag 的子孙节点进行递归循环:\n") print(bs.head.descendants) print("\n遍历结果:") for i in bs.head.descendants: print(i)

.contents:获取Tag的所有子节点,返回一个list(含换行符):

['\n', <meta content="text/html;charset=utf-8" http-equiv="content-type"/>, '\n', <meta content="IE=Edge" http-equiv="X-UA-Compatible"/>, '\n', <meta content="always" name="referrer"/>, '\n', <link href="https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css" rel="stylesheet" type="text/css"/>, '\n', <title>百度一下,你就知道 </title>, '\n']
*********************************************此处为分隔符*****************************************

.children:获取Tag的所有子节点,返回一个生成器(含换行符):

<list_iterator object at 0x000002388A6CB940>

遍历结果:
<meta content="text/html;charset=utf-8" http-equiv="content-type"/>
<meta content="IE=Edge" http-equiv="X-UA-Compatible"/>
<meta content="always" name="referrer"/>
<link href="https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css" rel="stylesheet" type="text/css"/>
<title>百度一下,你就知道 </title>
**************************************此处为分隔符*************************************

.descendants:获取Tag的所有子孙节点,不同的是,.descendants对所有tag 的子孙节点进行递归循环:

<generator object Tag.descendants at 0x000002388A6D2970>

遍历结果:
<meta content="text/html;charset=utf-8" http-equiv="content-type"/>
<meta content="IE=Edge" http-equiv="X-UA-Compatible"/>
<meta content="always" name="referrer"/> 
<link href="https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css" rel="stylesheet" type="text/css"/> 
<title>百度一下,你就知道 </title>
百度一下,你就知道     

2. 子孙标签内容(文本内容)

 

print(".strings:如果Tag包含多个字符串,即在子孙节点中有内容,可以用此获取,而后进行遍历:\n") print(bs.head.strings) print("\n遍历结果:") for i in bs.head.strings: print(i) print("*"*50 + "此处为分隔符" + "*"*50 + "\n") print(".stripped_strings:与strings用法一致,只不过可以去除掉那些多余的空白内容:\n") print(bs.head.stripped_strings) print("\n遍历结果:") for i in bs.head.stripped_strings: print(i)

.strings:如果Tag包含多个字符串,即在子孙节点中有内容,可以用此获取,而后进行遍历:

<generator object Tag._all_strings at 0x000002388A6D2190>

遍历结果:
百度一下,你就知道 
******************************************此处为分隔符*****************************************

.stripped_strings:与strings用法一致,只不过可以去除掉那些多余的空白内容:

<generator object Tag.stripped_strings at 0x000002388A6D2190>

遍历结果:
百度一下,你就知道

3. 父标签

 

print(bs.a) print(".parent:获取Tag的父节点:\n") print(bs.a.parent) print("\n" + "*"*50 + "此处为分隔符" + "*"*50 + "\n") print(".parents:递归得到父辈元素的所有节点,返回一个生成器:\n") print(bs.a.parents) print("\n遍历结果:") n = 1 for i in bs.a.parents: print("第{}个父标签\n".format(str(n))) print(i) n = n + 1

<a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>
.parent:获取Tag的父节点:

<div id="u1">
<a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>
<a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>
<a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>
<a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>
<a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>
<a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>
</div>

*******************************************此处为分隔符*******************************************
.parents:递归得到父辈元素的所有节点,返回一个生成器:
<generator object PageElement.parents at 0x000002388A79AF20>
遍历结果:
第1个父标签
<div id="u1">
<a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>
<a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>
<a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>
<a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>
<a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>
<a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>
</div>
第2个父标签
<div class="head_wrapper">
<div id="u1">
<a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>
<a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>
<a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>
<a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>
<a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>
<a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>
</div>
</div>
...

4. 上一个节点

 

print(".previous_sibling:获取当前Tag的上一个节点,属性通常是字符串或空白,真实结果是当前标签与上一个标签之间的顿号和换行符:\n") print(bs.body.previous_sibling) print("\n" + "*"*50 + "此处为分隔符" + "*"*50 + "\n") print(".previous_siblings:获取当前Tag的上面所有的兄弟节点,返回一个生成器:\n") print(bs.body.previous_siblings) print("\n遍历结果:") n = 1 for i in bs.body.previous_siblings: print("往上数,第{}个同级标签\n".format(str(n))) print(i) n = n + 1

.previous_sibling:获取当前Tag的上一个节点,属性通常是字符串或空白,真实结果是当前标签与上一个标签之间的顿号和换行符:
*********************************************此处为分隔符*********************************************

.previous_siblings:获取当前Tag的上面所有的兄弟节点,返回一个生成器:

<generator object PageElement.previous_siblings at 0x000002388A6D2040>

遍历结果:
往上数,第1个同级标签

往上数,第2个同级标签

<head>
<meta content="text/html;charset=utf-8" http-equiv="content-type"/>
<meta content="IE=Edge" http-equiv="X-UA-Compatible"/>
<meta content="always" name="referrer"/>
<link href="https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css" rel="stylesheet" type="text/css"/>
<title>百度一下,你就知道 </title>
</head>
往上数,第3个同级标签

5. 下一个节点

 

print(".next_sibling:获取当前Tag的下一个节点,属性通常是字符串或空白,真是结果是当前标签与下一个标签之间的顿号与换行符,同级节点:\n") print(bs.a.next_sibling) print("\n" + "*"*50 + "此处为分隔符" + "*"*50 + "\n") print(".next_siblings:获取当前Tag的下面所有的兄弟节点,返回一个生成器:\n") print(bs.a.next_siblings) print("\n遍历结果:") n = 1 for i in bs.a.next_siblings: print("往下数,第{}个同级标签\n".format(str(n))) print(i) n = n + 1

.next_sibling:获取当前Tag的下一个节点,属性通常是字符串或空白,真是结果是当前标签与下一个标签之间的顿号与换行符,同级节点:
**********************************************此处为分隔符**********************************************

.next_siblings:获取当前Tag的下面所有的兄弟节点,返回一个生成器:

<generator object PageElement.next_siblings at 0x000002388A6D2C10>

遍历结果:
往下数,第1个同级标签
往下数,第2个同级标签

<a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>
往下数,第3个同级标签
往下数,第4个同级标签

<a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>
往下数,第5个同级标签
往下数,第6个同级标签

<a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>
往下数,第7个同级标签
往下数,第8个同级标签

<a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>
往下数,第9个同级标签
往下数,第10个同级标签

<a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>
往下数,第11个同级标签

6. 上一个元素

 

print(".previous_element:获取解析过程中上一个被解析的对象(字符串或tag),与previous_sibling不同的,这里包括不同级的:\n") print(bs.a.previous_element) print("\n" + "*"*50 + "此处为分隔符" + "*"*50 + "\n") print(".previous_elements:返回一个生成器,可以向前访问文档的解析内容:\n") print(bs.a.previous_elements) print("\n遍历结果:") n = 1 for i in bs.a.previous_elements: print("往上数,第{}个元素\n".format(str(n))) print(i) n = n + 1

.previous_element:获取解析过程中上一个被解析的对象(字符串或tag),与previous_sibling不同的,这里包括不同级的:
**********************************************此处为分隔符**********************************************

.previous_elements:返回一个生成器,可以向前访问文档的解析内容:

<generator object PageElement.previous_elements at 0x000002388A6D30B0>

遍历结果:
往上数,第1个元素
往上数,第2个元素

<div id="u1">
<a href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>
<a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>
<a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>
<a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>
<a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>
<a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>
</div>
往上数,第3个元素
往上数,第4个元素
...  
往上数,第27个元素

html

7. 下一个元素

 

print(".next_element:获取解析过程中下一个被解析的对象(字符串或tag),可能与next_sibling不同,这里包括不同级的:\n") print(bs.meta.next_element) print("\n" + "*"*50 + "此处为分隔符" + "*"*50 + "\n") print(".next_elements:返回一个生成器,可以向后访问文档的解析内容:\n") print(bs.meta.next_elements) print("\n遍历结果:") n = 1 for i in bs.meta.next_elements: print("往下数,第{}个元素\n".format(str(n))) print(i) n = n + 1

.next_element:获取解析过程中下一个被解析的对象(字符串或tag),可能与next_sibling不同,这里包括不同级的:
**********************************************此处为分隔符**********************************************

.next_elements:返回一个生成器,可以向后访问文档的解析内容:

<generator object PageElement.next_elements at 0x000002388A6D2190>

遍历结果:
往下数,第1个元素
往下数,第2个元素

<meta content="IE=Edge" http-equiv="X-UA-Compatible"/>
往下数,第3个元素
...

8. 属性判断

 

print(".has_attr:判断Tag是否包含属性:\n") print(bs.a.has_attr("href"))

.has_attr:判断Tag是否包含属性:

True

第4节 BeautifulSoup 搜索文档树

BeautifulSoup 通过find_all 和find 对文档树进行搜索。

uploading.4e448015.gif正在上传…重新上传取消

1. find_all的使用

find_all () 方法搜索当前 tag 的所有 tag 子节点,并判断是否符合过滤器的条件。

  • 语法:find_all(name, attrs, recursive, text, **kwargs, limit)

name 参数

查找所有名字为 name 的 tag

  1. 字符串过滤:匹配标签名等于字符串的tag,返回tag列表。
 

a_list = bs.find_all("a") print(a_list)

[<a href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>, <a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>, <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>, <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>, <a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>, <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>]
  1. 正则表达式过滤:匹配标签名符合正则表达式的tag,返回tag列表。
 

import re pattern = re.compile("^b") a_list = bs.find_all(pattern) print(a_list)

 

[<body link="#0000cc"> <div id="wrapper"> <div id="head"> <div class="head_wrapper"> <div id="u1"> <a href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a> <a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a> <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a> <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a> <a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a> <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a> </div> </div> </div> </div> </body>]

  1. 列表:匹配标签名符合列表中的任一元素的tag,返回tag列表。
 

a_list = bs.find_all(["a", "meta"]) print(a_list)

 

[<meta content="text/html;charset=utf-8" http-equiv="content-type"/>, <meta content="IE=Edge" http-equiv="X-UA-Compatible"/>, <meta content="always" name="referrer"/>, <a href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>, <a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>, <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>, <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>, <a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>, <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>]

  1. 方法:传入一个方法,方法只接受一个元素参数, 如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则返 False。
 

## 校验当前元素,如果包含 class 属性却不包含 id 属性。 def has_class_but_no_id(tag): return tag.has_attr('class') and not tag.has_attr('id') a_list = bs.find_all(has_class_but_no_id) print(a_list)

 

[<div class="head_wrapper"> <div id="u1"> <a href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a> <a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a> <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a> <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a> <a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a> <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a> </div> </div>, <a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>, <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>, <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>, <a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>, <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>]

attrs 参数

针对部分tag 属性在搜索不能使用,比如 HTML5 中的 data-* 属性。

 

data_soup = BeautifulSoup('<div data-foo="value">foo!</div>') data_list = data_soup.find_all(attrs={"data-foo": "value"}) print(data_list)

 

[<div data-foo="value">foo!</div>]

recursive 参数

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

 

a_list = bs.find_all(text="html", recursive=False) print(a_list)

<!DOCTYPE html>
<html>
<head>
<meta content="text/html;charset=utf-8" http-equiv="content-type"/>
<meta content="IE=Edge" http-equiv="X-UA-Compatible"/>
<meta content="always" name="referrer"/>
<link href="https://ss1.bdstatic.com/5eN1bjq8AAUYm2zgoY3K/r/www/cache/bdorz/baidu.min.css" rel="stylesheet" type="text/css"/>
<title>百度一下,你就知道 </title>
</head>
<body link="#0000cc">
<div id="wrapper">
<div id="head">
<div class="head_wrapper">
<div id="u1">
<a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>
<a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>
<a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>
<a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>
<a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>
<a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>
</div>
</div>
</div>
</div>
</body>
</html>
['html']
 

a_list = bs.find_all(text="地图 ", recursive=False) print(a_list)

[]

text 参数

通过 text 参数可以搜搜文档中的字符串内容

 

a_list = bs.find_all(text="地图 ") print(a_list)

['地图 ']

limit 参数

find_all() 方法返回全部的搜索结构,使用limit 参数限制返回结果的数量。效果与 SQL 中的 limit 关键字类似。

 

a_list = bs.find_all("a", limit=2) print(a_list)

[<a href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>, <a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>]

**kwargs 参数

查找属性值符合要求的tag。class 是 python 的关键词,需加个下划线。

 

## 单条件 a_list = bs.find_all(id="wrapper") print(a_list)

[<div id="wrapper">
<div id="head">
<div class="head_wrapper">
<div id="u1">
<a href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>
<a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>
<a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>
<a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>
<a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>
<a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>
</div>
</div>
</div>
</div>]
 

## 正则表达式匹配 import re pattern = re.compile("baidu.com") a_list = bs.find_all(href=pattern) print(a_list)

[<a href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>, <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>, <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>, <a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>, <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>]
 

## 多条件 a_list = bs.find_all(class_="mnav",href="http://news.baidu.com") print(a_list)

[]

2. find的使用

find() 与 find_all() 方法唯一的区别是 find_all() 方法的返回结果是值包含一个元素的列表,而 find() 方法直接返回去全部结果

  • 语法:find( name , attrs , recursive , text , **kwargs )

从结果可以看出find_all(),尽管传入了limit=1,但是返回值仍然为一个列表,当我们只需要取一个值时,远不如find()方法方便。但是如果未搜索到值时,将返回一个None。


第5节 BeautifulSoup CSS选择器

BeautifulSoup支持发部分的CSS选择器,在Tag获取BeautifulSoup对象的.select()方法中传入字符串参数,即可使用CSS选择器的语法找到Tag,返回类型是 list

  1. 通过标签名查找:标签名
  2. 通过类名查找:.类名
  3. 通过id查找:#id值
  4. 组合查找:多个查找条件组合
  5. 属性查找:标签名[属性名 = ‘属性值’]
  6. 直接子标签查找:父标签名 > 子标签名
  7. 兄弟节点标签查找:标签名 ~ 标签名
  8. 获取内容:.get_text()

1. 通过标签名查找

 

a_list = bs.select("a") print(a_list)

[<a href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>, <a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>, <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>, <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>, <a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>, <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>]

2. 通过类名查找

 

a_list = bs.select('.mnav') print(a_list)

[<a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>, <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>, <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>, <a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>]

3. 通过id查找

 

a_list = bs.select('#wrapper') print(a_list)

[<div id="wrapper">
<div id="head">
<div class="head_wrapper">
<div id="u1">
<a href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>
<a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>
<a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>
<a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>
<a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>
<a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>
</div>
</div>
</div>
</div>]

4. 组合查找

 

a_list = bs.select('div .mnav') print(a_list)

[<a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>, <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>, <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>, <a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>]

5. 属性查找

 

a_list = bs.select('div[id="head"]') print(a_list)

[<div id="head">
<div class="head_wrapper">
<div id="u1">
<a href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>
<a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>
<a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>
<a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>
<a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>
<a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>
</div>
</div>
</div>]

6. 直接子标签查找

 

a_list = bs.select('div > a') print(a_list)

[<a href="http://news.baidu.com" name="tj_trnews"><!-- 新闻 --></a>, <a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>, <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>, <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>, <a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>, <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>]

7. 兄弟节点标签查找

 

a_list = bs.select('a ~ a') print(a_list)

[<a class="mnav" href="https://www.hao123.com" name="tj_trhao123">hao123 </a>, <a class="mnav" href="http://map.baidu.com" name="tj_trmap">地图 </a>, <a class="mnav" href="http://v.baidu.com" name="tj_trvideo">视频 </a>, <a class="mnav" href="http://tieba.baidu.com" name="tj_trtieba">贴吧 </a>, <a class="bri" href="//www.baidu.com/more/" name="tj_briicon" style="display: block;">更多产品 </a>]

8. 获取内容

 

a_list = bs.select('a') for i in a_list: print(i.get_text())

hao123 
地图 
视频 
贴吧 
更多产品 

开始实验

第6节 附录

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

撸码的xiao摩羯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值