使用正则表达式解析网页是Python的一个擅长的领域。如果还想更加深入地学习正则表达式,或者在平时经常用到正则表达式,可以进入Regular Expression 101网站学习,网站地址为 https://regex101.com/ 。

接下来会讲解爬虫抓取网页后,Python如何用正则表达式进行网页解析。

beautifulsoup网页爬虫解析_Python爬虫3步曲:5分钟学习用Python解析网页-编程知识网

正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的特定字符和这些特定字符的组合组成一个规则字符串,这个规则字符串用来表达对字符串的一种过滤逻辑。举一个简单的例子,假设字符串为'我们爱吃苹果,也爱吃香蕉',我们需要提取其中的水果,用正则表达式匹配'爱吃'后面的内容就可以找到'苹果'和'香蕉'了。

为了利于我们改善优化接下来的内容贴合度,可以填写下您的Python掌握程度。

在提取网页中的数据时,我们可以先把源代码变成字符串,然后用正则表达式匹配想要的数据。刚刚接触正则表达式时可能会觉得晦涩难懂,但是使用正则表达式可以迅速地用极简单的方式达到字符串的复杂控制。

beautifulsoup网页爬虫解析_Python爬虫3步曲:5分钟学习用Python解析网页-编程知识网

表5-1是常见的正则字符和含义。如果想了解更为详细的正则表达式文档,可以访问: https://docs.python.org/3/library/re.html 。

表5-1 常见的正则字符和含义

beautifulsoup网页爬虫解析_Python爬虫3步曲:5分钟学习用Python解析网页-编程知识网

首先,我们介绍Python正则表达式的3种方法,分别是re.match、re.search和re.findall。

 re.match方法

re.match的意思是从字符串起始位置匹配一个模式,如果从起始位置匹配不了,match()就返回none。

re.match的语法为re.match(pattern,string,flags=0),其中pattern是正则表达式,包含一些特殊的字符,string为要匹配的字符串,flags用来控制正则表达式的匹配方式,如是否区分大小写、多行匹配等。

例如,我们想使用两个字符串匹配并找到匹配的位置,可以使用:


import rem = re.match('www', 'www.santostang.com')print ("匹配的结果: ", m) print ("匹配的起始与终点: ", m.span()) print ("匹配的起始位置: ", m.start())print ("匹配的终点位置: ", m.end())

得到的结果为:

匹配的结果: <_sre.sre_match object>

匹配的起始与终点: (0,3)

匹配的起始位置: 0

匹配的终点位置: 3

上述例子中的pattern只是一个字符串,我们也可以把pattern改成正则表达式,从而匹配具有一定模式的字符串,例如:


line = "Fat cats are smarter than dogs, is it right?"m = re.match( r'(.*) are (.*?) ', line)print ('匹配的整句话', m.group(0))print ('匹配的第一个结果', m.group(1))print ('匹配的第二个结果', m.group(2))print ('匹配的结果列表', m.groups())

得到的结果为:

匹配的整句话Fat cats are smarter

匹配的第一个结果Fat cats

匹配的第二个结果smarter

匹配的结果列表('Fat cats','smarter')

为什么这里(.*)匹配了Fat cat,而(.*?)只匹配了smarter呢?

这就涉及正则表达式匹配中默认的贪婪模式总是尝试匹配尽可能多的字符。在上述例子中,(.*)are会尽量匹配最多的字符,因此把Fat cat匹配了。非贪婪模式则相反,总是尝试匹配尽可能少的字符,are(.*?)会尽量匹配尽量少的字符,因此把smarter匹配了。

为什么要在match的模式前加上r呢?

r'(.*)are(.*?).*'前面的r意思是raw string,代表纯粹的字符串,使用它就不会对引号里面的反斜杠''进行特殊处理。要解释清楚,可以举个例子。例如:


print ('HelloWorldPython')

结果为:

HelloWorld

Python

可以看到里面的''已转义为换行符,但是'W'没有转义,这是因为'W'在字符串转义中没有对应特殊字符。如果现在需要不对''转义,原封不动输出'HelloWorldPython'呢?

第一种方法我们可以写成


print ('HelloWorldPython')

两个反斜杠的“字符串转义”会把""转义为""。

第二种方法是使用r'…',原始字符串的方法,不会对引号里面的反斜杠''进行特殊处理。


print (r'HelloWorldPython')

以上是字符串转义中raw string的用法,那么正则表达式的转义怎么用呢?


import re string = r'27' m = re.match('(d+)', string)print (m.group(1)) # 结果为:2n = re.match(r'(d+)', string) print (n.group(1)) # 结果为:2

首先需要知道的是,正则表达式字符串需要经过两次转义,这两次分别是上面的“字符串转义”和“正则转义”

正则表达式如果不用r'…'方法的话,就需要进行“字符串转义”和“正则转义”。在上述案例中,需要匹配r'27'中的字符"",使用编程语言表示的正则表达式里就需要4个反斜杠"":前两个反斜杠""和后两个反斜杠""各自在字符串转义成一个反斜杠"/",所以4个反斜杠""就转义成了两个反斜"",这两个反斜杠""最终在正则表达式转义成一个反斜杠""。

如果使用r'…'方法的话,不用进行字符串转义,直接进入第二步“正则转义”,在正则转义中""被转义为了"",这个例子中可以使用r""表示。

5.1.2 re.search方法

re.match只能从字符串的起始位置进行匹配,而re.search扫描整个字符串并返回第一个成功的匹配,例如:


import rem_match = re.match('com', 'www.santostang.com')m_search = re.search('com', 'www.santostang.com')print (m_match)print (m_search)

得到结果为:

None

其他方面re.search与re.match一样,可以参照上面的re.match来操作。

re.findall方法

上述match和search方法中,我们只能找到一个匹配所写的模式,而findall可以找到所有的匹配,例如:


import rem_match = re.match('[0-9]+', '12345 is the first number, 23456 is the sencond')m_search = re.search('[0-9]+', 'The first number is 12345, 23456 is the sencond')m_findall = re.findall('[0-9]+', '12345 is the first number, 23456 is the sencond')print (m_match.group())print (m_search.group())print (m_findall)

上述代码的'[0-9]+'表示任意长度的数字,然后在后面的字符串中进行匹配。

运行上述代码,得到的结果是:

12345

12345

['12345','23456']

findall与match、search不同的是,findall能够找到所有匹配的结果,并且以列表的形式返回。当爬取博客文章的标题时,如果提取的不只是一个标题,而是所有标题,就可以用findall。

博客的文章标题部分的HTML代码如下:


Hello world!

07月04日 Python 网络爬虫 1条评论


抓取博客主页所有文章标题的Python代码如下:


import requestsimport relink = "http://www.santostang.com/"headers = {'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'} r = requests.get(link, headers= headers)html = r.texttitle_list = re.findall('

(.*?)

',html)print (title_list)


以上代码用于提取博客主页上所有文章的标题,这里使用findall匹配,使用'

(.*?)

'正则表示式表示对所有满足此条件的结果。带有括号,表示只提取其中的(.*?)部分。运行代码,得到的结果是:

['4.3通过selenium模拟浏览器抓取','4.2解析真实地址抓取','第四章-动态网页抓取(解析真实地址+selenium)','《网络爬虫:从入门到实践》一书勘误','Hello world!']

这样就把所有的标题提取出来了。

了解更多,请点击获取。