import re
reg3 = r’(?<=hello)-python’
print(re.search(reg3, ‘hello-python’))
print(re.search(reg3, ‘hell-python hello-python’))
print(re.search(reg3, ‘hell-python’))
输出结果
<_sre.SRE_Match object; span=(5, 12), match=‘-python’>
<_sre.SRE_Match object; span=(17, 24), match=‘-python’>
None
环视在对字符串插入某些字符很有效,你可以利用它来匹配位置,然后插入对应的字符,而不需要对原来的文本进行替换。
捕获分组
在正则表达式中,分组可以帮助我们提取出想要的特定信息。
指明分组很简单,只需要在想捕获的表达式中两端加上()就可以了。在python中,我们可以用re.search(reg, xx).groups()来获取到所有的分组。
默认的()中都指明了一个分组,分组序号为i,i从1开始,分别用re.search(reg, xx).group(i)来获取。
如果不想捕获分组可以使用(?:…)来指明。
具体例子如下:
import re
reg7 = r’hello,([a-zA-Z0-9]+)’
print(re.search(reg7, ‘hello,world’).groups())
print(re.search(reg7, ‘hello,world’).group(1))
print(re.search(reg7, ‘hello,python’).groups())
print(re.search(reg7, ‘hello,python’).group(1))
输出结果
(‘world’,)
world
(‘python’,)
python
贪婪匹配
贪婪匹配是指正则表达式尽可能匹配多的字符,也就是趋于最大长度匹配。
正则表达式默认是贪婪模式。
例子如下:
import re
reg5 = r’hello.*world’
print(re.search(reg5, ‘hello world,hello python,hello world,hello javascript’))
输出结果
<_sre.SRE_Match object; span=(0, 36), match=‘hello world,hello python,hello world’>
由上可以看到它匹配的是hello world,hello python,hello world而不是刚开始的hello world。那如果我们只是想匹配刚开始的hello world,这时候我们可以利用正则表达式的非贪婪模式。
非贪婪匹配正好与贪婪匹配相反,它是指尽可能匹配少的字符,只要匹配到了就结束。要使用贪婪模式,仅需要在量词后面加上一个问号(?)就可以。
还是刚刚那个例子:
import re
reg5 = r’hello.*world’
reg6 = r’hello.*?world’
print(re.search(reg5, ‘hello world,hello python,hello world,hello javascript’))
print(re.search(reg6, ‘hello world,hello python,hello world,hello javascript’))
输出结果
<_sre.SRE_Match object; span=(0, 36), match=‘hello world,hello python,hello world’>
<_sre.SRE_Match object; span=(0, 11), match=‘hello world’>
由上可以看到这是我们刚刚想要匹配的效果。
进入开发
有了上面的基础知识,我们就可以进入开发环节了。
我们想实现的最终效果
本次我们的最终目的是写一个简单的python爬虫,这个爬虫能够下载一个静态网页,并且在保持网页引用资源的相对路径下下载它的静态资源(如js/css/images)。测试网站为http://www.peersafe.cn/index.html,效果图如下:
开发流程
我们的总体思路是先获取到网页的内容,然后利用正则表达式来提取我们想要的资源链接,最后就是下载资源。
获取网页内容
我们选用python3自带的urllib.http来发出http请求,或者你可以采用第三方请求库requests。
获取内容的部分代码如下:
url = ‘http://www.peersafe.cn/index.html’
读取网页内容
webPage = urllib.request.urlopen(url)
data = webPage.read()
content = data.decode(‘UTF-8’)
print(‘> 网站内容抓取完毕,内容长度:’, len(content))
获取到内容之后,我们需要把它保存下来,也就是写到本地磁盘上。我们定义一个SAVE_PATH路径,代表专门放置爬虫下载的文件。
python-spider-downloads是我们要放置的目录
这里推荐使用os模块来获取当前的目录或者拼接路径
不推荐直接使用’F://xxx’ + '//python-spider-downloads’等方式
SAVE_PATH = os.path.join(os.path.abspath(‘.’), ‘python-spider-downloads’)
接下来就是为这个站点创建一个单独的文件夹了。这个站点文件夹的格式是xxxx-xx-xx-domain,比如2018-08-03-www.peersafe.cn。在此之前,我们需要写一个函数来提取出一个url链接的域名、相对路径、请求文件名和请求参数等等,这个在后续在根据资源文件的引用方式创建相对应的文件夹时也会用到。
比如输入http://www.peersafe.cn/index.html,那么将会输出:
{‘baseUrl’: ‘http://www.peersafe.cn’, ‘fullPath’: ‘http://www.peersafe.cn/’, ‘protocol’: ‘http://’, 'domain
': ‘www.peersafe.cn’, ‘path’: ‘/’, ‘fileName’: ‘index.html’, ‘ext’: ‘html’, ‘params’: ‘’}
部分代码如下:
REG_URL = r’^(https?😕/|//)?((?:[a-zA-Z0-9-]+.)+(?:[a-zA-Z0-9-:]+))((?😕[-_.a-zA-Z0-9]?))((?<=/)[-a-zA-Z0-9]+(?:.([a-zA-Z0-9]+))+)?((?:?[a-zA-Z0-9%&=]))$’
regUrl = re.compile(REG_URL)
…
‘’’
解析URL地址
‘’’
def parseUrl(url):
if not url:
return
res = regUrl.search(url)
在这里,我们把192.168.1.109:8080的形式也解析成域名domain,实际过程中www.baidu.com等才是域名,192.168.1.109只是IP地址
(‘http://’, ‘192.168.1.109:8080’, ‘/abc/images/111/’, ‘index.html’, ‘html’, ‘?a=1&b=2’)
if res is not None:
path = res.group(3)
fullPath = res.group(1) + res.group(2) + res.group(3)
if not path.endswith(‘/’):
path = path + ‘/’
fullPath = fullPath + ‘/’
return dict(
baseUrl=res.group(1) + res.group(2),
fullPath=fullPath,
protocol=res.group(1),
domain=res.group(2),
path=path,
fileName=res.group(4),
ext=res.group(5),
params=res.group(6)
)
‘’’
解析路径
eg:
basePath => F:\Programs\python\python-spider-downloads
resourcePath => /a/b/c/ or a/b/c
return => F:\Programs\python\python-spider-downloads\a\b\c
‘’’
def resolvePath(basePath, resourcePath):
解析资源路径
res = resourcePath.split(‘/’)
去掉空目录 /a/b/c/ => [a, b, c]
dirList = list(filter(lambda x: x, res))
目录不为空
if dirList:
拼接出绝对路径
resourcePath = reduce(lambda x, y: os.path.join(x, y), dirList)
dirStr = os.path.join(basePath, resourcePath)
else:
dirStr = basePath
return dirStr
上面的正则表达式REG_URL有点长,这个正则表达式能解析目前我遇到的各种url形式,如果有不能解析的,你可以自行补充,我测试过的url列表可以去我的github中查看。
首先一个最复杂的url链接(比如’http://192.168.1.109:8080/abc/images/111/index.html?a=1&b=2’)来说,我们想分别提取出http://, 192.168.1.109:8080, /abc/images/111/, index.html, ?a=1&b=2。提取出/abc/images/111/的目的是为以后创建目录做准备,index.html是写入网页内容的名字。
有需要的可以深入研究一下REG_URL的写法,如果有更好的或者看不懂的,我们可以一起探讨。
有了parseUrl函数之后,我们就可以把刚刚获取网页内容和写入文件联系起来了,代码如下:
首先创建这个站点的文件夹
urlDict = parseUrl(url)
print(‘分析的域名:’, urlDict)
domain = urlDict[‘domain’]
filePath = time.strftime(‘%Y-%m-%d’, time.localtime()) + ‘-’ + domain
如果是192.168.1.1:8000等形式,变成192.168.1.1-8000,:不可以出现在文件名中
filePath = re.sub(r’:', ‘-’, filePath)
SAVE_PATH = os.path.join(SAVE_PATH, filePath)
读取网页内容
webPage = urllib.request.urlopen(url)
data = webPage.read()
content = data.decode(‘UTF-8’)
print(‘> 网站内容抓取完毕,内容长度:’, len(content))
把网站的内容写下来
pageName = ‘’
if urlDict[‘fileName’] is None:
pageName = ‘index.html’
else:
pageName = urlDict[‘fileName’]
pageIndexDir = resolvePath(SAVE_PATH, urlDict[‘path’])
if not os.path.exists(pageIndexDir):
os.makedirs(pageIndexDir)
pageIndexPath = os.path.join(pageIndexDir, pageName)
print(‘主页的地址:’, pageIndexPath)
f = open(pageIndexPath, ‘wb’)
f.write(data)
f.close()
提取有用的资源链接
我们想要的资源是图片资源,js文件、css文件和字体文件。如果我们要对网页内容一一进行解析,利用分组,来捕获出我们想要的链接形式,比如images/1.png和scripts/lib/jquery.min.js。
代码如下:
REG_RESOURCE_TYPE = r’(?:href|src|data-original|data-src)="'[a-zA-Z0-9?=.]*["‘]’
re.S代表开启多行匹配模式
regResouce = re.compile(REG_RESOURCE_TYPE, re.S)
…
解析网页内容,获取有效的链接
content是上一步读取到的网页内容
contentList = re.split(r’\s+', content)
resourceList = []
for line in contentList:
resList = regResouce.findall(line)
if resList is not None:
resourceList = resourceList + resList
下载资源
在解析出资源链接后,我们要针对每一个资源链接进行检查,把它变成符合http请求的url格式,比如把images/1.png加上http头和刚刚的domain,也就是http://domain/images/1.png。
下面是对资源链接进行处理的代码:
./static/js/index.js
/static/js/index.js
static/js/index.js
//abc.cc/static/js
http://www.baidu/com/static/index.js
if resourceUrl.startswith(‘./’):
resourceUrl = urlDict[‘fullPath’] + resourceUrl[1:]
elif resourceUrl.startswith(‘//’):
如果你也是看准了Python,想自学Python,在这里为大家准备了丰厚的免费学习大礼包,带大家一起学习,给大家剖析Python兼职、就业行情前景的这些事儿。
一、Python所有方向的学习路线
Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
二、学习软件
工欲善其必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。
三、全套PDF电子书
书籍的好处就在于权威和体系健全,刚开始学习的时候你可以只看视频或者听某个人讲课,但等你学完之后,你觉得你掌握了,这时候建议还是得去看一下书籍,看权威技术书籍也是每个程序员必经之路。
四、入门学习视频
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。
四、实战案例
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
五、面试资料
我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
成为一个Python程序员专家或许需要花费数年时间,但是打下坚实的基础只要几周就可以,如果你按照我提供的学习路线以及资料有意识地去实践,你就有很大可能成功!
最后祝你好运!!!
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Python爬虫全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:python)
都能找到满意的工作。
成为一个Python程序员专家或许需要花费数年时间,但是打下坚实的基础只要几周就可以,如果你按照我提供的学习路线以及资料有意识地去实践,你就有很大可能成功!
最后祝你好运!!!
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Python工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Python爬虫全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:python)
[外链图片转存中…(img-jY2ixQom-1711066835630)]