簡體   English   中英

如何“手動”返回WebBrowser?

[英]How to “manually” go back with a WebBrowser?

我正在研究一個有時需要記住特定頁面的Web抓取工具,然后轉到其他頁面,然后返回到該頁面。 目前我只保存頁面的網址,但這對於Google地圖這樣的網頁不起作用,其中網址始終相同。

我可以看到GoBack方法確實返回到上一頁,因此WebBrowser以某種方式記住以前的頁面是什么。 我該如何手動完成此操作? 我可以計算GoBack想要返回的頁面以來訪問了多少頁面,然后根據需要多次調用GoBack ,但這非常不可靠且不優雅。 所以我想知道如何實現GoBackToAParticularPage方法。

我認為有一件事可以讓我更接近解決方案:保存所有幀的URL,然后在返回該頁面時將它們放回原處。 我認為這將解決谷歌地圖問題。 我還沒有測試過。 我不確切知道這樣做的正確方法是什么。 在設置URL之前,我需要等待幀存在。

您可以使用

webBrowser1.Document.Window.History.Go(x);

其中x是一個int,表示瀏覽器歷史記錄中的相對位置。

x = -2會導航兩頁。

更新 :有關HtmlHistory.Go()的更多信息

試試這個!

的javascript:history.go(-1)”

我知道已經說了幾句話,所以我不會重寫它,但是,如果你真的想使用JavaScript方法(即:如果你想使用javascript歷史對象而不是webbrowser控件歷史對象)並且想知道如何做到這一點。 您可以在.NET WB控件中使用.InvokeScript,或者如果您希望兼容.NET和.NET,則可以使用:

您可以在.NET控件的.NET版本和WB控件的當前/ .NET版本中使用.execScript。 您還可以選擇要執行的腳本的語言,即:“JScript”或“VBScript”。 這是一個班輪:

WebBrowser1.Document.parentWindow.execScript "alert('hello world');", "JScript" 

使用JavaScript歷史記錄對象的好處是,如果您通過向.navigate方法發送數字“2”來終止webbrowser控件中的歷史信息,則轉到WB控件中取消歷史記錄的頁面將不起作用,但它將在JavaScript的歷史對象中工作,這是一個優勢。

再一次,這只是對這篇文章所討論的想法的向后兼容補充,包括一些未提及的其他花絮。

讓我知道,如果我可以為您提供進一步的幫助,那么答案已被接受。

通過javascript Location對象,您可以實現任務。

<FORM><INPUT TYPE="BUTTON" VALUE="Go Back" 
ONCLICK="history.go(-1)"></FORM>

還檢查

JavaScript歷史對象

歷史信息

根據設計,瀏覽器歷史是不透明的; 否則會打開一個安全漏洞:您是否真的希望您訪問的每個頁面都能看到您訪問過的頁面/網站? 可能不是。

要做你想做的事,你需要實現自己的URI堆棧,跟蹤需要重新訪問的內容。

您不想使用history.go(-1)因為它不可靠。 但是,您無法使用該網址,因為GoogleMaps等網頁的網址始終相同。

如果URL相同但內容不同,則表示確定頁面內容的值是從URL以外的其他位置提取的。

這可能在哪里?

您最可能的嫌疑人是已發布的表單集合,但數據也可能來自Cookie。

我認為索引絕對位置比相對位置更有意義,因為正如您所指出的,相對位置可能不可靠。 問題是您需要獲取發送到Web服務器的所有數據,以了解其實際絕對位置(因為URI不夠)。

執行此操作的方法是創建頁面的本地副本,並使用服務器上的URL替換提交URL(可以在鏈接,表單或javascript中)。 然后,當您單擊GoogleMaps頁面上的某些內容以觸發更改(這似乎不會影響URL)時,您將在服務器上收到該數據,並且能夠確定實際位置。

把它想象成一個查詢字符串。

如果我有

