Pyton爬虫编程入门学习笔记(八)学习正则表达式

文章目录

    • 一、Python正则表达式
      • 1.re.match()函数
      • 2.常用正则表达式用法
      • 3.re.search()函数
      • 4.re.findall()函数
      • 5.re.sub()函数
      • 6.compile()函数
    • 二、课堂练习
      • 爬取古诗文网推荐页面诗文
    • 三、正则表达式实战练习:爬取古诗文网站唐诗三百首

一、Python正则表达式

正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。
Python 自1.5版本起增加了re 模块,它提供 Perl 风格的正则表达式模式。
re 模块使 Python 语言拥有全部的正则表达式功能。
compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。 >re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。(引用出处:菜鸟教程–正则表达式)

  • 主要学习Python中常用的正则表达式处理函数。

1.re.match()函数

使用re.match()函数,必须导入re模块:从第一个字符开始匹配,且只返回一个匹配成功的字符串,不是第一个字符则失败。

  • 函数语法:
import re
re.match(pattern, string, flags=0)
  • 参数说明:
参数 说明
pattern 编写的正则表达式字符串
string 要去匹配正则表达式的原始字符串或请求回来的网页源代码
flags 标志位,用于控制正则表达式的匹配方式,如:re.S,re.I,re.DOTALL等

如果匹配成功,match()返回一个匹配对象,否则返回None。可以使用group(num=0)来获取匹配成功的字符串。

2.常用正则表达式用法

  • 匹配某个字符串:
import re

text = 'hello world'
ret = re.match('he', text)
ret = re.match('world',text)    # None
print(ret.group())    # he
  • 点".",匹配任意的字符
text = 'hello'
ret = re.match('.', text)
print(ret.group())  # h
  • \d:匹配任意的数字(0-9)
# text = '9'
# ret = re.match('\d', text)
# print(ret.group())
  • \D:匹配任意的非数字
text = '9'
ret = re.match('\D', text)
print(ret.group())  # 'NoneType' object has no attribute 'group'
  • \s:匹配任意空白字符(\n, \t, \r, 空格)\S:匹配非空白字符
text = '\r'
ret = re.match('\D', text)
print(ret.group())
  • \w:匹配a-z,A-Z,0-9,数字和_下划线;\W:与\w正好相反
text = 'hello'
ret = re.match('\w', text)
print(ret.group()) 
  • []组合方式,只要满足中括号中的字符,就能匹配
text = 'a1234'
ret = re.match('[a1]', text)
print(ret.group())
  • 配合通配符,能匹配多个字符,如"+,*,?"

  • 匹配电话号码:

text = '0731-88888888aaaa'
ret = re.match('[\d\-]+', text)
print(ret.group())  # 0731-88888888
  • 使用[0-9]代替\d:
text = '0731-88888888aaaa'
ret = re.match('[0-9\-]+', text)
print(ret.group())  # 0731-88888888
  • 使用[0-9a-zA-Z_]代替\w:
text = '0731-88888888aaaa'
ret = re.match('[0-9a-zA-Z_\-]+', text)
print(ret.group())  # 0731-88888888aaaa
  • “*” 号匹配0或任意多个字符
text = 'abcd'
ret = re.match('\w*', text)
print(ret.group())  # abcd
  • “+”号匹配至少1个或多个字符,必须要有一个能匹配成功,否则失败
text = 'ab+cd'
ret = re.match('\w+', text)
print(ret.group())  # ab
  • ”?“号匹配0个或1个(要么没有,要么只有一个)
text = 'abcd'
ret = re.match('\w?', text)
print(ret.group())  # 只返回"a"
  • {m}:匹配m个字符
text = 'abcd'
ret = re.match('\w{3}', text)
print(ret.group())  # 只返回"abc"
  • {m,n}:匹配m-n个字符:
text = 'abcdefghijk'
ret = re.match('\w{1,5}', text)
print(ret.group())  # 只返回"abcde"
  • 验证手机号码
text = '13377005111'
ret = re.match('1[3456789]\d{9}', text)
print(ret)
  • 验证邮箱
text = '[email protected] hjm'
ret = re.match('\w*@[a-z0-9]*\.[a-z]*', text)
print(ret, ret)
  • 验证URL
text = 'http://www.baidu.com/'
ret = re.match('(http|https|ftp):[^\s]+', text)
print(ret)
  • 验证身份证号码
text = '45233019750101001X'
ret = re.match('\d{17}[0xX]', text)
print(ret)
  • ”^“(脱字号):表示以…开始,在中括号中表示取反
