利用Php爬虫备份自己的CSDN博客

  |  
 阅读次数

自己写备份博客的原因

最近逛自己博客的时候发现左边经常有个小广告,十分恶心,看着很烦。同时自己最近也准备自己搭一个博客,所以就想着把自己CSDN博客上的文章备份下来。本着偷懒至上的原则⁄(⁄ ⁄•⁄㉨⁄•⁄ ⁄)⁄ ,先去百度了一下有木有现成的博客爬虫软件。发现有个叫豆约翰的软件,当时的心情是很激动的有木有φ(゜▽゜*)♪,然而打开的一瞬间居然要收费,还是按月收费。尼玛,程序员的本性简直不能忍。So,自己写了一个github开源项目CSDNSpider,接下来讲解一下思路吧。

项目地址:CSDNSpider

Php爬虫那些事儿

爬虫需要了解的函数

  • fopen,用于打开需要爬虫的url,获得一个流
  • stream_get_contents,用于将fopen获得的流处理成字符串
  • preg_match,用于正则表达式匹配
  • curl,这里用作图片的下载
  • preg_replace,用于替换符合正则表达式的内容
    当然还有最最重要的 正则表达式,详情可以点击教程
    这里函数的作用就只进行简单说明了,各位先更深入了解可以去官网查看文档。

整个爬虫的思路

关于爬虫首先我们要理清楚我们要做的是什么,需要构造那些函数?
整理后我们可以得到以下函数,当然因人而异,可能你会有其它不同的看法

  • SpiderGo,爬虫主函数
  • getWebContent,用于获得网站的主要内容
  • getPageNumber,用于获得网站文章页面的总页数
  • getArticleList,用于获文章列表包括文章的链接和题目
  • getArticleContent,用于获得文章的内容
  • getImage,获取文章中图片的链接
  • replaceImgUrl,替换文章中的图片连接为本地连接
  • downloadImg,下载图片

还有些函数就不多做说明了,其实大致文章爬虫主题上就是这些部分,根据不同个网站的需要进行增删部分辅助性的函数

爬虫的一些基本常识

爬虫中所谓的翻页、查看文章详情内容等这些点击操作其实都是通过url实现的,所以爬虫的核心点在我看来就是url+正则表达式,就拿我CSDN博客来举例子
打开我的CSDN个人博客页面,url栏是这样显示的:http://blog.csdn.net/shanamaid
我们可以看到url的格式为:

1
“http://blog.csdn.net/”+用户名

那么我们要如何通过url实现翻页呢?
我们先翻第二页看看,url栏是这样显示的:

1
http://blog.csdn.net/ShanaMaid/article/list/2

So,我们得到结论,文章翻页的url格式是这样的:

1
http://blog.csdn.net/用户名/article/list/页数

再来,我们把这个url打开会得到什么东西呢?

1
http://blog.csdn.net/ShanaMaid/article/list/1

很显然,

1
http://blog.csdn.net/ShanaMaid/article/list/1

打开的页面和

1
http://blog.csdn.net/shanamaid

是一样的,也就是说,这两个链接是等价的,但是为了统一url格式,我们在写爬虫的时候肯定用的是

1
http://blog.csdn.net/ShanaMaid/article/list/1

打开页面而不是

1
http://blog.csdn.net/shanamaid。

接下来我们打开文章详情页面看看,

1
http://blog.csdn.net/shanamaid/article/details/52441330

分析得到文章详情页面得到:

1
http://blog.csdn.net/用户名/article/details/文章ID编号

我们再分析一下文章列表页面发现

1
2
3
4
<span class="link_title"><a href="/shanamaid/article/details/52441330">
<font color="red">[置顶]</font>
ReactJS学习之一篇博客教你入门ReactJS
</a></span>

发现我们需要的文章的题目和链接都在class=”link_title”的span里面,所以我们可以用一个正则表达式把它提取出来

1
<span class="link_title">[\w\W]*?<\/span>

然后再用

1
<\/?[^>]+>

可以去掉标签得到题目 [置顶]ReactJS学习之一篇博客教你入门ReactJS

1
[0-9]{5,}

可以提取出文章标号,得到52441330

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//获取文章列表
function getArticleList($page,$username){
$url = 'http://blog.csdn.net/'.$username.'/article/list/'.$page;
$content = getWebContent($url);
$tag = '/<span class="link_title">[\w\W]*?<\/span>/';
$tag_name = '/<\/?[^>]+>/';//去除html标签
$tag_url = '/[0-9]{5,}/';//提取编号
preg_match_all($tag, $content, $result);//提取出包含有文章题目和编号的内容
for ($i=0; $i < sizeof($result[0]); $i++){
preg_match($tag_url,$result[0][$i],$number);//提出出文章题目编号
$result[0][$i]=preg_replace($tag_name,'',$result[0][$i]);//提取出文章题目
$result[1][$i]=$number[0];
}
return $result;
}

同理,我们观看文章详情页面发现都在id=”article_content”的div里面,同时这个块后面一行内容为

1
<!-- Baidu Button BEGIN -->

所以我们可以这样写正则表达式

1
<div id="article_content" class="article_content">[\w\W]*<\/div>[\w\W]*<!-- B

则提取文章内容的函数应该这样写

1
2
3
4
5
6
7
8
// 获取文章内容
function getArticleContent($number,$username){
$url = "http://blog.csdn.net/".$username."/article/details/".$number;
$content = getWebContent($url);
$tag = '/<div id="article_content" class="article_content">[\w\W]*<\/div>[\w\W]*<!-- B/'; //匹配正文内容
preg_match($tag,$content,$main);//提出正文内容
return $main[0];
}

再看看总页数,观察后可以很容易写出下列函数

1
2
3
4
5
6
7
8
9
//获取文章总页数
function getPageNumber($content){
$tag = '/共[0-9]+页/';
$tagNumber = '/[0-9]+/';
preg_match($tag, $content,$result);
preg_match($tagNumber, $result[0],$sumPage);
return $sumPage[0];
}

同样我们继续观察img的格式,可以得出正则表达式

1
http:\/\/img.blog.csdn.net\/.*?\/Center

提取图片的函数为

1
2
3
4
5
6
//提取-文章内容中的图片
function getImage($content){
$tag = '/http:\/\/img.blog.csdn.net\/.*?\/Center/';
preg_match_all($tag, $content, $result);//筛选出图片
return $result[0];//图片链接数组
}

然后是对提取出的图片的链接进行下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//下载图片
function downloadImg($url,$id,$imgName){
if(!is_dir("Img\\".$id))
{
mkdir("Img\\".$id);
}
for ($i=0; $i <sizeof($url) ; $i++) {
$curl = curl_init();
curl_setopt($curl,CURLOPT_URL, $url[$i]);
curl_setopt ($curl, CURLOPT_HEADER, false);
curl_setopt ($curl, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($curl);
curl_close($curl);
file_put_contents($imgName[$i],$result);
}
}

由于下载了图片,为了能够离线观看文章,所以还得把文章中img的src中的链接替换为本地连接,可以用下面函数

1
2
3
4
5
6
7
8
9
10
11
//替换-文章内容中的图片链接为本地
function replaceImgUrl($content,$local_url){
$tag = '/http:\/\/img.blog.csdn.net\/.*?\/Center/';
$tag_array = array();
for ($i=0; $i < sizeof($local_url) ; $i++) {
$tag_array[$i] = $tag;
}
$count = 1;
$st = preg_replace($tag_array, $local_url, $content,$count);
return $st;
}

整个爬虫大概就是这样了,最后再提示一遍,完整的文件在我的github上面
CSDNSpider