
「网页解析与信息提取」BeautifulSoup库、Re库的使用
¶基于BeautifulSoup库解析HTML页面
BeautifulSoup库,是用于解析、遍历、维护“标签树” 的功能库
约定的引用方式:
1 | |
每一个 BeautifulSoup 类,对应一个HTML/XML的全部内容
¶Beautiful Soup库解析器
获取 BeautifulSoup 类的方式(重点在下方代码第三行):
1 | |
在构造方法中,除了
html.parser,还可以传入其他的解析器如:lxml的HTML解析器、lxml的XML解析器(需要额外安装)
HTML格式化打印:bs.prettify()
¶Tag类(标签)
bs4.element.Tag 类,对应于HTML/XML的标签,是最基本的信息组织单元,用 <> 和 </> 标明开头和结尾的。
获取方式:
1 | |
任何存在于HTML语法中的标签,均可通过BeautifulSoup 类 进行访问,即bs.<tag>。
当HTML文档存在多个相同的
<tag>时,优先返回第一个

¶Tag.name(标签名称)
每个标签的名称字符串,可通过 <tag>.name 获取
1 | |
¶Tag.attrs(标签属性)
每个标签的属性,如 class、href等,可通过 <tag>.attrs,返回的是字典类型
1 | |
¶Tag.String
<tag>.string 获取的是标签内非属性字符串
要点:
注释的文本,返回的是
bs4.element.Comment;否则,返回的是bs4.element.NavigableString:1
2
3
4<!--示例1:bs.a.string为"我是注释"-->
<a href=""><!--我是注释--></a>
<!--示例2:bs.a.string为"2222"-->
<a href="">222</a>如果指定的
<tag>含有多个同级标签(包括注释标签),或者含有更深的层级标签,则.string返回为None。1
2
3
4
5
6
7
8
9
10
11
12<!--示例1:bs.p.string为None-->
<p>
111
<a href=""><!--我是注释--></a>
<span>333</span>
</p>
<!--示例2:bs.a.string为None-->
<a href="">我是正文<!--我是注释--></a>
<!--示例3:bs.article.string为None-->
<article>
<a href="">你</a>
</article>
¶HTML内容遍历

