Как "вручную" вернуться с помощью WebBrowser?

Я работаю над веб-скребком, который иногда должен помнить конкретную страницу, затем переходить на другие страницы, а затем возвращаться к этой странице. В настоящее время я просто сохраняю URL-адрес страницы, но это не работает для таких страниц, как Карты Google, где URL-адрес всегда один и тот же.

Я вижу, что метод GoBack возвращается к предыдущей странице, поэтому как-то WebBrowser запоминает, что было на предыдущих страницах. Как я могу сделать это вручную? Я мог бы подсчитать, сколько страниц было посещено со страницы, на которую я хочу вернуться, и затем называть GoBack столько раз, сколько необходимо, но это довольно ненадежно и не элегантно. Поэтому мне интересно, как реализовать метод GoBackToAParticularPage.

Есть одна вещь, которая, по моему мнению, приблизит меня к решению: сохранение URL-адреса всех фреймов, а затем возврат их обратно на эту страницу. Я думаю, что это решило бы арендовать проблемы с Картами Google. Я еще не тестировал его. Я не знаю точно, как это будет правильным способом. Мне нужно дождаться, пока кадры будут существовать, прежде чем устанавливать их URL-адреса.

Ответ 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;
        }
    }
}

Ответ 2

Вы можете использовать

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

где x - это int, означающее относительное положение в истории браузера.

x = -2 будет перемещаться по двум страницам назад.

Обновление: дополнительная информация о HtmlHistory.Go()

Ответ 3

попробуйте это!

JavaScript: history.go(-1) "

Ответ 4

Я знаю, что было сказано несколько вещей, поэтому я не буду переписывать это, однако, если вы действительно хотите использовать метод JavaScript (то есть: если вы хотите использовать объект истории javascript вместо элементов управления webbrowser объект истории) и задаются вопросом, как это сделать. Вы можете использовать .InvokeScript в элементах управления .NET WB, или если вы хотите совместимость с pre-.NET и .NET, вы можете использовать это:

Вы можете использовать .execScript в версиях WB версии до версии .NET и текущих версиях управления WB/.NET. Вы также можете выбрать язык script, который вы хотите выполнить, например: "JScript" или "VBScript". Вот один лайнер:

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

Хорошая вещь об использовании объекта истории JavaScript заключается в том, что если вы удаляете информацию истории в элементе управления webbrowser, отправив номер "2" в метод .navigate, переход на страницу, где история была отменена в WB-элементе управления, не будет работать, но он будет работать в объекте истории JavaScript, это преимущество.

Еще раз, это просто обратное совместимое дополнение к идеям, обсуждаемым на этом посту, в том числе несколько других лакомых кусочков, которые не упоминаются.

Сообщите мне, если я могу вам помочь, так как ответ уже был принят.

Ответ 5

Объектом javascript Location вы можете выполнить свою задачу.

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

также проверьте

Объект истории JavaScript

для информации истории

Ответ 6

История браузера по дизайну непрозрачна; в противном случае он открывает отверстие для безопасности: действительно ли вы хотите, чтобы каждая страница, которую вы посещаете, имела видимость того, какие страницы/сайты вы посещали? Наверное, нет.

Чтобы сделать то, что вы хотите, вам нужно будет реализовать собственный стек URI, отслеживая, что нужно пересмотреть.

Ответ 7

Вы не хотите использовать history.go(-1), потому что это ненадежно. Но вы не можете использовать URL-адрес, потому что есть такие страницы, как GoogleMaps, где URL-адрес всегда один и тот же.

Если URL-адрес тот же, но контент отличается, значит, значения для определения содержимого страницы вытягиваются из другого места, кроме URL-адреса.

Где это может быть?

Ваш наиболее вероятный подозреваемый - это размещенная форма-коллекция, но данные также могут поступать из файла cookie.

Я думаю, что гораздо более важно индексировать абсолютное местоположение, чем относительное местоположение, потому что, как вы отметили, относительные местоположения могут быть ненадежными. Проблема в том, что вам нужно получить все данные, которые отправляются на веб-сервер, чтобы понять, каково его фактическое абсолютное местоположение (поскольку URI недостаточно).

Способ сделать это - создать локальную копию страницы и заменить URL-адрес отправки (это может быть ссылка, форма или javascript) с URL-адресом на вашем сервере. Затем, когда вы нажимаете что-то на странице GoogleMaps, чтобы вызвать изменение (что, похоже, не влияет на URL-адрес), вы получите эти данные на своем сервере и сможете определить фактическое местоположение.

Подумайте об этом, как о querystring.

Если у меня

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

и я нажимаю кнопку отправки, я попадаю в URL

 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>

и я нажимаю кнопку отправки, затем меня берут на URL

 http://myhost.com/page.html

Сервер по-прежнему получает secret_location_parameter=mrbigglesworth, но он получает его как значение формы вместо значения querystring, поэтому он не отображается с URL-адреса. Сервер может отображать другую страницу в зависимости от значения secret_location_parameter, но не изменять URL-адрес, и если используется метод post, то появится, что несколько страниц находятся на одном URL-адресе.

Я хочу сказать, что вы можете решить проблему с неправильного угла, потому что вы не понимали, что происходит под капотом. Я, конечно, делаю предположения, но основываясь на том, как вы задали свой вопрос, я думаю, что это может быть полезно для вас.

Ответ 8

Если вам не нужно визуально видеть, что происходит, возможно, более элегантные способы навигации и разбора URL-адресов с помощью классов WebClient, возможно, разработка вашей конкретной программы даст более четкие результаты.

Ответ 9

Предполагая, что у вас есть элемент управления webbrowser в форме, и вы пытаетесь выполнить возврат.

Следующее решение. (Если предположение неверно, пожалуйста, исправьте меня)

Добавить веб-браузер, текстовое поле, кнопку btnBack

В переменной истории также есть данные url для навигации (но не используется в настоящее время).

Решение С#

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

Ответ 10

Программно добавить элемент маркера в DOM для тех страниц, на которые вы позже захотите вернуться. Когда вы возвращаетесь в историю браузера, проверяйте этот маркер после каждого history.go(-1) и останавливайтесь, когда вы его встретите. В некоторых случаях это может оказаться ненадежным, и в этом случае запоминание уровня глубины может служить резервным подходом.

Вам может потребоваться поэкспериментировать с правильным временем, чтобы вставить элемент, чтобы убедиться, что он правильно записан в истории.