2009-08-20 81 views
25

有没有一种办法,以查看网页的产生源(后所有的代码AJAX调用和JavaScript DOM操作已经发生)从C#应用程序,而无需打开了浏览器的代码?查看生成的源代码(后AJAX/JavaScript的),在C#

使用WebRequestWebClient查看初始页面对象工作正常,但如果页面在页面加载时广泛使用JavaScript来更改DOM,则这些不会提供页面的准确图片。

我已经尝试使用SeleniumWatin UI测试框架,它们完美地工作,提供所有JavaScript操作完成后显示的源代码。不幸的是,他们通过打开一个非常慢的实际网页浏览器来实现这一点。我已经实现了一个将这项工作卸载到另一台机器上的硒服务器,但仍然存在很大的延迟。

有一个.net库,将加载和分析页面(如浏览器)和吐出生成的代码?显然,谷歌和雅虎并没有为他们想要蜘蛛的每一页打开浏览器(当然他们可能比我拥有更多的资源......)。

是否有这样的图书馆还是我倒霉,除非我愿意来剖析一款开源浏览器的源代码?

SOLUTION

好,感谢大家对你的帮助。我有一个工作解决方案,比Selenium快10倍。呜!

感谢这个old article from beansoftware我能够使用System.Windows.Forms.WebBrowser控件下载页面并解析它,然后给它生成的源代码。尽管控件位于Windows.Forms中,但仍然可以从Asp.Net(我正在做的)中运行它,只需记住将System.Window.Forms添加到您的项目引用。

关于代码有两件值得注意的事情。首先,WebBrowser控件在新线程中调用。这是因为它必须在single threaded apartment上运行。

其次,GeneratedSource变量在两个地方设置。这不是由于一个明智的设计决定:)我仍在努力,并会在我完成时更新这个答案。 wb_DocumentCompleted()被多次调用。首先下载最初的HTML,然后在第一轮JavaScript完成时再次。不幸的是,我刮的网站有3个不同的装载阶段。 1)加载初始HTML 2)执行第一轮JavaScript DOM操作3)暂停半秒钟,然后进行第二轮JS DOM操作。

出于某种原因,第二轮不被wb_DocumentCompleted()函数造成的,但它总是陷于当wb.ReadyState ==完成。那么为什么不从wb_DocumentCompleted()中删除呢?我仍然不确定为什么它没有被捕获,这就是beadware软件文章推荐的。我会继续研究它。我只想发布此代码,以便任何感兴趣的人都可以使用它。请享用!

using System.Threading; 
using System.Windows.Forms; 

public class WebProcessor 
{ 
    private string GeneratedSource{ get; set; } 
    private string URL { get; set; } 

    public string GetGeneratedHTML(string url) 
    { 
     URL = url; 

     Thread t = new Thread(new ThreadStart(WebBrowserThread)); 
     t.SetApartmentState(ApartmentState.STA); 
     t.Start(); 
     t.Join(); 

     return GeneratedSource; 
    } 

    private void WebBrowserThread() 
    { 
     WebBrowser wb = new WebBrowser(); 
     wb.Navigate(URL); 

     wb.DocumentCompleted += 
      new WebBrowserDocumentCompletedEventHandler(
       wb_DocumentCompleted); 

     while (wb.ReadyState != WebBrowserReadyState.Complete) 
      Application.DoEvents(); 

     //Added this line, because the final HTML takes a while to show up 
     GeneratedSource= wb.Document.Body.InnerHtml; 

     wb.Dispose(); 
    } 

    private void wb_DocumentCompleted(object sender, 
     WebBrowserDocumentCompletedEventArgs e) 
    { 
     WebBrowser wb = (WebBrowser)sender; 
     GeneratedSource= wb.Document.Body.InnerHtml; 
    } 
} 
+1

你可以尝试破解萤火虫的来源。 – 2009-08-20 18:08:15

+0

我的尝试本来是和Watin和朋友一起的。伟大的问题! – orip 2009-08-20 18:25:51

+0

尝试运行你对“http://www.host.com/path/page.html?ast=3”或“http://gwt.google.com/samples/Showcase/Showcase.html”代码。您会注意到,它没有获取正确的HTML。任何想法如何解决这个问题? – Cosmo 2010-08-15 16:21:50

回答

4

它可能使用浏览器的实例(在你的情况下:ie控制)。您可以轻松地在您的应用中使用并打开一个页面。该控件将加载它并处理任何javascript。一旦完成,您可以访问控件dom对象并获取“解释”代码。

+0

这就是华廷确实 – orip 2009-08-20 18:25:21

+0

这是不是仍然有相同的速度问题,打开浏览器? – 2009-08-20 18:46:12

+0

既然你想你的代码解释+解析,速度“问题”会(如果你不显示窗口+你有一点点的开销更少,也许少了几分CPU)是非常相同。据我记得你也可以防止ocntrol加载图像,从而减少加载时间更多。但是那唯一的办法,你可以完成你想要的恐怕 – Niko 2009-08-20 19:00:51

1

理论上是的,但是,在目前,还没有。

我不认为这是目前唯一做到这一点的产品或OSS项目。这样的产品需要有它自己的JavaScript解释器,并能够准确地模拟它支持所有浏览器的运行时环境和怪癖。

鉴于您需要精确模拟服务器+浏览器环境以生成最终页面代码的内容,从长远来看,我认为使用浏览器实例是在其最终页面中精确生成页面的最佳方式州。当你认为页面加载完成后,浏览器中的页面源代码可能会随着AJAX/javascript的变化而变化,这一点尤其如此。

+0

你可能是对的,感谢你的想法。我没有找到一个Java库,可能是我所需要的,但我仍然希望有一个.NET解决方案。我之前当然别人也需要这样的:http://stackoverflow.com/questions/857515/screen-scraping-from-a-web-page-with-a-lot-of-javascript/857630#857630 – 2009-08-20 18:32:54

2

最好的办法是使用PhantomJs。那很棒。 (样品是Article)。

我的解决办法是这样的:

var page = require('webpage').create(); 

page.open("https://sample.com", function(){ 
    page.evaluate(function(){ 
     var i = 0, 
     oJson = jsonData, 
     sKey; 
     localStorage.clear(); 

     for (; sKey = Object.keys(oJson)[i]; i++) { 
      localStorage.setItem(sKey,oJson[sKey]) 
     } 
    }); 

    page.open("https://sample.com", function(){ 
     setTimeout(function(){ 
     page.render("screenshoot.png") 
      // Where you want to save it  
      console.log(page.content); //page source 
      // You can access its content using jQuery 
      var fbcomments = page.evaluate(function(){ 
       return $("body").contents().find(".content") 
      }) 
      phantom.exit(); 
     },10000) 
    });  
}); 
+0

你应该至少添加一部分代码,并更多地解释这一点。 – 2016-02-09 07:09:28