当前位置:   article > 正文

网页数据提取 -- 正则表达式_用正则表达式获取网页指定数据

用正则表达式获取网页指定数据

目录

1. 概述

2. 元字符

基础元字符:

重复元字符:

位置元字符:

其他元字符

转义符:

3. 常用正则表达式

4. re模块的方法

5. 正则进阶使用

.*?

模式修正符

6. 正则解析数据demo



1. 概述

Regular Expression,译作正则表达式或正规表示法,表示有规则的表达式,意思是说,描述一段文本排列规则的表达式。

正则表达式并不是Python的一部分。而是一套独立于编程语言,用于处理复杂文本信息的强大的高级文本操作工具。正则表达式拥有自己独特的规则语法以及一个独立的正则处理引擎,我们根据正则语法编写好规则(模式)以后,引擎不仅能够根据规则进行模糊文本查找,还可以进行模糊分割,替换等复杂的文本操作,能让开发者随心所欲地处理文本信息。正则引擎一般由编程语言提供操作,像python就提供了re模块或regex模块来调用正则处理引擎。

>

正则表达式在处理文本的效率上不如系统自带的字符串操作,但功能却比系统自带的要强大许多。

>

最早的正则表达式来源于Perl语言,后面其他的编程语言在提供正则表达式操作时基本沿用了Perl语言的正则语法,所以我们学习python的正则以后,也可以在java,php,go,javascript,sql等编程语言中使用。

>

★ 于爬虫而言,正则是最基础的一个数据解析工具

● 正则是基于对字符串或文本的处理:无非是分割、匹配、查找和替换。

● 正则在线测试工具  http://tool.chinaz.com/regex/

2. 元字符

元字符(Metacharacters),元字符是具有特殊含义的字符。

Python提供了处理正则表达式的模块有标准库的re模块和第三方模块regex。

导入`re`模块后,可以开始使用正则表达式了。

基础元字符:

元字符描述
.叫通配符、万能通配符或通配元字符,匹配1个除了换行符\n以外任何原子
[]匹配一个中括号中出现的任意原子
 [^原子]匹配一个没有在中括号出现的任意原子 ,字符取反/非

使用示例如下: 

  1. import re
  2. # 通配符:.也叫万能通配符或通配元字符,匹配1个除了换行符\n以外任何原子
  3. ret = re.findall(".", "a,b,c,d,e")
  4. ret1 = re.findall("a.b","a,b,c,d,e,acb,abb,a\nb,a\tb")
  5. print("ret:",ret)
  6. print("ret1:",ret1)
  7. print("*" * 40)
  8. #字符集:[] 匹配一个中括号中出现的任意原子
  9. ret3 = re.findall("[ace]", "a,b,c,d,e")
  10. ret4 = re.findall("a[ace]f", "af,abbf,acef,aef")
  11. print("ret3:",ret3)
  12. print("ret4:",ret4)
  13. ret5 = re.findall("[a-z]", "a,b,c,d,e") #提取所有小写字母
  14. ret6 = re.findall("[0-9]", "1,2,3,4,5") #提取所有数字
  15. ret7 = re.findall("[a-zA-Z]", "a,b,c,d,e,A,B,C") #提取所有小写和大写字母
  16. ret8 = re.findall("[a-z0-9A-Z]", "a,b,c,d,e,1,2,3,4,E,F,G") #提取所有大/小写字母+数字
  17. print("ret5:",ret5)
  18. print("ret6:",ret6)
  19. print("ret7:",ret7)
  20. print("ret8:",ret8)
  21. print("*" * 40)
  22. #\d取所有数字,,只能匹配一个符号
  23. ret9 = re.findall("\d", "a,b,c,d,e,1,2,3,4,E,F,G")
  24. print("ret9:",ret9)
  25. #\w取所字符,只能匹配一个符号
  26. ret10 = re.findall("\w", "a,b,c,d,e,1,2,3,4,E,F,G")
  27. print("ret10:",ret10)
  28. #字符集取反,不包含的意思:取不包含0-9的字符
  29. ret11 = re.findall("[^0-9]", "a,b,c,d,e,1,2,3,4,E,F,G")
  30. print("ret11:",ret11)
  31. #输出:
  32. ret: ['a', ',', 'b', ',', 'c', ',', 'd', ',', 'e']
  33. ret1: ['a,b', 'acb', 'abb', 'a\tb']
  34. ****************************************
  35. ret3: ['a', 'c', 'e']
  36. ret4: ['aef']
  37. ret5: ['a', 'b', 'c', 'd', 'e']
  38. ret6: ['1', '2', '3', '4', '5']
  39. ret7: ['a', 'b', 'c', 'd', 'e', 'A', 'B', 'C']
  40. ret8: ['a', 'b', 'c', 'd', 'e', '1', '2', '3', '4', 'E', 'F', 'G']
  41. ****************************************
  42. ret9: ['1', '2', '3', '4']
  43. ret10: ['a', 'b', 'c', 'd', 'e', '1', '2', '3', '4', 'E', 'F', 'G']
  44. ret11: ['a', ',', 'b', ',', 'c', ',', 'd', ',', 'e', ',', ',', ',', ',', ',', 'E', ',', 'F', ',', 'G']

