摘要
上一篇文章讲述了如何使用requests库简单爬取网页,在这一篇教学中,我将介绍正则表达式(Regex)在Python爬虫中的应用,并演示如何用正则表达式对上文爬取的baidu.html文件实现简单的内容解析。
1. 正则表达式基础
正则表达式可以由普通字符、元字符(特殊字符)、量词、边界匹配、分组与捕获、模式修饰符以及转义字符等不同类型的字符组合而成,由于这些需要介绍的内容过多并且网上相关介绍文章已经足够详细所以不过多描述,现在只对下面代码所用到的模式进行简单介绍。
模式 | 用法介绍 |
---|---|
. | 匹配任意单个字符(除换行符) |
.* | 匹配任意多个字符(除换行符) |
* | 匹配0个或多个表达式 |
? | 使前面的字符或子表达式匹配0次或1次,作为非贪婪模式修饰符 |
+ | 匹配1个或多个表达式 |
/d | 匹配数字 |
/s | 匹配空白字符 |
() | 提取匹配的子字符串 |
2. Python中的正则表达式模块
Python内置re
模块提供正则表达式支持。常用函数:
pattern
为填入的正则表达式
string
为需要处理的文本内容
re.search(pattern, string)
:搜索第一个匹配项。
re.findall(pattern, string)
:返回所有匹配项的列表。
re.match(pattern, string)
:从字符串开头匹配。
re.sub(pattern, repl, string)
:替换匹配项。
导入模块:import re
。本文仅对search
和findall
进行演示。
下面先来一个简单的正则表达式的应用并介绍贪婪和非贪婪的区别,开始前再补充一个re.S的用法,前面白色说了 .* 能匹配任意多个字符(除换行符),这个的作用就是使匹配内容包括换行符在内。
import re
content = "hello spider 123456"
result = re.search('hello.*(\d+)',content,re.S)
print(result.group())
print(result.group(1))
#这里的1代表输出正则表达式内第一个括号的内容即(\d+)里面所匹配的内容
下图是这份代码的输出
从第一行显而易见这份正则表达式匹配了content里面的所有内容,但由于.*默认采用贪婪方式所以会匹配到数字串的倒数第二位5,最终留给(\d+)匹配的只剩6了所以第二行输出的是6,接下来看看加了?的这份代码:
import re
content = "hello spider 123456"
result = re.search('hello.*?(\d+)',content,re.S)
print(result.group())
print(result.group(1))
下图是这份代码的输出
可以看到非贪婪的匹配最终使(\d+)的内容匹配到更多的数字串
注意:正则表达式不是万能工具,它适合处理简单、规则性强的文本,但对于复杂HTML(如嵌套标签)可能出错。
3. 用正则表达式解析HTML(search)
以下是我在baidu.html中随便截取的一段
'<meta name="description" content="全球领先的中文搜索引擎、致力于让网民更便捷地获取信息,找到所求。百度超过千亿的中文网页数据库,可以瞬间找到相关的搜索结果。">'
现在给出正则表达式
'<meta name="description"\scontent="(.*?)">'
#<meta name="description"这一部分是原文内容
#当然这个地方也可以写成'<meta\sname="description"
#\s在上文讲过是匹配空白字符
#content="(.*?)">主要是匹配content里面的内容用括号括起来可以使用group(1)输出
#>最后的这个不是特殊符号是html的>现在你就把它看成截至位置的字符也行
现在用完整的代码演示一遍
import re
content='<meta name="description" content="全球领先的中文搜索引擎、致力于让网民更便捷地获取信息,找到所求。百度超过千亿的中文网页数据库,可以瞬间找到相关的搜索结果。">'
result = re.search('<meta\sname="description"\scontent="(.*?)">',content,re.S)
print(result.group())
print(result.group(1))
下图是输出内容:
现在我们完成了使用search匹配字符串内容了,当然看完前面你会发现search只能匹配第一个符合要求的子串,所以接下来要使用findall在上一篇文章中保存的baidu.html进行匹配了
4.用正则表达式解析HTML(findall)
下面将使用findall来提取我们在baidu,html内所需要的文本内容了
首先我们可以在文件夹中用浏览器打开baidu.html然后找到自己感兴趣的部分写出正则表达式
我找的是左上角地图,贴吧,图片等这些东西,通过看源码可以发现他们大致有一个相同的规律就是前面<a href=
和后面target="_blank" class="mnav c-font-normal c-color-t">
这些内容是一样的,所以正则表达式就可以写出来了
'<a href=".*?" target="_blank" class="mnav c-font-normal c-color-t">\s*(.*?)\s*</a>'
#如果一直出问题可以把有空格的地方都改为/s*
下面是完整代码
with open('注意此处填写你自己baidu.html保存的位置','r',encoding='utf-8') as f:
html = f.read()
result = re.findall('<a href=".*?" target="_blank" class="mnav c-font-normal c-color-t">\s*(.*?)\s*</a>',html,re.S)
print(result)
下图是输出结果
findall返回的是列表,所以不要再用之前的gruop了嗷
到这里我们就完成了使用正则表达式对html进行简单的解析
小结
通过本文的学习我们了解到了如何使用正则表达式来提取html文件中我们需要的内容,然而在文章中也提到过正则表达式无法理解 HTML 的树形结构,多层标签匹配容易出错
所以有没有更好的方法来解析的,有的兄弟,像这样的解析方法还有好多,比如XPath,css选择器,相关的解析库比如lxml,Beautiful Soup等,下一章我们将着重讲解XPath的使用。