BeautifulSoup 类,是标签树的根节点。
¶标签树的下行遍历
.contents:子节点的列表,即将<tag>所有儿子节点存入列表,元素类型是NavigableString、Tag等类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19bs.body.contents
'''注意到,每一儿子节点作为列表中的一个元素
['\n',
<article>
<a href="">222</a>
<a href=""><!--我是注释--></a>
</article>,
'\n',
<div id="wrapper"><div id="head"><div class="head_wrapper"><div id="u1"><a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!--新闻1--></a>
<a class="mnav" href="http://news.baidu.com" name="tj_trnews">新闻</a></div></div></div></div>,
'\n']
'''
bs.body.contents[1]
'''
<article>
<a href="">222</a>
<a href=""><!--我是注释--></a>
</article>
'''.children:子节点的迭代类型,用于循环遍历儿子节点1
2for child in bs.body.children:
print(child).descendants:子孙节点的迭代类型,包含所有子孙节点(结果类似于DFS),同样用于循环遍历1
2for child in bs.body.descendants:
print(child)
¶标签树的上行遍历
.parent:节点的父亲标签.parents:节点先辈标签的迭代类型,用于循环遍历先辈节点1
2
3
4
5for parent in bs.a.parents:
if parent is None:
print(parent)
else:
print(parent.name)1
2
3
4article
body
html
[document]
¶标签树的平行遍历
以下操作均按照原HTML的文本顺序,并且只能遍历同一个父节点下的各节点间
.next_sibling:下一个平行节点标签.previous_sibling:上一个平行节点标签.next_siblings:迭代类型,返回后续所有平行节点标签.previous_siblings:同上相反的方向
¶HTML内容查找
<>.select():类似于CSS选择器,返回的结果为列表。如下:
1 | |
<>.find_all(name, attrs, recursive, string, **kwargs):查找与字符串完全匹配的内容,并存放到列表类型
name:按标签名称进行检索,如:1
2
3
4bs.find_all('a')
bs.find_all(['a', 'b'])
bs.find_all(re.compile('b')) # 支持正则表达式,返回 body、b 等标签
bs.find_all('a', limit=3) # 结果最多只取limit个元素attrs:按标签属性值进行检索1
2
3
4
5
6
7
8
9
10
11
12bs.find_all('a', 'mnav')
'''
[<a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!--新闻1--></a>, <a class="mnav" href="http://news.baidu.com" name="tj_trnews">新闻</a>]
'''
bs.find_all(id='u1')
'''
[<div id="u1">
<a class="mnav" href="http://news.baidu.com" name="tj_trnews"><!--新闻1--></a>
<a class="mnav" href="http://news.baidu.com" name="tj_trnews">新闻</a>
</div>]
'''
bs.find_all(id=re.compile('link'))recursive:是否对子孙全部检索,默认为Truestring:按<>...</>中字符串区域进行检索1
2bs.find_all(string='新闻')
bs.find_all(string=re.compile('产品'))
¶基于Re(正则表达式)库提取页面关键信息
引入方式:
1 | |
¶常用操作符
| 操作符 | 说明 | 实例 |
|---|---|---|
. | 任何单个字符 | |
[] | 对单个字符给出取值范围(字符集) | [abc] 表示a,b,c,[a-z] 表示 a 到 z 单个字符 |
[^ ] | 对单个字符给出排除范围 | |
* | 前一个字符任意次拓展(0次或无限次) | abc* 表示:ab,abc,abcc,abccccc等 |
+ | 前一个字符至少拓展1次(>=1) | abc+ 表示:abc,abcccc等 |
? | 前一个字符要么拓展0次,要么拓展1次 | abc? 表示:ab,abc |
| ` | ` | 左右表达式任意一个 |
{m} | 前一个字符拓展m次 | ab{2}c 表示:abbc |
{m,n} | 前一个字符拓展[m, n]次 | ab{1,2}c 表示:abc,abbc |
^ | 匹配字符串开头 | ^abc 表示 abc 且在一个字符串开头 |
$ | 匹配字符串结尾 | abc$ 表示abc 且在一个字符串的结尾 |
() | 分组标记,内部只能用 ` | ` |
\d | 匹配数字,等价于 [0-9] | |
\w | 匹配字母、数字、下划线,等价于[A-Za-z0-9_] |
语法实例:
| 正则表达式 | 对应字符串 |
|---|---|
| `P(Y | YT |
PYTHON+ | ‘PYTHON’、‘PYTHONN’、‘PYTHONNN’ … |
PY[TH]ON | ‘PYTON’、‘PYHON’ |
PY[^TH]?ON | ‘PYON’、‘PYaON’、‘PYbON’、‘PYcON’… |
PY{:3}N | ‘PN’、‘PYN’、‘PYYN’、‘PYYYN’ |
匹配IP地址的正则表达式:
满足0-99:[1-9]?\d;又满足100-199:1\d{2};又满足200-249:2[0-4]\d;又满足250-255:25[0-5],故精确的写法如下:
(([1‐9]?\d|1\d{2}|2[0‐4]\d|25[0‐5]).){3}([1‐9]?\d|1\d{2}|2[0‐4]\d|25[0‐5])
¶表示类型
re 库建议采用 raw string 类型(不包含对转义符再次转义的字符串)表示正则表达式,即 r'text',如 r'[1-9]\d{5}',r'\d{3}-\d{8}|\d{4}-\d{7}'
¶具体用法
有 re.search() 、re.match() 等方法:
1 | |
以下方法均可用上述的面向对象方法,即将正则表达式编译至正则表达式对象后,再调用。
但更加常用匹配方法为:re.findall(pattern, string, flags=0),搜索字符串,以列表类型返回全部能匹配的子串。其中,pattern:正则表达式的字符串;string:待匹配字符串;flags:正则表达式使用时的控制标记
注意区分 bs4 的
find_all()用于找到所在标签及内容,findall()匹配具体字符串另外,re库默认采用贪婪匹配,即输出匹配最长的子串
1 | |
匹配并替换的方法:re.sub(pattern, repl, string, count=0, flags=0),其中,pattern :正则表达式的字符串,repl:替换匹配字符串的字符串,string:待匹配字符串,count:匹配的最大替换次数
1 | |