【发布时间】:2015-04-02 11:47:27
【问题描述】:
我正在制作一个 Web Crawler,但我刚刚发现我的方法之一 GetHTML 非常慢,因为它使用 StreamReader 从 HttpWebResponse 对象中获取 HTML 字符串。
方法如下:
static string GetHTML(string URL)
{
HttpWebRequest Request = (HttpWebRequest)WebRequest.Create(URL);
Request.Proxy = null;
HttpWebResponse Response = ((HttpWebResponse)Request.GetResponse());
Stream RespStream = Response.GetResponseStream();
return new StreamReader(RespStream).ReadToEnd(); // Very slow
}
我用 Stopwatch 做了一个测试,并在 YouTube 上使用了这个方法。
Time it takes to get an HTTP response: 500 MS
Time it takes to convert the HttpWebResponse object to a string: 550 MS
所以 HTTP 请求没问题,只是 ReadToEnd() 太慢了。
除了 ReadToEnd() 方法之外,还有其他方法可以从响应对象中获取 HTML 字符串吗?我尝试使用 WebClient.DownloadString() 方法,但它只是 HttpWebRequest 的一个包装器,它也使用流。
编辑:用 Sockets 试了一下,速度要快得多:
static string SocketHTML(string URL)
{
string IP = Dns.GetHostAddresses(URL)[0].ToString();
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
s.Connect(new IPEndPoint(IPAddress.Parse(IP), 80));
s.Send(Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\n\r\n"));
List<byte> HTML = new List<byte>();
int Bytes = 1;
while (Bytes > 0)
{
byte[] Data = new byte[1024];
Bytes = s.Receive(Data);
foreach (byte b in Data) HTML.Add(b);
}
s.Close();
return Encoding.ASCII.GetString(HTML.ToArray());
}
不过,将它与 Socket 一起使用的问题在于,它在大多数情况下会返回错误,例如“永久移动”或“您的浏览器发送了服务器无法理解的请求”。
【问题讨论】:
-
你在这里比较什么?对远程站点的实际调用返回一个空字符串?
-
我做了这个比较,看看 StreamReader.ReadToEnd() 是否是瓶颈,我已经看到了。当我收到响应并且我不使用 ReadToEnd() 方法时,GetHTML(string URL) 返回大约需要 500 毫秒,但如果我使用 ReadToEnd() 方法则需要 1000 毫秒。在这种情况下(当我在 youtube.com 上测试时),ReadToEnd() 方法需要 500 毫秒才能完成 - 这非常慢。请求本身没问题,发送OK,但是转成字符串很慢。
标签: .net performance stream streamreader httpwebresponse