6

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

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

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

任何帮助将不胜感激

提前致谢

4

1 回答 1

0

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

是的,如果您尝试使其成为 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;
}

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

干杯。

于 2013-08-21T21:11:46.157 回答