作者:finallyliuyu 出处:博客园(博文转载请标明作者和出处)
编者按:本系列文章给出的网络数据采集方法、思路、和框架并无工业化应用价值,但足以满足各高校实验室在实验阶段爬去语料库,获取网络资源的需求。
欢迎老鸟指点,但是此篇博文的定位是“写个菜鸟,新手的”所以禁止无厘头的疯狗式乱骂。
在上一篇文章:《巧用C# webbrowser实现动态网页爬虫机器人》中,给出了一个综合利用webbrowser控件,MSHTML DOM,正则表达式,以及线程阻塞技术爬取动态网页链接的框架和方法。(注:所谓动态网页是指:目标网页的URL不能从当前网页中直接获得,而是要依赖JavaScript重新定向和生成。这种动态网页,我们有的时候可以通过查看页面<script>元素的内容找到蛛丝马迹,当更多时候,生成目标网页的URL的JS函数的源码不再当前网页,这时候就显得无能为力了)。《巧用C# webbrowser实现动态网页爬虫机器人》一文中的框架方法也同样适用于静态网页,可以说这个框架方法在某种程度上具有一定的通用性。此篇博文是对上一篇博文的一个补充,实现的功能是:从一级索引页获取到二级索引页首页的链接,在二级索引页首页获取当前页面中指向内容页面的URL链接,并且进行翻页获取内容页源码,同时完成二级索引页首页到次页的翻页,并以此类推。(注意:索引页,内容页的定义请见:《巧用C# webbrowser实现动态网页爬虫机器人》)
网络数据采集是网络挖掘的一个重要步骤。属于预处理工作范畴。一般分为两步,网络信息采集(即下载网页源码)和网络信息解析(即对网页源码进行解析,提取出BOI (block of interest))。本文是对《巧用C# webbrowser实现动态网页爬虫机器人》的补充,完成网络信息采集功能。
下面给出关键模块代码:
{
public string title;
public string url;
public string rawtext;
public ArticlePage()
{
title = string.Empty;
url = string.Empty;
rawtext = string.Empty;
}
}
public bool mysignal2;
public bool mysignal3;
public bool loading;//工作流按钮与webbrowser进行交互的通信按钮
public bool subloading;
public bool subloadingPer;
{
InitializeComponent();
mysignal1 = false;
mysignal2 = false;
mysignal3 = false;
loading = true;
subloading = true;
subloadingPer = true;
}
{
if (webBrowser1.ReadyState ==WebBrowserReadyState.Complete)
{
if (mysignal1)
{
if (!mysignal2&&!mysignal3)
{
loading = false;
}
else
{
if (mysignal2&&!mysignal3)
{
subloading = false;
}
if (mysignal3)
{
subloadingPer = false;
}
}
}
}
}
{
mysignal1 = true;
string dirCurPageUrl = string.Empty;//用于恢复目录页当前页的网页视图
List<ArticlePage> arListCurrentPage;
foreach (string s in issuesMap)
{
loading = true;
string tmpurl = s;
webBrowser1.Navigate(tmpurl);
while (loading == true)
{
Application.DoEvents();
}
arListCurrentPage = GetArticlePageInfoFromCurrentDirpage();
if (arListCurrentPage != null)
{
dirCurPageUrl = webBrowser1.Url.ToString();
mysignal3 = true;
foreach ( ArticlePage ap in arListCurrentPage)
{
webBrowser1.Navigate(ap.url);
subloadingPer = true;
while(subloadingPer)
{
Application.DoEvents();
}
ap.rawtext = webBrowser1.DocumentText;
}
InsertTitleUrlToDataBase(arListCurrentPage);
mysignal3 = false;
webBrowser1.Navigate(dirCurPageUrl);
loading = true;
while (loading == true)
{
Application.DoEvents();
}
}
mysignal2 = true;
while (AnchorNextPage())
{
subloading = true;
while(subloading)
{
Application.DoEvents();
}
arListCurrentPage = GetArticlePageInfoFromCurrentDirpage();
if (arListCurrentPage != null)
{
dirCurPageUrl = webBrowser1.Url.ToString();
mysignal3 = true;
foreach (ArticlePage ap in arListCurrentPage)
{
webBrowser1.Navigate(ap.url);
subloadingPer = true;
while (subloadingPer)
{
Application.DoEvents();
}
ap.rawtext = webBrowser1.DocumentText;
}
InsertTitleUrlToDataBase(arListCurrentPage);
mysignal3 = false;
webBrowser1.Navigate(dirCurPageUrl);
subloading = true;
while (subloading)
{
Application.DoEvents();
}
}
}
mysignal2 = false;
//获得当前页面的下一页链接
}
}
{
DataBaseManipulation dm = new DataBaseManipulation();
string conStr = "server=(local);database=xxxxx;uid=sa;pwd=xxx";
dm.ConstructConnection(conStr);
foreach (ArticlePage article in arlist)
{
dm.InsertToDataBase(article, "xxx");
}
}
{ //插入字符串
string sqlcommand=string.Format("insert into {0}(ArticlePageUrl,ArticlePageTitle,ArticlePageSource)values(@ArticlePageUrl,@ArticlePageTitle,@ArticlePageSource)",table);
//数据库参数构造与赋初值
SqlParameter ArticlePageTitle = new SqlParameter("@ArticlePageTitle", SqlDbType.VarChar, 400);
ArticlePageTitle.Value = article.title;
SqlParameter ArticlePageUrl = new SqlParameter("@ArticlePageUrl", SqlDbType.VarChar, 400);
ArticlePageUrl.Value = article.url;
SqlParameter ArticlePageSource = new SqlParameter("@ArticlePageSource", SqlDbType.Text);
ArticlePageSource.Value = article.rawtext;
SqlCommand cmd = new SqlCommand(sqlcommand, connection);
cmd.Parameters.Add(ArticlePageTitle);
cmd.Parameters.Add(ArticlePageUrl);
cmd.Parameters.Add(ArticlePageSource);
//打开数据库连接
OpenConnection();
try
{
//执行cmd操作
cmd.ExecuteNonQuery();
}
catch (System.Exception e)
{ //输出错误到记事本中
StreamWriter sw = new StreamWriter("D:\\myerror.txt", true, Encoding.Default);
sw.Write(e.Message);
sw.Close();
//一旦发生错误程序就停止运行,等待用户发现
Console.Read();
}
//关闭数据库连接
CloseConnection();
}
}
}
本地数据库(保存爬取的信息)视图:
小结与发散:笔者于本科毕设做过新闻类网页正文提取的课题,请见《新闻类网页正文提取系列》,并且从各大新闻门户网站的不同版面提取了四万余条新闻作为语料库,该语料库已经提供给网友下载,语料库说明以及下载地址见:《献给热衷于自然语言处理的业余爱好者的语料库》。 但是毕设当时,我对于动态网页提取方法并没有一个清晰的认识,所以可以提取的新闻版面上限制很大(必须是静态新闻网页才能提取)。有兴趣,并且对语料库有需求的网友,可以参考我的此篇博客,以及上一篇博客《巧用C# webbrowser实现动态网页爬虫机器人》,还有正文提取系列的一些博文,自己动手配置一个自动获取新闻语料库的小型爬虫。