零.文章出处
https://blog.csdn.net/Eastmount/article/details/108887652
- 文本仅仅是个人对于杨老师的文章的学习笔记总结,请支持原文
一、正则的相关知识
0.理解和使用
- 1.正则就是一个表达式
- 2.表达式可以由一个或者多个pattern组成
- 3.pattern由符号组成,且遵循特定的规则
pattern就是要回答:谁+多少+在哪里
所以Pattern = 代词 + 量词 + 定位介词
0.1代词
代词就是用来指代某一个特定字符,只指代一个字符的范围。
^:表示从头开始校验,$:表示校验到最后一位
常用的代词(大写一般都是取反):
- []::表示的是一个字符的范围
- [0-9]:表示0-9之间的一个数字
- [a-zA-Z]:表示一个大小写的字母
- \d: 数字
- \D: 非数字
- \w == [0-9a-zA-Z_] :匹配字母或数字或下划线或汉字
- \W== [^0-9a-zA-Z_]:非匹配字母或数字或下划线或汉字
- \s: 空格
- \S: 非空格
- . :表示除了换行\n之外的任意字符
- [0-9a-zA-Z_] : 字符集
- [^xyz] :
- [[:alpha:]] 任何字母
- [[:digit:]] 任何数字
- [[:alnum:]] 任何字母和数字
- [[:space:]] 任何空白字符
- [[:upper:]] 任何大写字母
- [[:lower:]] 任何小写字母
- [[:punct:]] 任何标点符号
- [[:xdigit:]] 任何16进制的数字,相当于[0-9a-fA-F]
0.2量词
量词,就是有多少个代词。
*有无出现都可以,+至少出现一次,?表示1次或者0次,{}限定出现的次数
0.3 定位词
- ^ : 行首
- $ : 行尾
- \b : 单词边界
- \B : 非单词边界
0.4 选择器:
用来捕获匹配字符串,或者组合多种模式进行匹配
(pattern)
- (?:pattern) :匹配 pattern 但不获取匹配结果,hello|Hello 可以写成 (H|h)ello
- (?=pattern) :正向肯定预查(look ahead positive assert), Windows(?!95|98|NT|2000) 不匹配 Windows3.1
- (?!pattern) :正向否定预查(negative assert), Windows(?!95|98|NT|2000) 匹配 Windows3.1
- (?<=pattern) :反向(look behind)肯定预查
- (?<!pattern) :反向否定预查
捕获组是通过从左到右计算其开括号来编码,例如,在表达式 ((A)((B©))),对应以下捕获组:
((A)(B©))
(A)
(B©)
©
0.5反向引用:
二义性的符号 ^ : 在代词里表示非,在定位词中表示行首
二义性的符号 ?: 在代词后面表示量词,在量词后面表示非贪婪,在选择器中表示非捕获
1.re模块
python中通re模块实现对于正则表达式的支持
- import re
使用步骤:
1)创建pattern实例
2)再用pattern创建一个匹配实例(match)
3)用match实例去匹配文本常用的匹配函数;:findall
findall(string[, pos[, endpos]]) | re.findall(pattern, string[, flags])
该函数用于对字符串的文本的匹配,将匹配到的文本数据都放在一个列表之中
常见的re参数取值:
1)re.I(re.IGNORECASE):使用匹配忽略大小写
2)re.M(re.MULTILINE):允许多行的匹配
3)re.S(re.DATALL):匹配包换换行在内的所有字符
2.complie方法
re模块中的常用方法
- compile(pattern[,flags] )
- 根据包含正则表达式的字符串创建模式对象,返回一个pattern对象。参数flags是匹配模式,可以使用按位或“|”表示同时生效。Pattern对象是不能直接实例化的,只能通过compile方法得到。
>>> import re
>>> string="A1.45,b5,6.45,8.82"
>>> regex = re.compile(r"\d+\.?\d*")
>>> print regex.findall(string)
['1.45', '5', '6.45', '8.82']
>>>
3.match方法(第一个不对就不行)
match方法是从字符串的pos下标处起开始匹配pattern,如果pattern结束时已经开始匹配,就会返回一个match对象,如果匹配过程中无法匹配,或者匹配结束就会返回一个None:
match(string[, pos[, endpos]]) | re.match(pattern, string[, flags])
参数string表示字符串;pos表示下标,pos和endpos的默认值分别为0和len(string);参数flags用于编译pattern时指定匹配模式。
4.search方法(找到一个符合条件的就停下)
search方法用于查找字符串中可以匹配成功的子串。从字符串的pos下标处尝试匹配pattern,如果pattern结束时仍可匹配,则返回一个match对象;若pattern结束时仍无法匹配,则将pos加1后重新尝试匹配;直到pos=endpos时仍无法匹配则返回None。函数原型如下:
search(string[, pos[, endpos]]) | re.search(pattern, string[, flags])
参数string表示字符串;pos表示下标,pos和endpos的默认值分别为0和len(string));参数flags用于编译pattern时指定匹配模式。
import re
s = '娜扎佟丽娅迪丽热巴'
result = re.match('佟丽娅',s)
print(result)
result = re.search('佟丽娅',s)
print(result)
print(result.span())#>>>输出的的位置
print(result.group())#>>>输出的是匹配到的信息
二 、数据爬取常用的模块
1.urllib模块
urllib中的request 中的urlopen方法
urlopen(uel,data=None,proxies=None)
该方法用于创建一个URL的类的对象,url是路径,data表示以post方式提交数据到网页,proxies表示网页代理。
该方法返回的是一个类的对象,这个类对象可以使用的方法
案例:
import urllib.request
import webbrowser as web
url = "http://www.baidu.com"
content = urllib.request.urlopen(url)
print(content.read())
print(content.info())
print(content.geturl())
print(content.getcode())
#保存网页
open('baidu.com','wb').write(content.read())
#浏览器打开某个网页
web.open_new_tab('baidu.com')
- urlretrieve
urlretrieve(url, filename=None, reporthook=None, data=None)
该函数是将远程数据下载保存到本地,
参数filename指定了本地的保存路径,如果不设置这个函数就会生存一临时的文件夹
reporhook是一个回调函数,当连接上一个服务器就会触发回调函数,该函数通常用来保存当前的下载精度。
data表示上传表单数据
案例:
import urllib.request
#定义一个下载函数,a为已经下载的数据块,b为数据块的大小,c为远程数据
def Download(a,b,c):
per = 100.0 * a * b / c
if per > 100:
print('已经下载 %.2f' % per)
print('已经下载 %.2f' % per)
url = 'http://www.sina.com'
local = './sina.html'
urllib.request.urlretrieve(url,local,Download)
urllib模块中常用的两个方法,其中urlopen()用于打开网页,urlretrieve()方法是将远程数据下载到本地
2.urlparse模块
urlparse主要用来对于url的拆分和合并操作,它可以将url拆分为6个元组,并且返回元组,也可以将拆分的url合并成为一个url。主要的函数有urljoin,urlsplit,urlparse等等
-urlparse
urlparse.urlparse(urlstring[, scheme[, allow_fragments]])
该函数将urlstring值解析成6个部分,从urlstring中取得url,并返回元组(scheme, netloc, path, params, query, fragment)。该函数可以用来确定网络协议(HTTP、FTP等)、服务器地址、文件路径等。实例代码如下所示。
案例:
from urllib.parse import urlparse
url = urlparse('http://www.sina.com')
print(url)
print(url.netloc)
这个网址输出的参数都是无
# coding=utf-8
from urllib.parse import urlparse
url = urlparse('http://www.eastmount.com/index.asp?id=001')
print(url) #url解析成六部分
print(url.netloc) #输出网址
老师的输出:
可以看出确实将网站中的不同参数进行了解析分隔
用以调用urlunparse()函数将一个元组内容构建成一条Url。
- urlunparse
urlparse.urlunparse(parts)
案例:
# coding=utf-8
import urllib.parse
url = urllib.parse.urlparse('http://www.eastmount.com/index.asp?id=001')
print(url) #url解析成六部分
print(url.netloc) #输出网址
#重组URL
u = urllib.parse.urlunparse(url)
print(u)
正则表达式抓取网络数据
1.抓取标签间的内容
1).抓取得title内容
用(.*?)来自抓取我们需要的内容
<title>(.*?)</title>
案例
import re
import urllib.request
url = "http://www.baidu.com"
content = urllib.request.urlopen(url).read()
title = re.findall(r"<title>(.*?)</title>",content.decode('utf8'))
print(title[0])
直接读出来的content的内容是二进制的编码格式:
但是将content.decode(‘utf8’)解码后,就还原了原有网页的格式:
最后用re的findall匹配还原的网页格式中找title:
2).获取超链接的标签的内容
# coding=utf-8
import re
import urllib.request
url = "http://www.baidu.com/"
content = urllib.request.urlopen(url).read()
#获取完整超链接
res = r"<a.*?href=.*?<\/a>"
urls = re.findall(res, content.decode('utf-8'))
for u in urls:
print(u)
#获取超链接<a>和</a>之间内容
res = r'<a .*?>(.*?)</a>'
texts = re.findall(res, content.decode('utf-8'), re.S|re.M)
for t in texts:
print(t)
这样获取的是整个的标签的内容,注意 .*?都必须是英文字符,哎,我说我怎么匹配不出来
这也是获取标签中的内容:
3).抓取tr (table row)和td(table data)标签
# coding=utf-8
import re
import urllib.request
content = urllib.request.urlopen("test.html").read() #打开本地文件
#获取<tr></tr>间内容
res = r'<tr>(.*?)</tr>'
texts = re.findall(res, content.decode('utf-8'), re.S|re.M)
for m in texts:
print(m)
#获取<th></th>间内容
for m in texts:
res_th = r'<th>(.*?)</th>'
m_th = re.findall(res_th, m, re.S|re.M)
for t in m_th:
print(t)
#直接获取<td></td>间内容
res = r'<td>(.*?)</td><td>(.*?)</td>'
texts = re.findall(res, content.decode('utf-8'), re.S|re.M)
for m in texts:
print(m[0],m[1])
2.抓取标签中的参数
1).抓标签中的url
网页中的url基本的格式都是内容,我们要的就是url:
案例:
import re
content = '''
<a href="http://news.baidu.com" name="tj_trnews" class="mnav">新闻</a>
'''
res = r"(?<=href=\").+?(?=\")|(?<=href=\').+?(?=\')"
urls = re.findall(res, content, re.I|re.S|re.M)
for url in urls:
print(url)
老师这个正则表达式,我就有点看不懂了。去搜了下
正则表达式:(?<=(href=")).{1,200}(?=(">))
解释:(?<=(href=")) 表示 匹配以(href=")开头的字符串,并且捕获(存储)到分组中
(?=(">)) 表示 匹配以(">)结尾的字符串,并且捕获(存储)到分组中
2.抓取图片
content = '''<img alt="Python" src="http://www.yangxiuzhang.com/eastmount.jpg" />'''
urls = re.findall('src="(.*?)"', content, re.I|re.S|re.M)
print urls
# ['http://www.yangxiuzhang.com/eastmount.jpg']
3.获取最后一个参数
urls = 'http://www..csdn.net/eastmount.jpg'
name = urls.split('/')[-1]
print name
3.字符串的替换
3.1数据定位
如果数据在一个大的数据框中,可以通过finde函数找到数据的其实位置和结束位置,切片得到数据
star = content.find(r"table class='infobox'") #起始的位置
end = content.find(r'</table>') #终点位置
infobox = text[start:end]
print infobox
3.2 数据清洗替换
案例:
import re
content = '''
<tr><td>1001</td><td>你好<br /></td></tr>
<tr><td>1002</td><td>世 界</td></tr>
<tr><td>1003</td><td><B>Python</B></td></tr>
'''
res = r'<td>(.*?)</td><td>(.*?)</td>'
texts = re.findall(res,content,re.S|re.M)
for text in texts:
print(text[0],text[1])
数据的替换和利用正则再次重新提取数据:
# coding=utf-8
import re
content = '''
<tr><td>1001</td><td>你好<br /></td></tr>
<tr><td>1002</td><td>世 界</td></tr>
<tr><td>1003</td><td><B>Python</B></td></tr>
'''
res = r'<td>(.*?)</td><td>(.*?)</td>'
texts = re.findall(res, content, re.S|re.M)
for text in texts:
value0 = text[0].replace('<br />', '').replace(' ', '')
value1 = text[1].replace('<br />', '').replace(' ', '')
if '<B>' in value1:
m_value = re.findall(r'<B>(.*?)</B>', value1, re.S|re.M)
print(value0, m_value[0])
else:
print(value0, value1)