057论一只爬虫的自我修养5:正则表达式(中)
>>> import re>>> re.search(r'FishC', 'I love FishC.com!')
!&*#@……*&@¥……*(
>>> re.search(r'\.', 'I love FishC.com!')
<_sre.SRE_Match object, span=(12, 13), match='.'>
在正则表达式中,反斜杠同样具有这剥夺元字符的特殊能力
元字符就是这个字符本身代表的其他含义,有特殊能力的字符,像这个点号,就是个元字符
>>> re.search(r'\d', 'I love 123 FishC.com!')
<_sre.SRE_Match object; span=(7, 8), match='1'>
>>> re.search(r'\d\d\d', 'I love 123 FishC.com!')
<_sre.SRE_Match object; span=(7, 10), match='123'> # 然后就把123依次匹配下来了
结合以上两点知识就可以匹配一个IP地址
>>> re.search(r'\d\d\d.\d\d\d.\d\d\d.\d\d\d', '233.233.233.666') # 反斜杠d表示匹配到数字是0~9,而IP地址的约定范围,每组数据是0~255,三个反斜杠d可以匹配到的最大数字是999,这里要求IP地址必须有三个数字,但是有的IP地址则是233,66,233之类的,有的只有两个数字
<_sre.SRE_Match object; span=(0, 15), match='233.233.233.666'>
>>>
057论一只爬虫的自我修养5:正则表达式(中2)
>>> import re>>> re.search(r'', 'I love FishC.com!')
<_sre.SRE_Match object; span=(3, 4), match='o'> # 因为正则表达式自带大小写敏感模式,解决方案1、关闭大小写敏感模式2、修改字符类,例如
>>> re.search(r'', 'I love FishC.com!')
<_sre.SRE_Match object; span=(0, 1), match='I'> # 字符类中的任何一个字符匹配成功,就算匹配成功,在中括号中,也可以使用一个小横杠-,来表示一个范围,例如
>>> re.search(r'', 'I love 123 FishC.com!')
<_sre.SRE_Match object; span=(7, 8), match='1'>
>>> re.search(r'', 'I love 123 FishC.com!')
<_sre.SRE_Match object; span=(8, 9), match='2'>
>>>
有关数字范围↑
——————————————————————————————
有关匹配个数↓
限定重复匹配的个数,可以使用大括号来解决,例如
>>> re.search(r'ab{3}c', 'abbbc')
<_sre.SRE_Match object; span=(0, 5), match='abbbc'> # 要重复多少次,大括号里就写上那个要重复次数的数字就行了
>>> re.search(r'ab{3}c', 'abbbbbbbbc') # 如果手滑多打了几个b,Ta就匹配不了了
>>> re.search(r'ab{3,10}c', 'abbbbbbbbc') # 可以给Ta限制范围
<_sre.SRE_Match object; span=(0, 10), match='abbbbbbbbc'> # 在3或10以内的b,Ta都会进行匹配
>>> 摆渡终极鉴黄师 发表于 2017-7-7 00:00
>>> 3>2 and 1>> (3>2) and (1>> (3>2) and (1>2)
False
每次运行程序产生的 ...
这不是书上的内容吗
057论一只爬虫的自我修养5:正则表达式(下)
本帖最后由 摆渡终极鉴黄师 于 2017-12-2 01:34 编辑>>> import re
>>> re.search(r'', '188')
<_sre.SRE_Match object; span=(0, 1), match='1'>
>>> re.search(r'', '188')
>>>
正则表达式匹配的是字符串,所以说,数字对于字符来说只有0到9这几个字符
>>> re.search(r'\d\d|2\d|25', '188') # 这跟逻辑或是一个道理,要么第一个成立,要么第二个成立,要么第三个成立,三个里面任何一个成立都是OK的
<_sre.SRE_Match object; span=(0, 3), match='188'> # 现在来可以试试IP地址
>>> re.search(r'(({0,1}\d{0,1}\d|2\d|25)\.){3}({0,1}\d{0,1}\d|2\d|25', '233.233.6.6') # 小括号起到的作用是分组,一个小组就是一个整体,后面{}里加上的就是重复的次数,一个小组的内容就要必须匹配,小组内容匹配完之后,再来匹配这个反斜杠点\. moyuqqxing 发表于 2017-11-30 21:27
这不是书上的内容吗
是啊{:10_334:}
058论一只爬虫的自我修养6:正则表达式2(上)
反斜杠与字符的combo 触发效果\d 匹配任何十进制数字;相当于类
\D 与\d相反,匹配任何非十进制数字的字符;相当于类[^0-9]
\s 匹配任何空白字符(包含空格、换行符、制表符等);相当于类[\t\n\r\f\v]
\S 与\s相反,匹配任何空白字符;相当于类[^ \t\n\r\f\v]
\w 匹配任何单词字符,见上方解释
\W 与\w相反
\b 匹配单词的开始或结束
\B 与\b相反
058论一只爬虫的自我修养6:正则表达式2(中)
|表示匹配正则表达式的A或者B,例如>>> import re
>>> re.search(r"Fish(C|D)", "FishD")
<_sre.SRE_Match object; span=(0, 5), match='FishD'>
>>> re.search(r"Fish(C|D)", "FishC")
<_sre.SRE_Match object; span=(0, 5), match='FishC'>
>>> re.search(r"Fish(C|D)", "FishE")
>>>
^(脱字符)匹配输入字符串的开始位置,也就是确定一个位置,例如
>>> re.search(r"^FishC", "FishC")
<_sre.SRE_Match object; span=(0, 5), match='FishC'>
>>> re.search(r"^FishC", "f FishC") # 必须是字符串的开始位置对应,所以这个不行
>>>
$(差不多就是和^反一反)匹配输入字符串的结束位置,例如
>>> re.search(r"FishC$", "loveFishC")
<_sre.SRE_Match object; span=(4, 9), match='FishC'>
>>> re.search(r"FishC$", "loveFiCh") # 必须是字符串的结束位置对应,所以这个不行
>>>
058论一只爬虫的自我修养6:正则表达式2(中2)
本帖最后由 摆渡终极鉴黄师 于 2017-12-5 11:26 编辑\将一个普通字符变为特殊字符,例如\d表示匹配所有十进制数字
结束元字符的特殊功能,例如\.表示点号本身
引用序号对应的子组匹配的字符串(反斜杠加上一个序号,后面的数字是1-99,Ta表示对应的组所匹配的字符串),例如
>>> import re
>>> re.search(r"(FishC)\1", "FishC.com") # 子组就是括号括起来的
>>>
>>> re.search(r"(FishC)\1", "FishCFishC")
<_sre.SRE_Match object; span=(0, 10), match='FishCFishC'> # 所以后面必须是FishC,Ta才可以匹配到
>>>
058论一只爬虫的自我修养6:正则表达式2(中3)
>>> import re>>> re.search(r"(FishC)\060", "FishCFishC0")
>>> re.search(r"(FishC)\060", "FishCFishC0") # 0的十六进制是三个0,转换成八进制就是60,这里是060,因为八进制的要求是三个数字来描述
<_sre.SRE_Match object; span=(5, 11), match='FishC0'>
>>>
十进制的97对应的是小写字母a,八进制的话就是141
0开头的三位数或者直接一个三位数Ta都表示的是八进制
>>> re.search(r"(FishC)\141", "FishCFishCa") # 十进制的97对应的是小写字母a,八进制的话就是141,0开头的三位数或者直接一个三位数Ta都表示的是八进制
<_sre.SRE_Match object; span=(5, 11), match='FishCa'> # 匹配成功
>>>
058论一只爬虫的自我修养6:正则表达式2)(中4)
本帖最后由 摆渡终极鉴黄师 于 2017-12-9 15:07 编辑[...]字符类(就是字符集合的意思),匹配所包含的任意一个字符,被Ta包含在里面的字符都会失去特殊功能,就像反斜杠加上一个元字符,是一样的,例如
>>> import re
>>> re.search(r"[.]", "FishC.com")
<_sre.SRE_Match object; span=(5, 6), match='.'>
>>>
字符类的意思就是将Ta里边的内容当成普通的字符来看待,除了几个特殊的字符,例如小横杠-
findall方法是找到所有匹配的字符串,把Ta们打包成一个列表给返回,例如(当Ta遇到组或子组的时候也会有陷阱)
>>> re.findall(r"", "FishC.com")
['i', 's', 'h', 'c', 'o', 'm']
>>>
058论一只爬虫的自我修养6:正则表达式2(中5)
本帖最后由 摆渡终极鉴黄师 于 2017-12-9 15:08 编辑反斜杠在字符类里边表示python的转义符,例如
>>> re.findall(r"[\n]", "FindC.com\n")
['\n'] # 直接就匹配回车这个符号
>>>
058论一只爬虫的自我修养6:正则表达式2(中6)
>>> re.findall(r"[^a-z]", "FishC.com\n") # 出了字符类里的内容其他的都匹配,就是取反的意思['F', 'C', '.', '\n']
>>>
这个脱字符^只能放在最前面,如果放在后面的话就不是这样,就表示匹配脱字符本身,例如
>>> re.findall(r"", "FishC.com\n")
['i', 's', 'h', 'c', 'o', 'm']
>>>
058论一只爬虫的自我修养6:正则表达式2(下)
* 匹配前面的字表达式零次或多次,等价于{0,}+匹配前面的字表达式一次或多次,等价于{1,}
?匹配前面的字表达式零次或一次,等价于{0,1}
正则表达式默认是启用了贪婪的模式进行匹配的,贪婪就是贪心,也就是在符合的条件下,Ta会尽可能多的去匹配,例如
>>> import re
>>> s = "<html><title>I love FishC.com</title></html>"
>>> re.search(r"<.+>", s) # 加号+表示重复前面任何内容,Ta遇到右尖括号>Ta会停下来,尽可能多找,找到最后,最后不匹配再倒着往回找到第一个匹配的时候Ta就停下来,所以Ta匹配了整个字符串
<_sre.SRE_Match object; span=(0, 44), match='<html><title>I love FishC.com</title></html>'>
>>>
在表示重复的元字符后面再加上一个问号,这时候问号?不代表0次或者1次,这时候问号代表非贪婪模式
059论一只爬虫的自我修养7:正则表达式3(上)
如果你需要重复地使用某个正则表达式,那么你可以先将该正则表达式编译成模式对象。需要使用re.compile()方法来编译059论一只爬虫的自我修养7:正则表达式3(中)
VERBOSE使用这个标志后空格和#会被忽略(不包括反斜杠转义后的空格和#),例如charref = re.compile(r"""
&[#] # 开始引用
(
0+ #八进制
|+ #十进制
|x+ 只留禁止
)
: #结尾分号
""", re.VERBOSE)
————————
使用后代码看起来会舒服很多,要不然没空格会显得太复杂,例如
charref=re.compile("&#(0+|+|x+);")
059论一只爬虫的自我修养7:正则表达式3(下)
本帖最后由 摆渡终极鉴黄师 于 2017-12-15 16:09 编辑http://bbs.fishc.com/thread-57691-1-1.html
060论一只爬虫的自我修养8:正则表达式4(上)
本帖最后由 摆渡终极鉴黄师 于 2017-12-15 18:32 编辑group方法,例如
>>> import re
>>> result = re.search(r" (\w+) (\w+)", "I love FishC.com!")
>>> result
<_sre.SRE_Match object; span=(1, 12), match=' love FishC'>
>>> result.group(1)
'love'
>>> result.group(2)
'FishC'
>>> result.group()
' love FishC'
>>>
060论一只爬虫的自我修养8:正则表达式4(上2)
@&*……#*&!*(@>>> result.start() # 匹配的开始
1
>>> result.end() # 匹配的结束
12
>>> result.span() #匹配的范围
(1, 12)
>>>
060论一只爬虫的自我修养8:正则表达式4(中)
import urllib.requestimport re
def open_url(url):
req = urllib.request.Request(url)
req.add_header('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36')
page = urllib.request.urlopen(req)
html = page.read().decode('utf-8')
return html
def get_img(html):
p = r'<img class="BDE_Image" src="([^"]+\.jpg)"' # ^"表示除了这个双引号的之外的所有字符,可以用星号*重复0次或者用+加号重复一次或者多次一次或者多次,这个点.要加反斜杠\,要不然表示任何除了换行符之外其他的任何字符,加个小括号可以把地址提取出来
imglist = re.findall(p, html)
for each in imglist:
filename = each.split("/")[-1]
urllib.request.urlretrieve(each, filename, None)
if __name__ == '__main__':
url = "http://tieba.baidu.com/p/5481401082"
get_img(open_url(url))
060论一只爬虫的自我修养8:正则表达式4(下)
(?:...)非捕获组,即该子组匹配的字符串无法从后边获取小括号是元字符
import urllib.request
import re
def open_url(url):
req = urllib.request.Request(url)
req.add_header('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36')
page = urllib.request.urlopen(req)
html = page.read().decode('utf-8')
return html
def get_img(html):
p = r'(?:(?:?\d?\d|2\d|25)\.){3}(?:?\d?\d|2\d|25)' # 也就是所有出现子组的位置问号冒号下去,这样就不会直接捕获了,也不会给变成子组显示出来
iplist = re.findall(p, html)
for each in iplist:
print(each)
if __name__ == '__main__':
url = "!&*#……(*@&"
get_img(open_url(url))
多练习就ok了