重复元字符:

元字符描述
+叫加号贪婪符,指定左边原子出现1次或多次
 * 叫星号贪婪符,指定左边原子出现0次或多次 
?叫非贪婪符,指定左边原子出现0次或1次             
{n,m}叫数量范围贪婪符,指定左边原子的数量范围,有{n},{n, }, {,m}, {n,m}四种写法,其中n与m必须是非负整数。

代码示例如下:

  1. import re
  2. # 重复元字符: + * {} ?
  3. #取出所有完整的数字:
  4. ret = re.findall("\d", "a,b,234,D,6,888")
  5. print("ret:",ret) #结果是234/888都被拆分了
  6. # +:表示1~无穷次(默认贪婪),所以结果符合取出所有数字的预期
  7. ret1 = re.findall("\d+", "a,b,234,D,6,888")
  8. print("ret1:",ret1)
  9. print("*" * 50)
  10. '''
  11. ?的两个功能:
  12. 1、取消贪婪:只需要再+后面写一个?
  13. 2、表示:0次或1次
  14. '''
  15. ret2 = re.findall("\d+?", "a,b,234,D,6,888") #取消贪婪匹配(等同\d效果)
  16. print("ret2:",ret2)
  17. ret3 = re.findall("abc?","abc,abcc,abe,ab")
  18. print("ret3:",ret3)
  19. print("*" * 50)
  20. # *:表示0~多次
  21. ret4 = re.findall("\w+", "apple,banana,orange,melon")
  22. print("ret4:",ret4)
  23. ret5 = re.findall("\w?", "apple,banana,orange,melon") #等同\w
  24. print("ret5:",ret5)
  25. ret6 = re.findall("\w*", "apple,banana,orange,melon") #0次会包含空值
  26. print("ret6:",ret6)
  27. print("*" * 50)
  28. '''
  29. {m,n}:表示从多少次~多少次,固定区间
  30. 也可以单写一个数:取出6个字符的单词
  31. '''
  32. ret7 = re.findall("\w{6}?", "apple,banana,orange,melon")
  33. print("ret7:",ret7)
  34. ret8 = re.findall("\w{1,5}?", "abc,abcc")
  35. print("ret8:",ret8)
  36. #输出:
  37. ret: ['2', '3', '4', '6', '8', '8', '8']
  38. ret1: ['234', '6', '888']
  39. **************************************************
  40. ret2: ['2', '3', '4', '6', '8', '8', '8']
  41. ret3: ['abc', 'abc', 'ab', 'ab']
  42. **************************************************
  43. ret4: ['apple', 'banana', 'orange', 'melon']
  44. ret5: ['a', 'p', 'p', 'l', 'e', '', 'b', 'a', 'n', 'a', 'n', 'a', '', 'o', 'r', 'a', 'n', 'g', 'e', '', 'm', 'e', 'l', 'o', 'n', '']
  45. ret6: ['apple', '', 'banana', '', 'orange', '', 'melon', '']
  46. **************************************************
  47. ret7: ['banana', 'orange']
  48. ret8: ['a', 'b', 'c', 'a', 'b', 'c', 'c']

位置元字符:

元字符描述
^叫开始边界符或开始锚点符,匹配一行的开头位置 
 $叫结束边界符或结束锚点符,匹配一行的结束位置