<form action="http://myhost.com/page.html" method="get">
   <input type="hidden" name="secret_location_parameter" value="mrbigglesworth" />
   <input type="submit" />
</form>

然后我點擊提交按鈕,我會被帶到網址

 http://myhost.com/page.html?secret_location_parameter=mrbigglesworth

但是,如果我有

<form action="http://myhost.com/page.html" method="post">
   <input type="hidden" name="secret_location_parameter" value="mrbigglesworth" />
   <input type="submit" />
</form>

然后我點擊提交按鈕,然后我被帶到網址

 http://myhost.com/page.html

服務器仍然接收secret_location_parameter=mrbigglesworth ,但它將其作為表單值而不是查詢字符串值,因此從URL secret_location_parameter=mrbigglesworth它。 服務器可能會根據secret_location_parameter值呈現不同的頁面,但不會更改url,如果使用post方法,則會出現多個頁面駐留在同一個url中。

我的觀點是,你可能從錯誤的角度解決問題,因為你不明白引擎蓋下發生了什么。 我當然在做假設,但根據你提出問題的方式,我認為這可能對你有所幫助

如果您不需要直觀地看到發生的事情,可能會有更優雅的方法來使用WebClient類導航和解析URL,或許詳細說明您的特定程序會產生更清晰的結果。

假設您在表單上有一個webbrowser控件,並且您正在嘗試實現返回。

以下是解決方案。 (如果假設錯了。請糾正我)

添加webbrowser,文本框,按鈕為btnBack

歷史變量還具有用於導航的URL數據(但當前未使用)。

C#解決方案

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    private void Form1_Load(object sender, EventArgs e)
    {
         WebBrowser1.Url = new Uri("http://maps.google.com");
    }
    Stack< String> History = new Stack<String>();

    private void WebBrowser1_Navigating(object sender, WebBrowserNavigatingEventArgs e)
    {
            TextBox1.Text = e.Url.ToString();
            History.Push(e.Url.ToString());
    }

    private void btnBack_Click(object sender, EventArgs e)
    {
        if(WebBrowser1.CanGoBack) 
        {
            WebBrowser1.GoBack();
        }

    }

}
}

Vb解決方案

Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    WebBrowser1.Url = New Uri("http://maps.google.com")
End Sub

Private Sub WebBrowser1_Navigating(ByVal sender As Object, ByVal e As System.Windows.Forms.WebBrowserNavigatingEventArgs) Handles WebBrowser1.Navigating
    TextBox1.Text = e.Url.ToString
    History.Push(e.Url.ToString)
End Sub
Dim History As New Stack(Of String)
Private Sub btnBack_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnBack.Click
    If WebBrowser1.CanGoBack Then
        WebBrowser1.GoBack()
    End If
End Sub

End Class

以編程方式將標記元素添加到DOM中,以用於稍后要返回的頁面。 回溯瀏覽器歷史記錄時,請在每個history.go(-1)之后檢查該標記,並在遇到它時停止。 在某些情況下,這可能證明是不可靠的,在這種情況下,記住深度級別可以作為備用方法。

您可能需要嘗試插入元素的正確時間,以確保它在歷史記錄中正確記錄。

如果其他人可以從中受益,這就是我最終如何做到這一點。 唯一需要注意的是,如果旅行日志之間有太多頁面,則該條目可能不再存在。 可能有一種方法可以增加歷史記錄大小,但由於必須有一些限制,我使用TravelLog.GetTravelLogEntries方法來查看條目是否仍然存在,如果不存在,請使用URL。

大部分代碼來自PInvoke

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Collections.Generic;

namespace TravelLogUtils
{
    [ComVisible(true), ComImport()]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [GuidAttribute("7EBFDD87-AD18-11d3-A4C5-00C04F72D6B8")]
    public interface ITravelLogEntry
    {
        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int GetTitle([Out] out IntPtr ppszTitle); //LPOLESTR LPWSTR

        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int GetURL([Out] out IntPtr ppszURL); //LPOLESTR LPWSTR
    }

