2022年 11月 5日

Python正则表达式(网址正则/超链接正则)

Python正则表达式(匹配超链接URL)

​ python的正则表达式是在re模块,属于内置模块。正则表达式格式的详细说明见文章结束表, 模式的构建通过PATTERN = re.compile(REGEX_STRING)构建,下面是python正则常用的函数。


Python函数

函数用法说明
PATTERN = re.compile(REGEX_STRING) 正则模式构建
match_ret = re.match(PATTERN, str) str是否符合某种模式,从str开始位置进行扫描
match_ret = re.search(PATTERN, str) str是否包含某种模式的字符串,扫描整个字符串
match_ret.group(idx)/match_ret.groups() 符合模式的所有字符串匹配(tartget_str)
上式match_ret无符合模式的匹配返回None,找到的符合模式的结果通过groups()取值
match_ret.group(idx=0)取指定位置的字符串匹配
match_ret.groups() 取所有字符串匹配
re.findall(PATTERN/REGEX_STRING, str) 返回所有符合模式的字符串列表 (ret_lst)
  1. URL格式匹配

​ 从给定的URL中获取IP(PORT),这个操作也可以通过python内置模块urllib的request.Request(url=_url)构建(type://host, type://origin_req_host)获取:

import re

URL_M3U8 = 'https://www.kkarm.com:65/20190818/zzElGIgO/index.m3u8'
URL_ORIGIN = "https://www.cmcm5.com/play/5334.html?5334-6-1"
'''
	URL模式: http[s]://host:port/query
	目标:    获取query前的base_url (schema://host:port)
	正则构建:
		方式1:字符串格式
		方式2:突出特征 -> 以query前的/为分隔
'''
# https://后的host:port(由字母数字下划线, .点, :冒号组成, 遇到第一个/即终止匹配)
HOST_PATTERN = re.compile(r"\w{4,5}://(\w|\.|:)+")
# https://后的所有非/字符(遇到第一个/即终止)
HOST_PATTERN2 = re.compile(r"(\w{4,5}://[^/]+)")
host_match = re.match(HOST_PATTERN, URL_ORIGIN)
host_match2 = re.match(HOST_PATTERN2, URL_M3U8)
HOST = host_match and host_match.group()
HOST2 = host_match2 and host_match.group()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  1. 从大量文本中提取指定格式的URL

​ re.findall()经常和python爬虫结合,将网络请求的文本内容进行提取(html/js),从中获取指定格式的内容,从中提取URL在钻入式的爬取其他链接内容。下面是部分格式化后的链接内容。

目标字符串1(格式化)[1]

%u7b2c2%u96c6$CNTY5MDI1Ng==#
%u7b2c3%u96c6$CNTY5MDMwMA==#
%u7b2c4%u96c6$CNTY5MDMwNA==$$$
01$https://www.mgtv.com/b/159003/3363084.html#
02$https://www.mgtv.com/b/159003/3363085.html#
03$https://www.mgtv.com/b/159003/3364481.html#
04$https://www.mgtv.com/b/159003/3364483.html#
05$https://www.mgtv.com/b/159003/3366093.html$$$
%u7b2c01%u96c6$https://www.kkarm.com:65/20190818/zzElGIgO/index.m3u8#
%u7b2c02%u96c6$https://www.kkarm.com:65/20190818/U90bZ2CW/index.m3u8$$$
%u7b2c1%u96c6$https://video.buycar5.cn/20201006/a15C23PF/index.m3u8#
%u7b2c2%u96c6$https://video.buycar5.cn/20201006/UVsOhEq0/index.m3u8#
%u7b2c3%u96c6$https://video.buycar5.cn/20201006/hzqZ3BgP/index.m3u8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

​ 我们想要做的就是从中提取m3u8格式的URL(这是一种流式视频的文件格式,列出了所有视频片段的下载位置),下面是匹配思路:

js_content = """
%u7b2c2%u96c6$CNTY5MDI1Ng==#%u7b2c3%u96c6$CNTY5MDMwMA==#%u7b2c4%u96c6$CNTY5MDMwNA==$$$01$https://www.mgtv.com/b/159003/3363084.html#02$https://www.mgtv.com/b/159003/3363085.html#03$https://www.mgtv.com/b/159003/3364481.html#04$https://www.mgtv.com/b/159003/3364483.html#05$https://www.mgtv.com/b/159003/3366093.html$$$%u7b2c01%u96c6$https://www.kkarm.com:65/20190818/zzElGIgO/index.m3u8#%u7b2c02%u96c6$https://www.kkarm.com:65/20190818/U90bZ2CW/index.m3u8#$$$%u7b2c1%u96c6$https://video.buycar5.cn/20201006/a15C23PF/index.m3u8#%u7b2c2%u96c6$https://video.buycar5.cn/20201006/UVsOhEq0/index.m3u8#%u7b2c3%u96c6$https://video.buycar5.cn/20201006/hzqZ3BgP/index.m3u8
"""
  • 1
  • 2
  • 3
  • 按照[1]中的格式进行匹配

    # 提取所有这个格式的内容
    PATTERN = r"%u\w+\$(.*?)#{1}|\${3}"
    # 提取以m3u8结尾的链接
    M3U8_PATTERN = PATTERN = r"%u\w+\$(.*?\.m3u8)#{1}|\${3}"
    m3u8_match0= re.findall(PATTERN, js_content)
    m3u8_match = re.findall(M3U8_PATTERN, js_content)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    (.*?)是re.findall()常用的匹配方式,()表示只提取括号中的内容,括号意外的作为格式匹配的一部分,比如从特定html内容里,提取需要的图片链接:

    img = re.findall('<div class="arc_body">\n<img src="(.*?)"', itext)[0]
    
    • 1

    但是,这个提取的结果出现了偏差(m3u8结果)

    CNTY5MDI1Ng==#%u7b2c3%u96c6$CNTY5MDMwMA==#%u7b2c4%u96c6$CNTY5MDMwNA==$$$01$https://www.mgtv.com/b/159003/3363084.html#02$https://www.mgtv.com/b/159003/3363085.html#03$https://www.mgtv.com/b/159003/3364481.html#04$https://www.mgtv.com/b/159003/3364483.html#05$https://www.mgtv.com/b/159003/3366093.html$$$%u7b2c01%u96c6$https://www.kkarm.com:65/20190818/zzElGIgO/index.m3u8
    https://www.kkarm.com:65/20190818/U90bZ2CW/index.m3u8
    ''
    https://video.buycar5.cn/20201006/a15C23PF/index.m3u8
    https://video.buycar5.cn/20201006/UVsOhEq0/index.m3u8
    
    • 1
    • 2
    • 3
    • 4
    • 5
  • 只提取m3u8结尾的URL格式

    文本[1]中,m3u8是一个链接格式,每个URL以“#”结尾,所有同类的URL以”$$$”结尾,URL都是以https开头,遇到#或者$一个URL结束。正则的匹配实质是找到恰如其分的分割符,找到目标字符串。

    M3U8_PATTERN = r"(https://[^#|$]*?\.m3u8)"
    m3u8_match = re.findall(M3U8_PATTERN, js_content)
    
    • 1
    • 2
  1. python与 js escape()/unecape

​ python 内置库urllib.parse提供了quote()/unquote()函数来达到js escape()/unescape()的效果。对于爬取的内容含有js编码过的字符串可以采用unquote函数进行解码:

  • 对中文进行解码

    js_content = js_content.replace('%u', '\\u').encode().decode('unicode_escape')
    
    • 1
  • 还原js转码字符

    import urllib.parse
    js_content = urllib.parse.unquote(js_content)
    
    • 1
    • 2
  1. 正则表达式模式

​ 模式字符串使用特殊的语法来表示一个正则表达式,特殊字符代表本意,前面需要加上进行反斜杠\进行转义。

表1 正则表达式模式(所有语言通用)

模式 描述
^ 匹配字符串的开头
$ 匹配字符串的末尾。
. 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符。
[…] 用来表示一组字符,单独列出:[amk] 匹配 ‘a’,‘m’或’k’
[^…] 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符。
re* 匹配0个或多个的表达式。
re+ 匹配1个或多个的表达式。
re? 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式
re{ n} 精确匹配 n 个前面表达式。例如, o{2} 不能匹配 “Bob” 中的 “o”,但是能匹配 “food” 中的两个 o。
re{ n,} 匹配 n 个前面表达式。例如, o{2,} 不能匹配”Bob”中的”o”,但能匹配 “foooood”中的所有 o。“o{1,}” 等价于 “o+”。“o{0,}” 则等价于 “o*”。
re{ n, m} 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式
a| b 匹配a或b
(re) 对正则表达式分组并记住匹配的文本
\w 匹配字母数字及下划线
\W 匹配非字母数字及下划线
\s 匹配任意空白字符,等价于 [ \t\n\r\f]
\S 匹配任意非空字符
\d 匹配任意数字,等价于 [0-9].
\D 匹配任意非数字
\A 匹配字符串开始
\Z 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串。
\z 匹配字符串结束
\G 匹配最后匹配完成的位置。
\b 匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\b’ 可以匹配”never” 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’。
\B 匹配非单词边界。‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。
\n, \t, 等. 匹配一个换行符。匹配一个制表符。等
\1…\9 匹配第n个分组的内容。
\10 匹配第n个分组的内容,如果它经匹配。否则指的是八进制字符码的表达式。