text = 'hello'
ret = re.match('^h', text)
print(ret)

* ”$“:表示以...结尾
```python
text = '[email protected]'
ret = re.match('\w+@163\.com$', text)
print(ret)
  • ”|“:匹配多个字符串或者表达式,用()界定
text = 'https'
ret = re.match('(ftp|http|https)$', text)
print(ret)
  • 贪婪模式与非贪婪模式
text = '

Title

'
ret = re.match('<.*>', text) # 贪婪模式 ret1 = re.match('<.*?>', text) # 非贪婪模式 print(ret) print(ret1)
  • ”\“:转义符
text = 'Apple price is $299'
ret = re.search('\$\d+', text)
print(ret)
  • ”\n\t\r“:原生字符转义
text = r'\c'
ret = re.match(r'\\c', text)
print(ret.group())
  • group()分组
text = "apple's price $299,orange's price $10"
ret = re.search('.*(\$\d+).*(\$\d+)', text)
print(ret.group())
print(ret.group(1))
print(ret.group(2))
print(ret.group(1, 2))
print(ret.groups())
  • 小案例:匹配0-100之间的数
text = '98'
ret = re.match('([1-9]\d?$|100$)', text)
print(ret)

3.re.search()函数

re.search()函数扫描整个字符串并返回第一个成功的匹配。

函数语法:

re.search(pattern, string, flags=0)

re.match()与re.search()的区别:
re.match()只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None,而 re.search()匹配整个字符串,直到找到一个匹配。如:

text = 'hello world'
ret = re.match('hello', text)   # hello
ret = re.match('world', text)    # None 不是第一个,匹配失败
ret = re.search('world', text)  # world
print(ret.group())

4.re.findall()函数

re.findall()函数,在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表

  • 注意: re.match()和re.search()是匹配一次,re.findall()匹配所有。

  • 函数语法:

re.findall(string[, pos[, endpos]])

参数:

参数 说明
string 待匹配的字符串
pos 可选参数,指定字符串的起始位置,默认为 0
endpos 可选参数,指定字符串的结束位置,默认为字符串的长度
  • 查找所有的价格
text = "apple's price $299,orange's price $10"
rets = re.findall('\$\d+', text) # 返回列表
print(rets)

5.re.sub()函数

re.sub()用于替换字符串中的匹配项,经常用来替换提取出来的标签,如:”
床前明月光\n“。返回的是字符串。

  • 函数语法:
re.sub(pattern, repl, string, count=0, flags=0)

参数:

参数 说明
pattern 正则中的模式字符串
repl 替换的字符串,也可为一个函数(或lambda表达式)
string 要被查找替换的原始字符串
count 模式匹配后替换的最大次数,默认0表示替换所有的匹配
flags 编译时用的匹配模式,数字形式
  • 示例,将价格全部置为0:
text = "apple's price $299,orange's price $10"
ret = re.sub('\d+', '0', text)
print(ret)
  • 查找网页文本内容sub()、split()分割(返回列表):
html = '''

职位描述:
负责各类银行业务系统的设计、开发(JAVA方向)及团队管理工作。

应聘条件: 
1、全日制大学本科及以上学历,计算机相关专业(应聘者需获得全日制统招本科毕业证、学位证); 
2、精通Java语言,J2EE架构及重用轻量级开源架构,精通面向对象系统架构设计,并熟悉一种以上数据库; 
3、1年以上开发工作经验,并参与过大型JAVA项目的设计、开发工作,具备项目管理或开发团队管理经验者优先; 
4、具备良好的沟通力、表达力、团队协作力以及责任心; 
5、熟悉金融或者企业财务相关的业务,有参与金融系统开发经验者优先。

'''
# ret = re.sub('<.*?>', '', html) r_list = re.split('<.*?>', html) print(ret) print(r_list)

6.compile()函数

用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search()、findall()函数使用。

函数语法:

re.compile(pattern[, flags])

参数:

参数 说明
pattern 一个字符串形式的正则表达式
flags 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
re.I 忽略大小写
re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
re.M 多行模式
re.S 即为’ . ‘并且包括换行符在内的任意字符(’ . '不包括换行符)
re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
re.X/re.VERBOSE 为了增加可读性,忽略空格和’ # '后面的注释

示例:

text = 'the number is 20.50'
# r = re.compile('\d+\.\d+')
r = re.compile(r'''
                \d+ # 小数点前面的数字
                \.  # 小数点本身
                \d+ # 小数点后面的数字
                ''',re.VERBOSE)
ret = re.search(r, text)
print(ret.group())

二、课堂练习

爬取古诗文网推荐页面诗文

# -*- coding: utf-8 -*-
'''正则表达式学习'''

import re, requests, json
import pandas as pd


def parse_page(url):
    headers = {
        'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'
    }
    resp = requests.get(url, headers=headers)
    html = resp.text
    # 初学正则表达式,分段获取所需信息不易出错
    # 获取诗词标题
    titles = re.findall('(.*?)', html, re.S)
    # 获取作者
    authors = re.findall('

.*?(.*?).*?(.*?)', html, re.S) # 获取诗词正文 content_tags = re.findall('

(.*?)
'
, html, re.S) contents = [] for i in range(len(content_tags)): x = re.sub('<.*?>', '', content_tags[i]) contents.append(x.split()) poems = [] for value in zip(titles, authors, contents): title, author, content = value poem = { 'title': title, 'author': author, 'content': content } poems.append(poem) print(poems) print('-'*40) def main(): for i in range(1, 11): url = 'https://www.gushiwen.org/default_%s.aspx' % i poems = parse_page(url) if __name__ == '__main__': main()

三、正则表达式实战练习:爬取古诗文网站唐诗三百首

  • 代码如下:
# -*- conding: utf-8 -*-

"""
实战:爬取古诗文网唐诗三百首,学习使用正则表达式解析提取网页
1.使用浏览器开发者工具,从唐诗三百首全集页面'https://so.gushiwen.org/gushi/tangshi.aspx'
获取每首诗的网址包含id的后半部分,从而整合得到完整网址。
2.进入新页面使用正则表达式获取唐诗的诗句、作者、诗句、译注。
3.使用pandas将数据保存到CSV文件中。
说明:古诗文网站属于静态html,比较简单,练习正则表达式正合适
"""

import requests, re, time, random
import pandas as pd

headers = {
    'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'
}


def get_poem(poem_url):
    """获取每首唐诗标题、作者、正文等信息"""
    resp = requests.get(poem_url, headers=headers)
    resp.encoding = 'utf-8'
    text = resp.text
    # 获取唐诗标题,全为唐诗,作者都是唐朝的,故不再提取朝代
    title = re.findall('h1 style.*?>(.*?)', text, re.S)[0]
    # 获取作者姓名,后面列有1-3首其他作者的诗,所以只取第一位
    author = re.findall(
        '

.*?(.*?)', text, re.S)[0] # 获取诗句正文 content = re.findall( '

(.*?)
'
, text, re.S)[0] content = re.sub('\s', '', re.sub('
'
, '', content)) # 清除标签、空白符 # 获取诗文翻译、注释 target_texts = re.findall('

.*?(.*?)

'
, text, re.S) for i in range(len(target_texts)): # 清除标签、空白符 target_texts[i] = re.sub( '\s', '', re.sub('<.*?>', '', target_texts[i])) poem_info = { '诗名': title, '作者': author, '诗文': content, '译注': target_texts } # print(poem_info) return poem_info def get_url(base_url, tangshi_url): """获取每首唐诗的url""" resp = requests.get(tangshi_url, headers=headers) resp.encoding = 'utf-8' r = re.compile('', re.S) poem_urls = re.findall(r, resp.text) # 获取诗文id后半部分地址 for i in range(len(poem_urls)): poem_urls[i] = base_url + poem_urls[i] # 合成完整url # print(poem_urls[0:4]) return poem_urls def save_poems(poem_infos): """保存数据""" df = pd.DataFrame(poem_infos, columns=['诗名', '作者', '诗文', '译注']) print(df) df.to_csv('tangshi300.csv') def main(): """主运行函数""" base_url = 'https://so.gushiwen.org/' # 整合每首诗的网址用基址 tangshi_url = 'https://so.gushiwen.org/gushi/tangshi.aspx' poem_urls = get_url(base_url, tangshi_url) poem_infos = [] i = 1 for poem_url in poem_urls: poem_infos.append(get_poem(poem_url)) print('', end='') # 大佬说要多加这行,没整明白 time.sleep(random.randint(1, 8)) # 随机休息一会,缓解服务器压力 # 不换行在同一行显示进度,”\r“表示回到行首覆盖输出 print('\r' + '数据采集完成进度--> %.2f%%' % (i / len(poem_urls) * 100), end='') i += 1 save_poems(poem_infos) if __name__ == "__main__": main()

你可能感兴趣的:(Pyton爬虫编程入门学习笔记(八)学习正则表达式)