    [ComVisible(true), ComImport()]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [GuidAttribute("7EBFDD85-AD18-11d3-A4C5-00C04F72D6B8")]
    public interface IEnumTravelLogEntry
    {
        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int Next(
            [In, MarshalAs(UnmanagedType.U4)] int celt,
            [Out] out ITravelLogEntry rgelt,
            [Out, MarshalAs(UnmanagedType.U4)] out int pceltFetched);

        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int Skip([In, MarshalAs(UnmanagedType.U4)] int celt);

        void Reset();

        void Clone([Out] out ITravelLogEntry ppenum);
    }

    public enum TLMENUF
    {
        /// <summary>
        /// Enumeration should include the current travel log entry.
        /// </summary>
        TLEF_RELATIVE_INCLUDE_CURRENT = 0x00000001,
        /// <summary>
        /// Enumeration should include entries before the current entry.
        /// </summary>
        TLEF_RELATIVE_BACK = 0x00000010,
        /// <summary>
        /// Enumeration should include entries after the current entry.
        /// </summary>
        TLEF_RELATIVE_FORE = 0x00000020,
        /// <summary>
        /// Enumeration should include entries which cannot be navigated to.
        /// </summary>
        TLEF_INCLUDE_UNINVOKEABLE = 0x00000040,
        /// <summary>
        /// Enumeration should include all invokable entries.
        /// </summary>
        TLEF_ABSOLUTE = 0x00000031
    }

    [ComVisible(true), ComImport()]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [GuidAttribute("7EBFDD80-AD18-11d3-A4C5-00C04F72D6B8")]
    public interface ITravelLogStg
    {
        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int CreateEntry([In, MarshalAs(UnmanagedType.LPWStr)] string pszUrl,
            [In, MarshalAs(UnmanagedType.LPWStr)] string pszTitle,
            [In] ITravelLogEntry ptleRelativeTo,
            [In, MarshalAs(UnmanagedType.Bool)] bool fPrepend,
            [Out] out ITravelLogEntry pptle);

        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int TravelTo([In] ITravelLogEntry ptle);

        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int EnumEntries([In] int TLENUMF_flags, [Out] out IEnumTravelLogEntry ppenum);

        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int FindEntries([In] int TLENUMF_flags,
        [In, MarshalAs(UnmanagedType.LPWStr)] string pszUrl,
        [Out] out IEnumTravelLogEntry ppenum);

        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int GetCount([In] int TLENUMF_flags, [Out] out int pcEntries);

        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int RemoveEntry([In] ITravelLogEntry ptle);

        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int GetRelativeEntry([In] int iOffset, [Out] out ITravelLogEntry ptle);
    }