代码示例如下:

  1. import re
  2. # 位置元字符: ^ $
  3. #取最开始的数字字符,第一个字符不是数字,则返回空列表
  4. ret = re.findall("^\d+", "34,banana,255,orange,65536")
  5. print("ret:",ret)
  6. #取末尾的字符
  7. ret1 = re.findall("\w+$", "peach,34,banana,255,orange,65536")
  8. print("ret1:",ret1)
  9. #举个栗子:取网页数据,前面规则定好,不论后面数字是多少都可以取到
  10. ret2 = re.findall("/goods/food/\d+","/goods/food/1003")
  11. print("ret2:",ret2)
  12. #只要符合"/goods/food/\d+"规则的,都可以取到
  13. ret3 = re.findall("/goods/food/\d+","server/app01/goods/food/1003")
  14. print("ret3:",ret3)
  15. #加开头和结尾,限制了完整性,返回空列表
  16. ret4 = re.findall("^/goods/food/\d+$","server/app01/goods/food/1003")
  17. print("ret4:",ret4)
  18. #输出:
  19. ret: ['34']
  20. ret1: ['65536']
  21. ret2: ['/goods/food/1003']
  22. ret3: ['/goods/food/1003']
  23. ret4: []

其他元字符

元字符描述
|指定原子或正则模式进行二选一或多选一 
()对原子或正则模式进行捕获提取、分组划分整体操作

代码示例如下:

  1. import re
  2. '''其他元素符:
  3. |:指定原子或正则模式进行二选一、或者多选一
  4. ():具备模式捕获的能力,也就是优先提取数据的能力,通过(?:) 可以取消模式捕获
  5. '''
  6. #提取5个字母组成的单词,不同方式对比:
  7. #筛选出5个字符的单词,前后带逗号
  8. ret = re.findall(",\w+,", ",apple,banana,peach,orange,melon,")
  9. print('ret:',ret)
  10. # 筛选出5个字符的单词,前后带逗号
  11. ret1 = re.findall(",\w{5},", ",apple,banana,peach,orange,melon,")
  12. print('ret1:',ret1)
  13. # 筛选出5个字符的单词,不带逗号,仅单词;最优方式
  14. ret2 = re.findall(",(\w{5}),", ",apple,banana,peach,orange,melon,")
  15. print('ret2:',ret2)
  16. #输出:
  17. ret: [',apple,', ',peach,', ',melon,']
  18. ret1: [',apple,', ',peach,', ',melon,']
  19. ret2: ['apple', 'peach', 'melon']
  20. #提取邮箱,不同方式对比:
  21. # 筛选出所有邮箱
  22. ret3 = re.findall("\w+@\w+\.com", "123abc@163.com,....234xyz@qq.com,....")
  23. print('ret3:',ret3)
  24. #筛选邮箱中的qq号
  25. ret4 = re.findall("(\w+)@qq\.com", "123abc@163.com,....234xyz@qq.com,....")
  26. print('ret4:',ret4)
  27. #筛选所有qq邮箱和163邮箱,最优
  28. ret5 = re.findall("(?:\w+)@(?:qq|163)\.com", "123abc@163.com,....234xyz@qq.com,....")
  29. print('ret5:',ret5)
  30. #输出:
  31. ret3: ['123abc@163.com', '234xyz@qq.com']
  32. ret4: ['234xyz']
  33. ret5: ['123abc@163.com', '234xyz@qq.com']

转义符:

● 转义符(/)的两个功能:

        1、将一些普通符号赋予特殊功能

        2、将特符号取消取特殊功能

● 加上不同的字母后,作用不同

汇总如下:

元字符描述
\d匹配一个数字原子,等价于`[0-9]
\D匹配一个非数字原子。等价于`[^0-9]`或`[^\d]
\w匹配一个包括下划线的单词原子。等价于`[A-Za-z0-9_]
\W  匹配任何非单词字符。等价于`[^A-Za-z0-9_]` 或 `[^\w]
\n 匹配一个换行符
\s 匹配一个任何空白字符原子,包括空格、制表符、换页符等等。等价于`[ \f\n\r\t\v]
\S匹配一个任何非空白字符原子。等价于`[^ \f\n\r\t\v]`或 `[^\s]
\b匹配一个单词边界原子,也就是指单词和空格间的位置
\B匹配一个非单词边界原子,等价于 `[^\b]
\t匹配一个制表符,tab键

取一个有点绕的"\b"转义符示例:

  1. import re
  2. '''
  3. 转义符(/) :
  4. 两个功能:
  5. 1、将一些普通符号赋予特殊功能
  6. 2、将特符号取消取特殊功能
  7. '''
  8. #\b:单词边界效果:
  9. txt = "my name is nana.nihao,nana"
  10. ret = re.findall(r"\bna",txt)
  11. print(ret)
  12. ret1 = re.findall(r"\bna\w+",txt)
  13. print(ret1)
  14. #输出:
  15. ['na', 'na', 'na']
  16. ['name', 'nana', 'nana']

3. 常用正则表达式

● raw-string翻译为:原生字符串;

        使用正则时,可以加不加r,也不会报错,但是保险起见还是加上r

● 工作中,正则一般用于验证数据、校验用户输入的信息、爬虫、运维日志分析等。

其中如果是验证用户输入的数据:

场景正则表达式
 用户名    ^[a-z0-9_-]{3,16}$
密码 ^[a-z0-9_-]{6,18}$
 手机号码 ^(?:\+86)?1[3-9]\d{9}$
 颜色的十六进制值^#?([a-f0-9]{6}|[a-f0-9]{3})$
电子邮箱 ^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+\.[a-z]+$
 URL^(?:https:\/\/|http:\/\/)?([\da-z\.-]+)\.([a-z\.]+).\w+$
IP 地址((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
HTML 标签^<([a-z]+)([^<]+)*(?:>(.*)<\/\1>
utf-8编码下的汉字范围 ^[\u2E80-\u9FFF]+$

4. re模块的方法

python本身没有内置正则处理的,python中的正则就是一段字符串,我们需要使用python模块中提供的函数把字符串发送给正则引擎,正则引擎会把字符串转换成真正的正则表达式来处理文本内容。

`re`模块提供了一组正则处理函数,使我们可以在字符串中搜索匹配项:

函数描述
findall按指定的正则模式查找文本中所有符合正则模式的匹配项,以列表格式返回结果。
search

在字符串中**任何位置**查找首个符合正则模式的匹配项,存在则返回re.Match对象,

不存在返回None

match

判定字符串**开始位置**是否匹配正则模式的规则,匹配则返回re.Match对象,

不匹配返回None

split按指定的正则模式来分割字符串,返回一个分割后的列表
sub/subn把字符串按指定的正则模式来查找符合正则模式的匹配项,并可以替换一个或多个匹配项成其他内容
compile编译:编译一个具体的查找规则,后续相同规则时直接调用

代码示例如下:

  1. import re
  2. #findall方法:
  3. ret = re.findall("\d+","apple 122 peach 34")
  4. print("ret:",ret)
  5. #输出:
  6. ret: ['122', '34']
  7. #search:返回的是符合的匹配对象的位置
  8. ret1 = re.search("\d+","apple 122 peach 34")
  9. print("ret1:",ret1)
  10. print("ret1:",ret1.group())
  11. #输出:
  12. ret1: <re.Match object; span=(6, 9), match='122'>
  13. ret1: 122
  14. #search结合有名分组:将要去提取的手机号、邮箱都取个名
  15. rel = re.search("(?P<tel>1[3-9]\d{9}).*?(?P<email>\d+@qq.com)", "我的手机号码是13928835900,我的邮箱是123@qq.com")
  16. print("rel:",rel)
  17. print(rel.group("tel"))
  18. print(rel.group("email"))
  19. #输出:
  20. rel: <re.Match object; span=(7, 34), match='13928835900,我的邮箱是123@qq.com'>
  21. 13928835900
  22. 123@qq.com
  23. # match方法:比search多一个起始判断^
  24. #rel2不满足起始为1,所有返回None
  25. rel2 = re.match("^1[3-9]\d{9}.*?", "我的手机号码是13928835900,我的另一个手机号是13711112255")
  26. print("rel2:",rel2)
  27. #满足起始为1
  28. rel3 = re.match("^1[3-9]\d{9}.*?", "13928835900,我的另一个手机号是13711112255")
  29. print("rel3:",rel3.group())
  30. #输出:
  31. rel1: None
  32. rel2: 13928835900
  1. import re
  2. #split方法:字符串分割
  3. txt = "my name is moluo"
  4. ret = re.split("\s", txt)
  5. print(ret)
  6. #输出:
  7. ['my', 'name', 'is', 'moluo']
  8. #sub/subn:函数用选择的文本替换匹配
  9. s = "12 23 45 67 "
  10. #将所有数字都替换为hello world
  11. ret1 = re.sub("\d+","hello",s)
  12. print("ret1:",ret1)
  13. #只替换前2个数字
  14. ret2 = re.sub("\d+","hello",s,2)
  15. print("ret2:",ret2)
  16. #输出:
  17. ret1: hello hello hello hello
  18. ret2: hello hello 45 67
  19. #compile方法:编译
  20. s1 = "12 apple 34 peach 77 banana"
  21. rl = re.findall("\d+",s1)
  22. s2 = "18 apple 39 peach 99 banana"
  23. rl2 = re.findall("\d+",s2)
  24. '''
  25. 可以看出每次都重新写了一遍findall查找规则
  26. 所以,我们可以直接把规则做个定义,直接引用,简单省力
  27. '''
  28. reg = re.compile(r"\d+") #定义规则
  29. print("rl:",reg.findall(s1)) #调用编译好的规则
  30. print("rl2:",reg.findall(s2))
  31. #输出:
  32. rl: ['12', '34', '77']
  33. rl2: ['18', '39', '99']

5. 正则进阶使用

.*?

.*?:这三个符号凑在一起,威力无穷~

通过以下代码示例感受下:

  1. import re
  2. '''
  3. 正则进阶:.*?
  4. '''
  5. #需要提取txt中的所有内容,效果对比:
  6. text = '<12> <xyz> <!@#$%> <1a!#e2> <>'
  7. ret = re.findall("<.+>", text)
  8. print("ret:",ret)
  9. ret1 = re.findall("<.+?>", text)
  10. print("ret1:",ret1)
  11. ret2 = re.findall("<.*?>", text)
  12. print("ret2:",ret2)
  13. #输出:
  14. ret: ['<12> <xyz> <!@#$%> <1a!#e2> <>']
  15. ret1: ['<12>', '<xyz>', '<!@#$%>', '<1a!#e2>']
  16. ret2: ['<12>', '<xyz>', '<!@#$%>', '<1a!#e2>', '<>']

模式修正符

模式修正符,也叫正则修饰符,模式修正符就是给正则模式增强或增加功能的

修正符 re模块提供的变量描述 
re.I 使模式对大小写不敏感,也就是不区分大小写 
mre.M 使模式在多行文本中可以多个行头和行位,影响 ^ 和 $ 
 s re.S 让通配符. 可以代码所有的任意原子(包括换行符\n在内)

代码示例如下: 

  1. import re
  2. '''
  3. 正则进阶:模式修正符
  4. .*?搭配re.S
  5. '''
  6. #提取所有<>里的内容:
  7. text = """
  8. <12
  9. >
  10. <x
  11. yz>
  12. <!@#$%>
  13. <1a!#
  14. e2>
  15. <>
  16. """
  17. ret = re.findall("<.*?>", text)
  18. print("ret:",ret)
  19. ret1 = re.findall("<.*?>", text, re.S)
  20. print("ret1:",ret1)
  21. #输出:
  22. ret: ['<!@#$%>', '<>']
  23. ret1: ['<12\n>', '<x\n yz>', '<!@#$%>', '<1a!#\n e2>', '<>']

6. 正则解析数据demo

以豆瓣电影top250为例,进行正则表达式的学以致用,进行提取第一页的25部电影名字

网址:https://www.douban.com/doulist/134462233/

可以看出,电影名被嵌套在多个div标签中

初级水平,简单处理步骤:

1. 将所有的返回html内容,黏贴在html文件中

2. 新建一个py文件,进行导入html文件,然后开始电影名提取

  1. import re
  2. with open("douban.html",encoding="utf-8") as f:
  3. s = f.read()
  4. #提取所有的电影名
  5. ret = re.findall('<div class="title">\s+<a.*?>(.*?)</a>', s, re.S)
  6. for movie in ret:
  7. movie_name = re.sub(r'<.*?>', '', movie)
  8. print(movie_name.strip())
  9. print(len(ret))
  10. #输出:
  11. 肖申克的救赎 The Shawshank Redemption
  12. 霸王别姬
  13. 阿甘正传 Forrest Gump
  14. 泰坦尼克号 Titanic
  15. 这个杀手不太冷 Léon
  16. 美丽人生 La vita è bella
  17. 千与千寻 千と千尋の神隠し
  18. 辛德勒的名单 Schindler&#39;s List
  19. 盗梦空间 Inception
  20. 忠犬八公的故事 Hachi: A Dog&#39;s Tale
  21. 星际穿越 Interstellar
  22. 楚门的世界 The Truman Show
  23. 海上钢琴师 La leggenda del pianista sull&#39;oceano
  24. 三傻大闹宝莱坞 3 Idiots
  25. 机器人总动员 WALL·E
  26. 放牛班的春天 Les choristes
  27. 无间道 無間道
  28. 疯狂动物城 Zootopia
  29. 大话西游之大圣娶亲 西遊記大結局之仙履奇緣
  30. 熔炉 도가니
  31. 教父 The Godfather
  32. 控方证人 Witness for the Prosecution
  33. 当幸福来敲门 The Pursuit of Happyness
  34. 怦然心动 Flipped
  35. 触不可及 Intouchables
  36. 25

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/763124
推荐阅读
  

闽ICP备14008679号