我对Visual Basic不太满意,对此感到抱歉,但是我对Java和其他一些编程语言有基本的了解,因此我并不是一个全新的人。
我想制作一个程序,该程序使用从文本文件加载的代理连接到网站,但是当我调试它时,它会给我一堆不同的错误消息,例如:
- HTTP错误503。服务不可用
- 找不到网页
等。
这是我的将代理加载到列表框中的代码:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
OpenFileDialog1.ShowDialog()
streamer = IO.File.OpenText(OpenFileDialog1.FileName)
Dim mystring() As String = streamer.ReadToEnd.Split(vbNewLine)
ListBox1.Items.AddRange(mystring)
End Sub
以下是使用代理的代码:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Button2.Enabled = False
Button1.Enabled = False
For Each item In ListBox1.Items
UseProxy(item.ToString)
Label4.Text = item
WebBrowser1.Navigate(TextBox3.Text)
pause(10000)
Next
End Sub
这是useproxy:
Private Sub UseProxy(ByVal strProxy As String)
Const INTERNET_OPTION_PROXY As Integer = 38
Const INTERNET_OPEN_TYPE_PROXY As Integer = 3
Dim struct_IPI As Struct_INTERNET_PROXY_INFO
struct_IPI.dwAccessType = INTERNET_OPEN_TYPE_PROXY
struct_IPI.proxy = Marshal.StringToHGlobalAnsi(strProxy)
struct_IPI.proxyBypass = Marshal.StringToHGlobalAnsi("local")
Dim intptrStruct As IntPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(struct_IPI))
Marshal.StructureToPtr(struct_IPI, intptrStruct, True)
Dim iReturn As Boolean = InternetSetOption(IntPtr.Zero, INTERNET_OPTION_PROXY, intptrStruct, System.Runtime.InteropServices.Marshal.SizeOf(struct_IPI))
End Sub
按钮2的点击子底部也显示了错误
实际上,有时我关闭程序时,在按钮2末尾的Visual Studio中出现错误2单击子菜单(下一步)
System.InvalidOperationException:'此枚举器绑定到的列表已被修改。仅在列表不变的情况下才能使用枚举器。'
答案 0 :(得分:2)
我认为这是在整个系统范围内更改系统代理设置的最直接方法。
有时,每个连接设置是更可取的。在这种情况下,请参阅链接的文档。
使用Registry class在Internet设置子项中设置所需的值:
Software\Microsoft\Windows\CurrentVersion\Internet Settings
然后,将InternetSetOption与INTERNET_OPTION_SETTINGS_CHANGED
和INTERNET_OPTION_REFRESH
Flags结合使用,以执行系统更改通知:
(这些是标志,但在这种情况下不应合并)
如果使用INTERNET_OPTION_REFRESH
来基于每个连接修改设置,则还必须调用INTERNET_OPTION_PER_CONNECTION_OPTION
。
声明InternetSetOption
和一个辅助函数。
Imports Microsoft.Win32
Imports System.Runtime.InteropServices
Imports System.Security.AccessControl
<SecurityCritical>
<DllImport("wininet.dll", SetLastError:=True, CharSet:=CharSet.Auto)>
Friend Shared Function InternetSetOption(hInternet As IntPtr, dwOption As Integer, lpBuffer As IntPtr, dwBufferLength As Integer) As Boolean
End Function
Friend Const INTERNET_OPTION_SETTINGS_CHANGED As Integer = 39
Friend Const INTERNET_OPTION_REFRESH As Integer = 37
<SecuritySafeCritical>
Private Sub InternetSetProxy(ProxyAddress As String, ProxyPort As Integer, UseProxy As Boolean)
Dim keyName As String = "Software\Microsoft\Windows\CurrentVersion\Internet Settings"
Dim KeyValue As Object = ProxyAddress + ":" + ProxyPort.ToString()
Dim InternetSettingsKey As RegistryKey =
Registry.CurrentUser.OpenSubKey(keyName,
RegistryKeyPermissionCheck.ReadWriteSubTree,
RegistryRights.WriteKey)
InternetSettingsKey.SetValue("ProxyServer", KeyValue, RegistryValueKind.String)
InternetSettingsKey.SetValue("ProxyEnable", If(UseProxy, 1, 0), RegistryValueKind.DWord)
InternetSettingsKey.Close()
InternetSetOption(IntPtr.Zero, INTERNET_OPTION_SETTINGS_CHANGED, IntPtr.Zero, 0)
InternetSetOption(IntPtr.Zero, INTERNET_OPTION_REFRESH, IntPtr.Zero, 0)
InternetSettingsKey.Dispose()
Application.DoEvents()
End Sub
您可以使用Internet Explorer进行测试。
如果您使用的是Fiddler,请使用以下参数调用helper方法以将其用作默认系统代理:
InternetSetProxy("127.0.0.1", 8888, True)
要禁用Proxy设置,只需将UseProxy
参数设置为False
:
InternetSetProxy("127.0.0.1", 8888, False)
照常导航Internet地址:
WebBrowser1.Navigate("https://www.google.com")
有关.Net WebBrowser控件的说明。
WebBrowser控件使用当前缓存(在Internet Explorer设置中指定)将访问的资源作为预定义的行为加载。
如果启用了代理,但仍可以看到网站的(第一)页面,则取决于此默认行为。
如果您尝试单击一个链接,则将无法访问此新链接,并且显示以下消息:
代理服务器没有响应
将被呈现。
这种结果不是恒定的,取决于缓存设置。
修改:
一种让WebBrowser
控制Navigate
一个或多个Internet地址的方法,为每个地址使用不同的代理服务器:
为WebBrowser
DocumentCompleted事件添加事件处理程序。
首次调用WebBrowser.Navigate()
方法时,事件处理程序将在代理列表中循环(从ListBox
控件Items
列表中读取)。
此代码假设代理列表由以下字符串组成: 包括每个代理的地址和端口。 (例如。
"127.0.0.1:8888"
for Fiddler)。
在这里,如在OP示例中一样,所有代理的Internet地址都是相同的(WaitDocumentsComplete()
方法的参数),但是当然可以从另一个列表中读取。
DocumentCompleted
处理程序和辅助方法NavigateNextProxy()
都被标记为异步,因此在整个过程中都不会阻塞UI。
可以随时使用WebBrowser.Stop()方法或将ProxyIndex
字段设置为负值来停止此过程。
如果该过程在其自然完成之前被中断,则必须使用以下命令显式删除该处理程序:
RemoveHandler WebBrowser1.DocumentCompleted, DocumentCompletedHandler
事件处理程序声明以及Wrapper和Helper函数:
Protected Friend DocumentCompletedHandler As WebBrowserDocumentCompletedEventHandler
Private Sub WaitDocumentsComplete(ByVal Address As String, ByVal TimeOutSeconds As Integer)
DocumentCompletedHandler =
Async Sub(s, e)
If WebBrowser1.ReadyState = WebBrowserReadyState.Complete AndAlso ProxyIndex > -1 Then
If (Not WebBrowser1.IsBusy) Then
Dim ProxyParts() As String = ListBox1.GetItemText(ListBox1.Items(ProxyIndex)).Split(":"c)
Await NavigateNextProxy(Address, ProxyParts(0), CInt(ProxyParts(1)), TimeOutSeconds)
ProxyIndex += 1
If ProxyIndex > ProxyIndexMaxValue Then
ProxyIndex = -1
RemoveHandler WebBrowser1.DocumentCompleted, DocumentCompletedHandler
End If
End If
End If
End Sub
AddHandler WebBrowser1.DocumentCompleted, DocumentCompletedHandler
End Sub
Protected Async Function NavigateNextProxy(Address As String, ByVal ProxyAddr As String, ProxyPort As Integer, TimeOutSeconds As Integer) As Task
InternetSetProxy(ProxyAddr, ProxyPort, True)
Await Task.Delay(TimeSpan.FromSeconds(TimeOutSeconds))
If WebBrowser1.IsBusy Then WebBrowser1.Stop()
WebBrowser1.Navigate(Address)
End Function
在Button.Click()
事件中,设置列表中第一个和最后一个代理的索引,在每个navigation
之间设置一个超时值(以秒为单位),然后调用包装器方法WaitDocumentsComplete()
,它将初始化DocumentCompleted
事件处理程序。
要开始该过程,请使用WebBrowser
初始化WebBrowser1.Navigate("")
控件
抑制
WebBrowser
脚本错误对话框也很重要, 否则会损害整个过程。
Private ProxyIndex As Integer = -1
Private ProxyIndexMaxValue As Integer = 0
Private Sub btnForm2_Click(sender As Object, e As EventArgs) Handles btnForm2.Click
ProxyIndex = 0
ProxyIndexMaxValue = ListBox1.Items.Count - 1
Dim BrowsingTimeoutSeconds As Integer = 3
Dim Address As String = "https://www.google.com"
WaitDocumentsComplete(Address, BrowsingTimeoutSeconds)
WebBrowser1.ScriptErrorsSuppressed = True
WebBrowser1.Navigate("")
End Sub