3.4 Beautiful Soup 库和正则表达式
如前所述,除了 Lxml 库,网页信息的提取还有另外两种常用工具 - Beautiful Soup 和正则表达式。由于 Lxml 库的功能基本可以满足提取信息的需求,提取效率高,学习成本低,使用也非常方便,因此这一节只对 Beautiful Soup 和正则表达式做简单介绍,读者以后在遇到这方面问题时,可以查询其他文档。其实读者完全可以跳过这一节,直接学习下一章的内容。
3.4.1 Beautiful Soup 简介
Beautiful Soup 是一个灵活又方便的网页解析 Python 库,处理效率较高,支持多种解析器,很多爬虫初学者都是从使用 Beautiful Soup 开始学习网页解析的。Beautiful Soup 不是 Python 标准库,需要安装。可以使用如下命令安装 Beautiful Soup。
>pip install beautifulsoup4
注意这里是 beautifulsoup4。安装完成后,需要在 Python 解释器中引入。
>>>from bs4 import BeautifulSoup
下面还是使用讲解 XPath 语法的 HTML 源码做例子。
htm=""" ...<div> ... <ul> ... <li class="item-0"><a href="link1.html">first item</a></li> ... <li class="item-1"><a href="link2.html">second item</a></li> ... <li class="item-inactive"><a href="link3.html">third item</a></li> ... <li class="item-1"><a href="link4.html">fourth item</a></li> ... <li class="item-0"><a href="link5.html">fifth item</a></li> ... <li class="else-0">else item</li> another item ... </ul> ...</div> ..."""
首先将定义的 htm 传入 Beautiful Soup 的构造方法,得到一个文档对象 soup。
>>>soup = BeautifulSoup(htm, 'lxml')
Beautiful Soup 的构造方法的第一个参数是要解析的 HTML 文档,第二个参数是 Beautiful Soup 的解析器。Beautiful Soup 支持 Python 标准库中的 HTML 解析器、Lxml 解析器,还支持一些其他第三方解析器,如果不安装这些第三方的解析器,Beautiful Soup 会使用 Python 默认的解析器。Lxml 解析器更加强大,速度更快,推荐读者安装使用。上面的构造方法就使用了 Lxml 解析器。
3.4.2 Beautiful Soup 基本用法
使用 soup.x(x 代表标签名)这种形式可以获得标签的内容,如图 3-6 所示。
图 3-6 使用 soup.ul 获得标签内容
>>>print(soup.ul)
图 3-6 中打印出了<ul>标签的全部内容。如果文档中有多个同样的标签,返回的结果是第一个标签的内容,示例如下。
>>>print(soup.li) <li class="item-0"><a href="link1.html">first item</a></li>
在标签后面加上.string,就可获取标签内的文本,例如加上.string 获取第一个<a>标签的文本内容。
>>>print(soup.a.string) first item
当然也可以通过嵌套的方式获取。
>>>print(soup.ul.li.a.string) first item
可以使用“标签[属性]”这种形式来获取属性值,如编写如下代码获取第一个<a>标签的 href 属性。
>>>print(soup.ul.li.a['href']) link1.html
也可以使用 GET 方法获取属性。
>>>print(soup.ul.li.a.get('href')) link1.html
可以使用.contents 形式将所有子标签存入一个列表中,如图 3-7 所示。
图 3-7 将所有子标签存入一个列表中
这样打印出的是一个列表。如果使用 soup.ul.children,得到的内容与 soup.ul.contents 完全相同,但它是一个迭代器的形式。
3.4.3 Beautiful Soup 标准选择器
1. find_all 方法
find_all 方法搜索当前标签的所有子节点,并判断是否符合过滤器的条件。find_all 方法是 Beautiful Soup 最常用的方法。
例如,要获取所有的<a>标签,应编写如下代码。
>>>all_a = soup.find_all('a') #find_all 也可简写为 soup(a)
获取第二个<a>标签的文本信息,应编写如下代码。
>>>a2_text = soup.find_all('a')[1].string
注意列表的切片是从 0 开始的。也可以使用属性定位第二个<a>标签。
>>>a2_text = soup.find_all(attrs={'href':"link2.html"})[0]. st ring second item
上面使用了 attrs 参数定义一个字典参数,以搜索包含特殊属性的标签。也可以选择所有 class 属性等于 item-1 的标签,然后取出第一个。
>>>a2_text = soup.find_all(class_='item-1')[0].string >>>print(a2_text) second item
这里要注意,class_是带有下画线的,因为 class 是 Python 的语法关键词,如果没有下画线,会出现语法错误。Beautiful Soup 也可按 id 搜索:如果包含一个名字为 id 的参数,搜索时会把该参数当作指定名字标签的属性来搜索。
>>>soup.find_all(id='xxx')
图 3-8 中的例子查找所有包含 class 属性的标签,无论 class 属性的值是什么,这个方法同样可以应用在其他属性上。
图 3-8 查找所有包含 class 属性的标签
2. get_text()
如果只想得到标签中包含的文本内容,可以用 get_text() 方法,这个方法获取到标签中包含的所有文本内容(包括子孙节点中的文本内容),并将结果字符串返回,如图 3-9 所示。
图 3-9 获取标签中包含的所有文本内容
这样就提取了<ul>下(包括子孙节点)的全部文本内容。读者可以与 XPath 使用 string() 这种提取方法的结果对比,看看是否相同。
3.4.4 正则表达式
正则表达式是用于处理字符串的强大工具,其他编程语言中也有正则表达式的概念,区别只在于不同的编程语言实现支持的语法数量不同。正则表达式拥有自己独特的语法及一个独立的处理引擎,在提供了正则表达式的语言里,正则表达式的语法都是一样的。正则表达式无论是编写还是阅读,都相对复杂,这里只做简单的入门介绍。
Python 标准库中的 re 模块提供正则表达式的全部功能,可以直接引入。
>>>import re
使用 re 的一般步骤如下。
第一步将正则表达式的字符串形式编译为 Pattern 实例。
第二步正则表达式处理函数使用 Pattern 实例处理文本并获得匹配结果。
下面首先介绍 Python 中常用的正则表达式处理函数,然后给出构造正则表达式 Pattern 的语法规则。
1. 常用的正则表达式处理函数
(1)re.match 函数
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功,re.match 就返回 None。
以下为 re.match 函数的语法。
re.match(pattern, string[, flags])
这里 pattern 代表匹配的正则表达式;string 是要匹配的字符串;flags 是可选参数,用于指定匹配模式。
(2)re.search 方法
re.search 扫描整个字符串并返回第一个成功的匹配。以下为 re.search 函数的语法。
re.search(pattern, string[, flags])
这里 pattern、string 和 flags 的含义同 re.match。
(3)re.split
re.split 按照能够匹配的子串将 string 分割后返回列表。以下为 re.split 函数的语法。
re.split(pattern, string[, maxsplit])
maxsplit 用于指定最大分割次数,不指定时将全部分割。
(4)re.findall
re.findall 以列表形式返回全部能匹配的子串。以下为 re.findall 函数的语法。
re.findall(pattern, string[, flags])
(5)re.sub
re.sub 用于替换每一个匹配的子串并返回替换后的字符串。以下为 re.sub 函数的语法。
re.sub(pattern, repl, string[, count])
re.sub 使用 repl 替换 string 匹配的部分,count 用于指定最多替换次数,不指定时将全部替换。
2. 正则表达式 Pattern 的语法规则
前面简单介绍了正则表达式的处理函数,现在来看 Python 正则表达式的构造语法,也就是前面介绍的函数中 pattern 的写法。
Python 正则表达式的基本语法规则就是指定一个字符序列,如要在一个字符串 s='123abc456eabc789'中查找字符串'abc',可以这样编写如下代码。
>>>import re >>>text = '123abc456eabc789' >>>re.findall(r'abc', text)
上述代码返回结果如下。
['abc', 'abc']
代码中 r'abc'是模式字符串,模式字符串使用特殊的语法来表示一个正则表达式。
(1)字母和数字表示它们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
(2)多数字母和数字前加一个反斜杠时会有不同的含义。
(3)标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。一般使用反斜杠转义。
(4)反斜杠本身需要使用反斜杠转义。
(5)模式元素(如 r'\t'等价于 '\\t')匹配相应的特殊字符。
表 3-1 列出了正则表达式模式语法中的部分特殊元素。
表 3-1 正则表达式模式语法中的部分特殊元素
最后看一下 re.compile 方法。这个方法是 Pattern 类的工厂方法,用于将正则表达式 pattern 编译为正则表达式对象,当单个程序中的表达式被多次使用时,使用 re.compile() 和保存生成的正则表达式对象进行重用会更有效率。下面是一个例子。
>>>import re >>>text = '123abc456eabc789' >>>pat = re.compile('\d+') #编译正则表达式对象 >>>re.findall(pat, text) ['123', '456', '789']
首先使用 re.compile 编译了匹配模式\d+,根据表 3-1,\d 表示匹配任意数字,后面跟上 + 代表匹配一次或多次,这样使用 re.findall 就把文本中的数字全部提取出来了。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论