你好,获取网页内容有多种方法,这里直接上代码了,如下:
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
WebClient就可以啊 简单好用
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 ();
}
}
可以说,已经实现了爬虫的功能。只是它存在一个效率问题,下载速度可能很慢。这是两方面的原因造成的:
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地址,那么可以认为它已经下载完了所有链接。主要代码如下:
|
4.这个问题相对简单,因为在问题一中已经建议,将线程声名为类级数组,这样就很易于控制。只要用一个for循环即可结束。代码如下:
for( int i = 0; i < n; i++ )//关闭指定数量n的线程数
{
downloadThread[i].Abort();//逐个关闭线程
}