Dirain'blog
中国最年轻的编程爱好者
随笔- 17 文章- 0 评论- 647
博客园
首页
新随笔
联系
管理
订阅
浅谈文章采集,就拿博客园热门文章举例!
以前写了篇“百度视频采集"的思路简介,看到唯一一个人留言希望我总结一下新闻采集。今天就拿博客园的热门文章采集做个例子。说明前我得声明一点,经过在博客园混了几个月后,发现博客园首页发布的文章一般都是高手,很有参考价值。可我是一个新手,我请大家此文章的任何质疑直接留言,因为您发现问题不说出来,可能我永远会认为自己写的是正确的。
下面进入正题。首先需要注意的是采集网页上数据的唯一方式是必须
获取需要采集页面的源代码
,这点想必大家很清楚。因为我们不知道对方网站的数据库服务器连接方式,我们只能在页面的源代码中找寻我们想要的东西。这无疑就是对大量字符串进行处理,那么我们如何处理这些含有大量html标记与内容的代码呢?可能解决问题的方式有很多种,但我认为用
正则表达式
来解决这个问题会很好。
通过上面的话,我谈到了两个知识点,我们来总结一下流程。
1.获取需要采集页面的源代码。
2.利用正则表达式处理这些代码中我们想要的内容。
下面做一些准备工作,写一个实体类存储文章的信息。例如:标题、作者、发布时间、浏览次数,等。
文章信息实体类
using
System;
using
System.Collections.Generic;
using
System.Text;
namespace
Plug.Article.Entity
{
/**/
///
<summary>
///
采集文章信息,部分属性可留空。标题与地址如为空则默认赋值时引发异常
///
</summary>
[Serializable]
public
class
Article
{
private
string
category;
/**/
///
<summary>
///
文章类别
///
</summary>
public
string
Category
{
get
{
return
category; }
set
{ category
=
value; }
}
private
string
url;
/**/
///
<summary>
///
文章连接地址
///
</summary>
public
string
Url
{
get
{
return
url;
}
set
{
if
(value
==
""
||
value.Length
<=
0
)
{
throw
new
ApplicationException(
"
文章的连接地址不能为空!
"
);
}
url
=
value;
}
}
private
string
title;
/**/
///
<summary>
///
文章标题
///
</summary>
public
string
Title
{
get
{
return
title;
}
set
{
if
(value
==
""
||
value.Length
<=
0
)
{
throw
new
ApplicationException(
"
文章的标题不能为空!
"
);
}
title
=
value;
}
}
private
int
views;
/**/
///
<summary>
///
文章浏览次数
///
</summary>
public
int
Views
{
get
{
return
views;
}
set
{
views
=
value;
}
}
private
int
replys;
/**/
///
<summary>
///
文章评论次数
///
</summary>
public
int
Replys
{
get
{
return
replys;
}
set
{
replys
=
value;
}
}
private
string
datatime;
/**/
///
<summary>
///
文章发布日期
///
</summary>
public
string
Datatime
{
get
{
return
datatime;
}
set
{
datatime
=
value;
}
}
private
string
author;
/**/
///
<summary>
///
文章作者
///
</summary>
public
string
Author
{
get
{
return
author;
}
set
{
author
=
value;
}
}
private
string
site;
/**/
///
<summary>
///
文章作者网站、文章采集网站
///
</summary>
public
string
Site
{
get
{
return
site;
}
set
{
site
=
value;
}
}
}
}
获取采集网页源代码的方式,也很简单,我单独做成了一个类。
获取网页源代码
using
System;
using
System.Collections.Generic;
using
System.Text;
using
System.Net;
namespace
Plug.Article
{
/**/
///
<summary>
///
网页操作类
///
</summary>
public
class
HTML
{
/**/
///
<summary>
///
获取网页源代码
///
</summary>
///
<param name="url">
URL路径
</param>
///
<returns></returns>
public
string
GetHTML(
string
url)
{
WebClient web
=
new
WebClient();
byte
[] buffer
=
web.DownloadData(url);
return
Encoding.Default.GetString(buffer);
}
}
}
拿到源代码,该进入关键步骤了,写正则表达式采集数据。在采集之前我们需要了解网页源代码的特征,如果都不知道我们想要什么,恐怕无法写出正则表达式。我们要采集的页面是 http://www.cnblogs.com/TopPosts.aspx 这个页面,博客园文章阅读排行榜。
今日阅读排行、
昨日阅读排行
等信息。但我们要得到的只是如下信息:
·
我在外资公司的2个月
(阅读:1909) (评论:21) (2008-6-25 13:44)
yesry
·
为什么尽量避免使用触发器?
(阅读:1490) (评论:15) (2008-6-25 03:35)
凉面
·
Discuz!NT 系统架构分析
(阅读:1391) (评论:18) (2008-6-25 12:35)
韩龙
·
硬盘那点事儿
(阅读:1342) (评论:15) (2008-6-25 11:16)
李战
只需要得到标题、阅读次数、评论、时间、作者即可。那么我们就来分析一下关键信息的源代码特征。
<
tr
>
<
td
style
="width:80%"
>
·
<
a
id
="ctl00_cphMain_TopPostsPaged1_PostsRepeater_ctl01_lnkTitle"
href
="http://www.cnblogs.com/yesry/archive/2008/06/25/1229587.html"
target
="_blank"
>
我在外资公司的2个月
</
a
>
<
span
class
="title"
>
(阅读:1909) (评论:21) (2008-6-25 13:44)
</
span
>
</
td
>
<
td
height
="20"
>
<
a
id
="ctl00_cphMain_TopPostsPaged1_PostsRepeater_ctl01_lnkAuthor"
href
="http://yesry.cnblogs.com/"
>
yesry
</
a
>
</
td
>
</
tr
>
这就是我们需要采集信息的源代码。在开始写正则表达式之前我需要说明一点,我们都知道,这些内容也是动态产生的。所以它们的格式肯定是固定的。这样我们就可以利用一个正则表达式正确的采集到该页面所有信息。我觉得没必要在这片文章中详细解释正则表达式的含义,因为这需要多练习。
Regex regexarticles
=
new
Regex(
"
.+· <a\\s+id=\
"
.
+
\
"
href=\
"
(
?<
url
>
.
+
)\
"
\\s+target=\
"
_blank\
"
>(?<title>.+)</a> <span\\s+class=\
"
.
+
\
"
>\\(阅读:(?<views>\\d+)\\).*\\(评论:(?<reply>\\d+)\\).*\\((?<time>.+)\\)</span>\\s*</td>\\s*<td\\s+height=\
"
\\d
+
\
"
>\\s+<a\\s+id=\
"
.
+
\
"
href=\
"
(
?<
blog
>
.
+
)\
"
>(?<author>.+)</a>
"
);
这些让您可能阅读起来很吃力,但我想学过正则表达式的人会嘲笑我,因为我的正则写的不够灵活。我要为没有接触过正则表达式的朋友简单介绍下,我也只是刚入门。
正则表达式就是通过描述字符串的特征来进行匹配。
这也是我们为什么需要分析页面源代码的原因。至于怎么去匹配,其实也不难,我提供一些文章给各位参考。
正则表达式学习笔记:
http://hedong.3322.org/archives/000244.html
正则表达式30分钟入门:http://unibetter.com/deerchao/zhengzhe-biaodashi-jiaocheng-se.htm
我就是通过这两篇文章入门,并利用正则表达式写出了我喜欢的程序。至于更多的文章可以去网络寻找。
上面说到的是关键的正则表达式,下面还需要说一下怎么去取。
采集关键代码
//
网页操作对象,我用来获取网页源码
HTML html
=
new
HTML();
//
对博客园每日排行数据进行采集
string
htmlcode
=
html.GetHTML(
"
http://www.cnblogs.com/TopPosts.aspx
"
,
"
utf-8
"
);
//
提取博客园排行文章信息的正则表达式
Regex regexarticles
=
new
Regex(
"
.+· <a\\s+id=\
"
.
+
\
"
href=\
"
(
?<
url
>
.
+
)\
"
\\s+target=\
"
_blank\
"
>(?<title>.+)</a> <span\\s+class=\
"
.
+
\
"
>\\(阅读:(?<views>\\d+)\\).*\\(评论:(?<reply>\\d+)\\).*\\((?<time>.+)\\)</span>\\s*</td>\\s*<td\\s+height=\
"
\\d
+
\
"
>\\s+<a\\s+id=\
"
.
+
\
"
href=\
"
(
?<
blog
>
.
+
)\
"
>(?<author>.+)</a>
"
);
//
所有匹配表达式的内容
MatchCollection marticles
=
regexarticles.Matches(htmlcode);
/**/
///
遍历匹配内容
foreach
(Match m
in
marticles)
{
Entity.Article test
=
new
Entity.Article();
test.Category
=
"
博客园热门文章
"
;
//
设置分类
test.Title
=
m.Groups[
"
title
"
].Value;
//
设置标题
test.Url
=
m.Groups[
"
url
"
].Value;
//
设置连接
test.Views
=
int
.Parse(m.Groups[
"
views
"
].Value);
//
设置浏览次数
test.Replys
=
int
.Parse(m.Groups[
"
reply
"
].Value);
//
设置评论次数
test.Datatime
=
m.Groups[
"
time
"
].Value;
//
设置发布时间
test.Author
=
m.Groups[
"
author
"
].Value;
//
设置作者
test.Site
=
m.Groups[
"
blog
"
].Value;
//
设置文章出处
list.Add(test);
}
MatchCollection marticles = regexarticles.Matches(htmlcode);
通过此句代码获取多个匹配的内容。
foreach (Match m in marticles)
循环时需要用Match类取一条匹配内容,m.Groups["title"].Value 取出指定分组中的信息,这个分组是指
(?<title>.+) ,“?<title>”
这就是给匹配内容分组为title的代码。代码就是这样了,没有什么技术含量,来总结一下做采集的一个流程吧。
1.取指定页面的源代码
2.分析源代码中我们想要获得内容的特征
3.通过特征写出正则表达式进行匹配
4.遍历匹配内容装入集合
流程就是这样,我把整个案例的代码打包供大家参考,如有什么问题请留言。
源码下载
采集出的数据可能与博客园显示顺序不太一致,因为是整个页面的文章,没有做分类处理。但数据绝对是一致的。
posted on 2008-06-25 23:11
Dirain
阅读(1924)
评论(19)
编辑
收藏
发表评论
回复
引用
查看
#1楼
2008-06-25 23:41 |
lexus
我觉得做采集的问题是如何组件化,定时的抓取,
回复
引用
查看
#2楼
[
楼主
] 2008-06-25 23:50 |
Dirain
--引用--------------------------------------------------
lexus: 我觉得做采集的问题是如何组件化,定时的抓取,
--------------------------------------------------------
没有深入研究过。
不过最近的目标是做一个自动投简历的东东供自己使用。
回复
引用
查看
#3楼
2008-06-25 23:51 |
crazy