    [ComImport, ComVisible(true)]
    [Guid("6d5140c1-7436-11ce-8034-00aa006009fa")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    public interface IServiceProvider
    {
        [return: MarshalAs(UnmanagedType.I4)]
        [PreserveSig]
        int QueryService(
            [In] ref Guid guidService,
            [In] ref Guid riid,
            [Out] out IntPtr ppvObject);
    }

    public class TravelLog
    {
        public static Guid IID_ITravelLogStg = new Guid("7EBFDD80-AD18-11d3-A4C5-00C04F72D6B8");
        public static Guid SID_STravelLogCursor = new Guid("7EBFDD80-AD18-11d3-A4C5-00C04F72D6B8");

        //public static void TravelTo(WebBrowser webBrowser, int 
        public static ITravelLogEntry GetTravelLogEntry(WebBrowser webBrowser)
        {
            int HRESULT_OK = 0;

            SHDocVw.IWebBrowser2 axWebBrowser = (SHDocVw.IWebBrowser2)webBrowser.ActiveXInstance;
            IServiceProvider psp = axWebBrowser as IServiceProvider;
            if (psp == null) throw new Exception("Could not get IServiceProvider.");

            IntPtr oret = IntPtr.Zero;            
            int hr = psp.QueryService(ref SID_STravelLogCursor, ref IID_ITravelLogStg, out oret);            
            if ((oret == IntPtr.Zero) || (hr != HRESULT_OK)) throw new Exception("Failed to query service.");

            ITravelLogStg tlstg = Marshal.GetObjectForIUnknown(oret) as ITravelLogStg;
            if (null == tlstg) throw new Exception("Failed to get ITravelLogStg");            
            ITravelLogEntry ptle = null;

            hr = tlstg.GetRelativeEntry(0, out ptle);

            if (hr != HRESULT_OK) throw new Exception("Failed to get travel log entry with error " + hr.ToString("X"));

            Marshal.ReleaseComObject(tlstg);
            return ptle;
        }

        public static void TravelToTravelLogEntry(WebBrowser webBrowser, ITravelLogEntry travelLogEntry)
        {
            int HRESULT_OK = 0;

            SHDocVw.IWebBrowser2 axWebBrowser = (SHDocVw.IWebBrowser2)webBrowser.ActiveXInstance;
            IServiceProvider psp = axWebBrowser as IServiceProvider;
            if (psp == null) throw new Exception("Could not get IServiceProvider.");

            IntPtr oret = IntPtr.Zero;
            int hr = psp.QueryService(ref SID_STravelLogCursor, ref IID_ITravelLogStg, out oret);
            if ((oret == IntPtr.Zero) || (hr != HRESULT_OK)) throw new Exception("Failed to query service.");

            ITravelLogStg tlstg = Marshal.GetObjectForIUnknown(oret) as ITravelLogStg;
            if (null == tlstg) throw new Exception("Failed to get ITravelLogStg");

            hr = tlstg.TravelTo(travelLogEntry);

            if (hr != HRESULT_OK) throw new Exception("Failed to travel to log entry with error " + hr.ToString("X"));

            Marshal.ReleaseComObject(tlstg);
        }

        public static HashSet<ITravelLogEntry> GetTravelLogEntries(WebBrowser webBrowser)
        {
            int HRESULT_OK = 0;

            SHDocVw.IWebBrowser2 axWebBrowser = (SHDocVw.IWebBrowser2)webBrowser.ActiveXInstance;
            IServiceProvider psp = axWebBrowser as IServiceProvider;
            if (psp == null) throw new Exception("Could not get IServiceProvider.");

            IntPtr oret = IntPtr.Zero;
            int hr = psp.QueryService(ref SID_STravelLogCursor, ref IID_ITravelLogStg, out oret);
            if ((oret == IntPtr.Zero) || (hr != HRESULT_OK)) throw new Exception("Failed to query service.");

            ITravelLogStg tlstg = Marshal.GetObjectForIUnknown(oret) as ITravelLogStg;
            if (null == tlstg) throw new Exception("Failed to get ITravelLogStg");

            //Enum the travel log entries
            IEnumTravelLogEntry penumtle = null;
            tlstg.EnumEntries((int)TLMENUF.TLEF_ABSOLUTE, out penumtle);
            hr = 0;
            ITravelLogEntry ptle = null;
            int fetched = 0;
            const int MAX_FETCH_COUNT = 1;

            hr = penumtle.Next(MAX_FETCH_COUNT, out ptle, out fetched);
            Marshal.ThrowExceptionForHR(hr);

            HashSet<ITravelLogEntry> results = new HashSet<ITravelLogEntry>();

            for (int i = 0; 0 == hr; i++)
            {
                if (ptle != null) results.Add(ptle);
                hr = penumtle.Next(MAX_FETCH_COUNT, out ptle, out fetched);
                Marshal.ThrowExceptionForHR(hr);
            }

            Marshal.ReleaseComObject(penumtle);
            Marshal.ReleaseComObject(tlstg);

            return results;
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM