【问题标题】:Web browser hosting issue in asp.net mvc applicatonasp.net mvc 应用程序中的 Web 浏览器托管问题
【发布时间】:2013-07-18 05:27:53
【问题描述】:

在我的 Asp.Net MVC Web 应用程序中,我必须通过网站从网站获取数据。对于抓取数据,我需要登录该站点,然后通过单击菜单选项卡访问站点,然后从该页面我需要抓取数据。被抓取的站点包含 2 个框架。我之前在我的一个 Windows 项目中通过 Windows 网络浏览器控件实现了网络抓取。

我按照以下link 将网络浏览器控件集成到我的网络应用程序中。在 Visual Studio 环境下一切正常,我通过网络浏览器抓取网站获取数据。但是当我尝试托管应用程序时,它并没有按预期工作。 Web 浏览器控件未加载。我搜索了解决方案,但还没有找到可行的解决方案。我尝试通过 iframe 以及使用 Silverlight Webbrowser 控件和使用 javascript 调用登录事件来实现相同的功能,但由于跨域问题导致访问被拒绝,它也失败了。

那么有什么方法可以通过在 asp.net Web 应用程序中登录到站点来抓取数据。我可以将我的 Windows 应用程序作为 ActiveX 控件并使用它吗? ActiveX 会有跨浏览器的问题吗?

任何帮助将不胜感激

提前致谢

【问题讨论】:

  • 您是否考虑过使用System.Net.Http.HttpClientSystem.Net.WebRequest 获取所需的内容?
  • 是的,是的,我尝试使用相同的方法,但失败了。我怀疑是因为要报废的网站包含多个框架?
  • 是否有可能只创建一个单独的应用程序来处理抓取?然后将结果保存在数据库或文本文件中,您的网站可以从中读取。
  • 我的猜测是 Windows Server 安全限制阻止 IIS 启动浏览器,或阻止浏览器正常运行。你怎么知道浏览器控件没有被加载?
  • 您不需要浏览器控制来进行抓取。使用 System.Net.WebRequest。当您获得框架页面时,对其进行解析以获取每个框架的 URL。然后获取您感兴趣的框架。如果 URL 已知,则直接进入该框架。

标签: asp.net-mvc web-scraping


【解决方案1】:

正如 cmets 中所建议的,使用网络浏览器的方法似乎很繁重,并且会受到其他环境限制。您最好的方法是创建一个单独的、可测试的存储库来抓取数据 - 如果您确实需要(并且目标数据不会更改),则可以按需或提前使用爬虫方法。

是的,如果您尝试使其成为 ActiveX,不同的浏览器会遇到问题。安全可能不允许这样做。这里真的有很多因素;如果您的环境不受控制,这不是一个很好的选择。

假设您采用按需方法,我强烈建议您创建一个可以参考的 Web 服务或类。然后,您可以在服务器端使用开源解析器,例如:

  1. CsQuery 如果文档格式不正确,或者,
  2. Fizzler 如果您可以信任文档的完整性。

基本上,您需要进行身份验证、存储身份验证 cookie,最后通过填充有身份验证 cookie 的第二个请求加载目标文档。将 页面输入到您的解析器(CsQuery 或 Fizzler)中。

执行登录的示例如下:

private HttpWebRequest PerformLoginRequest(CookieContainer container)
{
    var request = (HttpWebRequest) WebRequest.Create(YOUR_POST_URL);
    request.Method = "POST";
    request.CookieContainer = container;

    _logger.DebugFormat("Attempting login for '{0}'", _username);
    var encoding = new ASCIIEncoding();

    // assumes the un/pw is stored in a field
    var credentials = string.Format("username={0}&password={1}", _username, _password);
    byte[] data = encoding.GetBytes(credentials);

    request.ContentType = "application/x-www-form-urlencoded";
    request.ContentLength = data.Length;

    using (var requestStream = request.GetRequestStream())
    {
        try
        {
            requestStream.Write(data, 0, data.Length);
        }
        catch (Exception e)
        {
            _logger.Error("Error in login attempt.", e);
        }
        finally
        {
            requestStream.Close();
        }
    }
    return request;
}

返回的 cookies 容器将有一个 set-cookie,您需要将其解析出来,以便后续请求正确显示身份验证位。我必须这样做,并处理了我在 SO 上某处找到的代码,但现在找不到参考。它可能看起来像这样(解释这里Set-Cookie):

private static CookieContainer ProcessCookieContainer(HttpWebRequest request, CookieContainer container)
{
    var response = (HttpWebResponse) request.GetResponse();
    var cookierReader = new StreamReader(response.GetResponseStream());
    string htmldoc = cookierReader.ReadToEnd();

    var cookieHeader = response.GetResponseHeader("Set-Cookie");
    response.Close();

    container = new CookieContainer();
    foreach (var cookie in cookieHeader.Split(','))
    {
        // these are ; seperated name/value pairs
        var split = cookie.Split(';');
        string name = split[0].Split('=')[0];
        string value = split[0].Split('=')[1];

        // create the cookie with the domain
        var c = new Cookie(name, value) {Domain = "YourCookieDomain.com"};

        container.Add(c);
    }
    return container;
}

要加载一个文档来解析它,你可能会这样做:

public string GetValueFromSomePage(int first, string second)
{
    var container = new CookieContainer();

    // do login
    var request = PerformLoginRequest(container);

    // chew on cookies
    container = ProcessCookieContainer(request, container);

    var result = string.Empty;
    var requestUrl = string.Format("http://YourUrlWithParams.com/?first={0}&second={1}", 123, "abc");
    var request = (HttpWebRequest)WebRequest.Create(requestUrl);
    request.CookieContainer = container;

    using (var serverResponse = (HttpWebResponse)request.GetResponse())
    {
        try
        {
            var reader = new StreamReader(serverResponse.GetResponseStream());
            var responseDoc = new CQ(reader);

            // do something with CSS selectors...
            result = responseDoc["input[name=name]"].FirstElement().Value;

        }
        catch (Exception e)
        {
            _logger.Error("Error fetching data.", e);
        }
        finally
        {
            serverResponse.Close();
        }
    }

    return result;
}

我希望这会有所帮助。这里有一些活动部分,但考虑到您的任务性质,您可能已经预料到了。

干杯。

【讨论】:

    猜你喜欢
    • 2020-05-20
    • 1970-01-01
    • 1970-01-01
    • 2011-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多