遇到的需求
前段时间需要快速做个静态展示页面,要求是响应式和较美观。由于时间较短,自己动手写的话也有点麻烦,所以就打算上网找现成的。
中途找到了几个页面发现不错,然后就开始思考怎么把页面给下载下来。
由于之前还没有了解过爬虫,自然也就没有想到可以用爬虫来抓取网页内容。所以我采取的办法是:
-
打开
chrome
的控制台,进入Application
选项 -
找到
Frames
选项,找到html文件,再右键Save As...
-
手动创建本地的
js/css/images
目录 -
依次打开
Frames
选项下的Images/Scripts/Stylesheets
,一个文件就要右键Save As...
这个办法是我当时能想到的最好办法了。不过这种人为的办法有以下缺点:
-
手工操作,麻烦费时
-
一不小心就忘记保存哪个文件
-
难以处理路径之间的关系,比如一张图片
a.jpg
, 它在html
中的引用方式是images/banner/a.jpg
,这样我们以后还要手动去解决路径依赖关系
然后刚好前段时间接触了一点python
,想到可以写个python爬虫
来帮我自动抓取静态网站。于是就马上动手,参考相关资料等等。
下面跟大家详细分享一下写爬虫抓取静态网站的全过程。
前置知识储备
在下面的代码实践中,用到了python知识、正则表达式等等,核心技术是正则表达式。
我们来一一了解一下。
Python基础知识
如果你之前有过其他语言的学习经历,相信你可以很快上手python
这门语言。具体学习可以上查看python官方文档或者其他教程。
爬虫的概念
爬虫,按照我的理解,其实是一段自动执行的计算机程序,在web领域
中,它存在的前提是模拟用户在浏览器中的行为。
它的原理就是模拟用户访问web网页
,获取网页内容,然后分析网页内容,找出我们感兴趣的部分,并且最后处理数据。
流程图是:
现在流行的爬虫主流实现形式有以下几种:
-
自己抓取网页内容,然后自己实现分析过程
-
用别人写好的爬虫框架,比如
Scrapy
正则表达式
概念
正则表达式是由一系列元字符和普通字符组成的字符串,它的作用是根据一定的规则来匹配文本,最终可以对文本做出一系列的处理。
元字符是正则表达式中的保留字符,它有特殊的匹配规则,比如*
代表匹配0到无穷多次
,普通字符就是普通的abcd
等等。
比如在前端中,常见的一个操作就是判断用户的输入是否为空,这时候我们可以先通过正则表达式来进行匹配,先过滤掉用户输入的两边空白值,具体实现如下:
-
function trim(value) {
-
return value.replace(/^\s+|\s+$/g, '')
-
}
-
// 输出 => "Python爬虫"
-
trim(' Python爬虫 ');
下面我们一起来具体了解一下正则表达式中的元字符。
正则表达式中的元字符
在上面,我们说过元字符是正则表达式中的保留字符,它有特殊的匹配规则,所以我们首先要了解经常出现的元字符。
匹配单个字符的元字符
-
.
代表匹配一个任意字符,除了\n
(换行符),比如可以匹配任意的字母数字等等 -
[...]
表示字符组,里面可以有任意字符,它只会匹配当中的任意一个,比如[abc]
可以匹配a
或b
或c
,这里值得注意的是,字符组里面的元字符有时候会被当成是普通字符,比如[-*?]
等等,它代表的仅仅是-
或*
或?
,而不是-代表区间
,*代表0到无穷次匹配
,?代表0或1次匹配
。 -
[^...]
跟[...]
的含义相反,它的意思是匹配一个不属于[...]
里面的字符,而不是不匹配[...]
里面的字符,这两种说法虽然细微但是有很大差别,前者规定一定要匹配一个字符,这个切记。
例子:[^123]
可以匹配4/5/6
等等,但是不匹配1/2/3
提供计数功能的元字符
-
*
代表匹配0次到无穷次
,可以不匹配任何字符 -
+
代表匹配1次到无穷次
,至少匹配1次 -
?
代表匹配0次或1次
-
{min, max}
代表匹配min次到max次
,如a{3, 5}
表示a至少匹配3-5次
提供位置的元字符
-
^
代表匹配字符串开头,如^a
表示a要出现在字符串开头,bcd则不匹配 -
$
代表匹配字符串结尾, 如A$
表示A要出现在字符串结尾,ABAB则不匹配
其他元字符
-
|
代表一个范围,可以匹配任意的子表达式,比如abc|def
可以匹配abc或者def,不匹配abd -
(...)
代表分组,它的作用有界定子表达式的范围和与提供功能的元字符相结合,比如(abc|def)+
代表可以匹配1次或1次以上的abc或者defdef,如abcabcabc,def -
\i
代表反向引用,i可以为1/2/3等整数,它的含义是指向上一个()里面匹配的内容。比如匹配(abc)+(12)*\1\2
,如果匹配成功的话,\1
的内容是abc,\2
的内容是12或者空。反向引用通常用在匹配""
或者''
中
环视
我理解的环视是界定当前匹配子表达式的左边文本和右边文本出现的情况,环视本身不会占据匹配的字符,它是当前子表达式的匹配规则但是本身不算进匹配文本。而我们上面说的元字符都代表一定的规则和占据一定的字符。环视可分为四种:肯定顺序环视、否定顺序环视、肯定逆序环视和否定逆序环视。它们的工作流程如下:
-
肯定顺序环视
:先找到环视中的文本在右侧出现的初始位置,然后从匹配到的右侧文本的最左的位置开始匹配字符 -
否定顺序环视
:先找到环视中的文本在右侧没有出现的初始位置,然后从匹配到的右侧文本的最左的位置开始匹配字符 -
肯定逆序环视
:先找到环视中的文本在左侧出现的初始位置,然后从匹配到的左侧文本的最右的位置开始匹配字符 -
否定逆序环视
:先找到环视中的文本在左侧没有出现的初始位置,然后从匹配到的左侧文本的最右的位置开始匹配字符
肯定顺序环视