首页 新闻 赞助 找找看

c#的爬虫程序

0
悬赏园豆:200 [已解决问题] 解决于 2011-04-25 09:07

能爬到某一页面的所有内容即可。

主要给出通过url取到相关页面内容就好了,谢谢!高分送上。

茂茂的主页 茂茂 | 老鸟四级 | 园豆:2892
提问于:2011-04-23 16:42
< >
分享
最佳答案
0

你好,获取网页内容有多种方法,这里直接上代码了,如下:

1)如上所说 WebClient 类可以做到,看代码:

try
        {
            string url = @"http://www.baidu.com";

            WebClient client = new WebClient();
            //获取或设置用于对Internet资源的请示进行身份验证的网络凭据
            client.Credentials = CredentialCache.DefaultCredentials;

            //从指定网站下载数据
            byte[] data = client.DownloadData(url);

            //如果获取网站页面采用的是GB2312,则使用这句
            //string html = Encoding.Default.GetString(data);

            //如果获取网站页面采用的是UTF-8,则使用这句
            //string html = Encoding.UTF8.GetString(data);

            //使用默认编码
            string html = Encoding.Default.GetString(data);

            Response.Write(html);
          
        }
        catch (WebException webEx)
        {
           
        }

2)WebRequest 获取网页内容,代码如下:

try
        {
            string url = @"http://www.baidu.com";

            //构造web请示,发送请示,获取响应
            WebRequest request = WebRequest.Create(url);
            WebResponse response = request.GetResponse();

            //获得流
            StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.Default);
            string html = sr.ReadToEnd();

            Response.Write(html);

            response.Close();
        }
        catch (Exception ex)
        {
           
            throw ex;
        }

3)更多内容,可以入群讨论. QQ群:149385300

收获园豆:55
DYStudio.Net | 小虾三级 |园豆:1747 | 2011-04-23 18:35
你的方法不错。那个我看了关于网络爬虫的方法,那个去内容的原理跟你的一样,但是会把页面所涉及到的url的内容都取到。
茂茂 | 园豆:2892 (老鸟四级) | 2011-04-24 16:58
你把网页内容读取到了以后,可以用正则表达式过滤的.
DYStudio.Net | 园豆:1747 (小虾三级) | 2011-04-24 17:05
正则表达式是我的弱项,要再去学学!
茂茂 | 园豆:2892 (老鸟四级) | 2011-04-25 09:05
其他回答(3)
0

WebClient就可以啊 简单好用

收获园豆:5
leo刘 | 园豆:156 (初学一级) | 2011-04-23 16:58
0

Copy from MSDN

http://msdn.microsoft.com/en-us/library/system.net.webclient(v=vs.80).aspx#Y1941

using System;
using System.Net;
using System.IO;

public class Test
{
public static void Main (string[] args)
{
if (args == null || args.Length == 0)
{
throw new ApplicationException ("Specify the URI of the resource to retrieve.");
}
WebClient client
= new WebClient ();

// Add a user agent header in case the
// requested URI contains a query.

client.Headers.Add (
"user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");

Stream data
= client.OpenRead (args[0]);
StreamReader reader
= new StreamReader (data);
string s = reader.ReadToEnd ();
Console.WriteLine (s);
data.Close ();
reader.Close ();
}
}

收获园豆:20
Jerry Chou | 园豆:2642 (老鸟四级) | 2011-04-23 18:32
0

可以说,已经实现了爬虫的功能。只是它存在一个效率问题,下载速度可能很慢。这是两方面的原因造成的:

1.分析和下载不能同步进行。

2.只是单线程下载

多线程在C#中并不难实现。它有一个命名空间:System.Threading,提供了多线程的支持要开启一个新线程,需要以下的初始化:

ThreadStart startDownload = new ThreadStart( DownLoad );

//线程起始设置:即每个线程都执行DownLoad(),注意:DownLoad()必须为不带有参数的方法

Thread downloadThread = new Thread( startDownload ); //实例化要开启的新类

downloadThread.Start();//开启线程

 

1.线程数量我们可以通过for循环来实现,就如同当年初学编程的打点程序一样。

