来源: Mask 链接:
https://segmentfault.com/a/1190000015880780
遇到的需求
前段时间需要快速做个静态展示页面,要求是响应式和较美观。由于时间较短,自己动手写的话也有点麻烦,所以就打算上网找现成的。
中途找到了几个页面发现不错,然后就开始思考怎么把页面给下载下来。
由于之前还没有了解过爬虫,自然也就没有想到可以用爬虫来抓取网页内容。所以我采取的办法是:
打开的控制台,进入选项
找到选项,找到html文件,再
手动创建本地的目录
依次打开选项下的,一个文件就要
这个办法是我当时能想到的最好办法了。不过这种人为的办法有以下缺点:
手工操作,麻烦费时
一不小心就忘记保存哪个文件
难以处理路径之间的关系,比如一张图片, 它在中的引用方式是,这样我们以后还要手动去解决路径依赖关系
然后刚好前段时间接触了一点,想到可以写个来帮我自动抓取静态网站。于是就马上动手,参考相关资料等等。
下面跟大家详细分享一下写爬虫抓取静态网站的全过程。
前置知识储备
在下面的代码实践中,用到了python知识、正则表达式等等,核心技术是正则表达式。
我们来一一了解一下。
Python基础知识
如果你之前有过其他语言的学习经历,相信你可以很快上手这门语言。具体学习可以上查看python官方文档或者其他教程。
爬虫的概念
爬虫,按照我的理解,其实是一段自动执行的计算机程序,在中,它存在的前提是模拟用户在浏览器中的行为。
它的原理就是模拟用户访问,获取网页内容,然后分析网页内容,找出我们感兴趣的部分,并且最后处理数据。
流程图是:
现在流行的爬虫主流实现形式有以下几种:
自己抓取网页内容,然后自己实现分析过程
用别人写好的爬虫框架,比如
正则表达式
概念
正则表达式是由一系列元字符和普通字符组成的字符串,它的作用是根据一定的规则来匹配文本,最终可以对文本做出一系列的处理。
元字符是正则表达式中的保留字符,它有特殊的匹配规则,比如代表匹配,普通字符就是普通的等等。
比如在前端中,常见的一个操作就是判断用户的输入是否为空,这时候我们可以先通过正则表达式来进行匹配,先过滤掉用户输入的两边空白值,具体实现如下:
下面我们一起来具体了解一下正则表达式中的元字符。
正则表达式中的元字符
在上面,我们说过元字符是正则表达式中的保留字符,它有特殊的匹配规则,所以我们首先要了解经常出现的元字符。
匹配单个字符的元字符
代表匹配一个任意字符,除了(换行符),比如可以匹配任意的字母数字等等
表示字符组,里面可以有任意字符,它只会匹配当中的任意一个,比如可以匹配或或,这里值得注意的是,字符组里面的元字符有时候会被当成是普通字符,比如等等,它代表的仅仅是或或,而不是,,。
跟的含义相反,它的意思是匹配一个不属于里面的字符,而不是不匹配里面的字符,这两种说法虽然细微但是有很大差别,前者规定一定要匹配一个字符,这个切记。
例子:可以匹配等等,但是不匹配
提供计数功能的元字符
代表匹配,可以不匹配任何字符
代表匹配,至少匹配1次
代表匹配
代表匹配,如表示a至少匹配3-5次
提供位置的元字符
代表匹配字符串开头,如表示a要出现在字符串开头,bcd则不匹配
代表匹配字符串结尾, 如表示A要出现在字符串结尾,ABAB则不匹配
其他元字符
代表一个范围,可以匹配任意的子表达式,比如可以匹配abc或者def,不匹配abd
代表分组,它的作用有界定子表达式的范围和与提供功能的元字符相结合,比如代表可以匹配1次或1次以上的abc或者defdef,如abcabcabc,def
代表反向引用,i可以为1/2/3等整数,它的含义是指向上一个()里面匹配的内容。比如匹配,如果匹配成功的话,的内容是abc,的内容是12或者空。反向引用通常用在匹配或者中
环视
我理解的环视是界定当前匹配子表达式的左边文本和右边文本出现的情况,环视本身不会占据匹配的字符,它是当前子表达式的匹配规则但是本身不算进匹配文本。而我们上面说的元字符都代表一定的规则和占据一定的字符。环视可分为四种:肯定顺序环视、否定顺序环视、肯定逆序环视和否定逆序环视。它们的工作流程如下:
:先找到环视中的文本在右侧出现的初始位置,然后从匹配到的右侧文本的最左的位置开始匹配字符
:先找到环视中的文本在右侧没有出现的初始位置,然后从匹配到的右侧文本的最左的位置开始匹配字符
:先找到环视中的文本在左侧出现的初始位置,然后从匹配到的左侧文本的最右的位置开始匹配字符
:先找到环视中的文本在左侧没有出现的初始位置,然后从匹配到的左侧文本的最右的位置开始匹配字符
肯定顺序环视
肯定顺序环视匹配成功的条件是当前的子表达式能够匹配右侧文本,它的写法是,...代表要环视的内容。比如正则表达式的意思是匹配包含hello的文本,它只匹配位置,不匹配具体字符,匹配到位置之后,才真正匹配要占用的字符是he,所以后面可以具体匹配llo等。
对于而言,hello world可以匹配成功,而hell world则匹配失败。具体代码如下:
否定顺序环视
否定顺序环视匹配成功的条件是当前的子表达式不能匹配右侧文本,它的写法是,...代表要环视的内容,还是上面的例子,比如正则表达式的意思是匹配不是hello的文本,找到位置,然后匹配he。
例子如下:
肯定逆序环视
肯定逆序环视匹配成功的条件是当前的子表达式能够匹配左侧文本,它的写法是,...代表要环视的内容,比如正则表达式的意思是匹配包含-python的子表达式,并且它的左侧必须出现hello,hello只匹配位置,不匹配具体字符,真正占用的字符是后面的-python。
例子如下:
否定逆序环视
否定逆序环视匹配成功的条件是当前的子表达式不能匹配左侧文本,它的写法是,...代表要环视的内容,比如正则表达式的意思是匹配包含-python的子表达式,并且它的左侧必须不能出现hello。
例子如下:
环视在对字符串插入某些字符很有效,你可以利用它来匹配位置,然后插入对应的字符,而不需要对原来的文本进行替换。
捕获分组
在正则表达式中,分组可以帮助我们提取出想要的特定信息。
指明分组很简单,只需要在想捕获的表达式中两端加上就可以了。在python中,我们可以用来获取到所有的分组。
默认的中都指明了一个分组,分组序号为i,,分别用来获取。
如果不想捕获分组可以使用来指明。
具体例子如下:
贪婪匹配
贪婪匹配是指正则表达式尽可能匹配多的字符,也就是趋于最大长度匹配。
正则表达式默认是贪婪模式。
例子如下:
由上可以看到它匹配的是而不是刚开始的。那如果我们只是想匹配刚开始的,这时候我们可以利用正则表达式的非贪婪模式。
非贪婪匹配正好与贪婪匹配相反,它是指尽可能匹配少的字符,只要匹配到了就结束。要使用贪婪模式,仅需要在量词后面加上一个问号()就可以。
还是刚刚那个例子:
由上可以看到这是我们刚刚想要匹配的效果。
进入开发
有了上面的基础知识,我们就可以进入开发环节了。
我们想实现的最终效果
本次我们的最终目的是写一个简单的python爬虫,这个爬虫能够下载一个静态网页,并且在保持网页引用资源的相对路径下下载它的静态资源(如)。测试网站为,效果图如下:
开发流程
我们的总体思路是先获取到网页的内容,然后利用正则表达式来提取我们想要的资源链接,最后就是下载资源。
获取网页内容
我们选用自带的来发出,或者你可以采用第三方请求库。
获取内容的部分代码如下:
获取到内容之后,我们需要把它保存下来,也就是写到本地磁盘上。我们定义一个路径,代表专门放置爬虫下载的文件。
接下来就是为这个站点创建一个单独的文件夹了。这个站点文件夹的格式是,比如。在此之前,我们需要写一个函数来提取出一个的域名、相对路径、请求文件名和请求参数等等,这个在后续在根据资源文件的引用方式创建相对应的文件夹时也会用到。
比如输入,那么将会输出:
部分代码如下:
上面的正则表达式有点长,这个正则表达式能解析目前我遇到的,如果有不能解析的,你可以自行补充,我测试过的url列表可以去我的github中查看。
首先一个最复杂的url链接(比如)来说,我们想分别提取出, , , , 。提取出的目的是为以后创建目录做准备,是写入网页内容的名字。
有需要的可以深入研究一下的写法,如果有更好的或者看不懂的,我们可以一起探讨。
有了函数之后,我们就可以把刚刚获取网页内容和写入文件联系起来了,代码如下:
提取有用的资源链接
我们想要的资源是。如果我们要对网页内容一一进行解析,利用分组,来捕获出我们想要的链接形式,比如和。
代码如下:
下载资源
在解析出资源链接后,我们要针对每一个资源链接进行检查,把它变成符合http请求的url格式,比如把加上和刚刚的,也就是。
下面是对资源链接进行处理的代码:
接着就是对每个规范的资源链接进行解析(),提取出它要存放的目录和文件名等等,然后创建对应的目录。
在这里,我也处理了引用的其他网站的资源。
下载的函数的代码是:
以上就是我们的开发全过程。
知识总结
本次开发用到的技术
利用来发网络请求
利用正则表达式来解析资源链接
利用来处理文件路径问题
心得体会
这篇文章也算是我这段时间学习的一个实践总结,顺便记录下正则表达式的知识。同时我也希望能够帮助到那些想学习正则表达式和爬虫的小伙伴。
该python爬虫的源代码已经放在github上(https://github.com/qzcmask/python-codes/blob/master/static-resource-spider.py),有兴趣的小伙伴可以上去看看,满意的可以顺便给个,感谢支持。
(完)
看完本文有收获?请转发分享给更多人
关注「Python那些事」,做全栈开发工程师
领取专属 10元无门槛券
私享最新 技术干货