我正在为特定网站编写网络抓取工具。该应用程序是一个VB.Net Windows窗体应用程序,不使用多个线程 - 每个Web请求是连续的。但是,在十次成功的页面检索之后,每个连续的请求都会超时。
我已经回顾了已经在SO上发布的类似问题,并在我的GetPage例程中实现了推荐的技术,如下所示:
Public Function GetPage(ByVal url As String) As String
Dim result As String = String.Empty
Dim uri As New Uri(url)
Dim sp As ServicePoint = ServicePointManager.FindServicePoint(uri)
sp.ConnectionLimit = 100
Dim request As HttpWebRequest = WebRequest.Create(uri)
request.KeepAlive = False
request.Timeout = 15000
Try
Using response As HttpWebResponse = DirectCast(request.GetResponse, HttpWebResponse)
Using dataStream As Stream = response.GetResponseStream()
Using reader As New StreamReader(dataStream)
If response.StatusCode <> HttpStatusCode.OK Then
Throw New Exception("Got response status code: " + response.StatusCode)
End If
result = reader.ReadToEnd()
End Using
End Using
response.Close()
End Using
Catch ex As Exception
Dim msg As String = "Error reading page """ & url & """. " & ex.Message
Logger.LogMessage(msg, LogOutputLevel.Diagnostics)
End Try
Return result
End Function
我错过了什么吗?我没有关闭或处理应该是的对象吗?似乎很奇怪,它总是在连续十次请求之后发生。
注意:
在此方法所在的类的构造函数中,我有以下内容:
ServicePointManager.DefaultConnectionLimit = 100
如果我将KeepAlive设置为true,则会在五次请求后开始超时。
所有请求均针对同一域中的网页。
修改
我在两次到七秒之间的每个网络请求之间添加了延迟,这样我就不会“锤击”网站或尝试DOS攻击。但是,问题仍然存在。
答案 0 :(得分:4)
我今天遇到了这个问题,我的决议是确保响应始终关闭。
我认为你需要在使用中抛出异常之前放入response.Close()。
Using response As HttpWebResponse = DirectCast(request.GetResponse, HttpWebResponse)
Using dataStream As Stream = response.GetResponseStream()
Using reader As New StreamReader(dataStream)
If response.StatusCode <> HttpStatusCode.OK Then
response.Close()
Throw New Exception("Got response status code: " + response.StatusCode)
End If
result = reader.ReadToEnd()
End Using
End Using
response.Close()
End Using
答案 1 :(得分:3)
我认为该网站有一些DOS保护,当它受到许多rapis请求的攻击时会启动。您可能想尝试在webrequest上设置UserAgent。
答案 2 :(得分:2)
我使用了以下解决方案,它对我有用。希望它对你也有帮助。
在变量形式上声明“全局”。
HttpWebRequest myHttpWebRequest;
HttpWebResponse myHttpWebResponse;
然后在每次连接后始终使用myHttpWebResponse.Close();
。
myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
myHttpWebResponse.Close();
答案 3 :(得分:1)
我知道这是一个老问题,但我最近遇到了这个问题(由于我的目标环境使用4.0并且不允许任何外部程序集引用)
我做了一些挖掘但是从.NET内部工作的角度来看,找到了各种修复并且非常有趣
ServicePointManager.DefaultConnectionLimit = 100;
ServicePointManager在内部处理由多个HttpWebRequest对象创建的实际HTTP请求。问题是,这些不会自动关闭,并且HttpWebRequest不会立即收集垃圾
所以我发现了一些非常有趣的东西 - 如果我让HttpWebRequest成为一个实例级变量而且我在切换引用后强制进行垃圾收集......它可以工作(没有DefaultConnectionLimit = 100 hack)
private HttpWebRequest Request { get; set; }
public void MyMethod() {
Request = (HttpWebRequest)HttpWebRequest.Create("http://myUrl");
GC.Collect();
GC.WaitForFullGCComplete();
}
每次在方法中创建新的局部变量之前。这似乎解决了我的问题 - 可能有点太晚了,无法帮助你,但我想我会分享以防其他人遇到这个问题
答案 4 :(得分:1)
如果服务器正在使用数据库并且没有正确关闭每个数据库连接,则可能会在最大值时收到错误(例如状态码502)。达到连接限制(直到数据库连接超时)。 在这种情况下,解决方案只是“睡眠”。给定时间的webrequest线程。 此外,您应确保在处理后关闭每个请求和响应流(最好通过使用&#39;使用&#39;语句):
答案 5 :(得分:0)
myRequest.Connection =“关闭”; 将使服务器关闭连接,这将使连接管理器也关闭连接。