比如已知用户指定了n(它是一个int型变量)个线程吧,可以用如下方法开启五个线程。

Thread[] downloadThread;

//声名下载线程,这是C#的优势,即数组初始化时,不需要指定其长度,可以在使用时才指定。

这个声名应为类级,这样也就为其它方法控件它们提供了可能

ThreadStart startDownload = new ThreadStart( DownLoad );

//线程起始设置:即每个线程都执行DownLoad()

downloadThread = new Thread[ n ];//为线程申请资源,确定线程总数

for( int i = 0; i < n; i++ )//开启指定数量的线程数

{
downloadThread[i] = new Thread( startDownload );//指定线程起始设置
downloadThread[i].Start();//逐个开启线程
}

主要的代码如下(以VFP为例):

<建立表>
CREATE TABLE (ctablename) ( curl M , ctext M , ldowned I , threadNum I )

&&建立一个表ctablename.dbf,含有地址、文本内容、已经尝试下载次数、

线程标志(初值为-1,线程标志是从0开始的整数)四个字段
<提取Url地址>
cfullname = (ctablename) + '.dbf'&&为表添加扩展名
USE (cfullname) 
GO TOP
LOCATE FOR (EMPTY( ALLTRIM( ctext ) ) AND ldowned < 2 AND

( threadNum = thisNum OR threadNum = - 1) ) 

&&查找尚未下载成功且应下载的属于本线程权限的Url地址,thisNum是当前线程的编号,

可以通过参数传递得到
gotUrl = curl
recNum = RECNO()
IF recNum <= RECCOUNT() THEN  &&如果在列表中找到这样的Url地址
UPDATE (cfullname) SET ldowned = ( ldowned + 1 ) , threadNum =

thisNum WHERE RECNO() = recNum &&更新表,将此记录更新为已申请,即下载次数加1,

线程标志列设为本线程的编号。

<下载内容>
cfulltablename = (ctablename) + '.dbf'
USE (cfulltablename)
SET EXACT ON
LOCATE FOR curl = (csiteurl) && csiteurl是参数,为下载到的内容所对应的Url地址
recNumNow = RECNO()&&得到含有此地址的记录号
UPDATE (cfulltablename) SET ctext = (ccontent) WHERE RECNO() =

recNumNow &&插入对应地址的对应内容

<插入新地址>
ctablename = (ctablename) + '.dbf'
USE (ctablename)
GO TOP
SET EXACT ON
LOCATE FOR curl = (cnewurl) &&查找有无此地址
IF RECNO() > RECCOUNT() THEN &&如果尚无此地址
SET CARRY OFF
INSERT INTO (ctablename) ( curl , ctext , ldowned , threadNum )

VALUES ( (cnewurl) , "" , 0 , -1 )  &&将主页地址添加到列表

好了,这样就解决了多线程中,线程冲突。当然,去重问题也可以在C#语言

3.线程结束是很难判断的,因为它总是在查找新的链接。用者认为可以假设:线程重复N次以后还是没有能申请到新的Url地址,那么可以认为它已经下载完了所有链接。主要代码如下:

string url = "";
int times = 0;
while ( url == "" )//如果没有找到符合条件的记录,则不断地寻找符合条件的记录
{
url = getUrl.GetAUrl( …… );//调用GetAUrl方法,试图得到一个url值
if ( url == "" )//如果没有找到
{
times ++;//尝试次数自增
continue; //进行下一次尝试
}

if ( times > N ) //如果已经尝试够了次数,则退出进程
{
downloadThread[i].Abort; //退出进程
}

else//如果没有尝试够次数
{
Times = 0; //尝试次数归零处理
}
//进行下一步针对得到的Url的处理

4.这个问题相对简单,因为在问题一中已经建议,将线程声名为类级数组,这样就很易于控制。只要用一个for循环即可结束。代码如下:

for( int i = 0; i < n; i++ )//关闭指定数量n的线程数
{
downloadThread[i].Abort();//逐个关闭线程
}

收获园豆:120
欧阳凝舞945522826 | 园豆:363 (菜鸟二级) | 2011-04-24 18:52
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册