PhantomJS 传递 HTML 字符串并返回页面源

Posted

技术标签:

【中文标题】PhantomJS 传递 HTML 字符串并返回页面源【英文标题】:PhantomJS pass HTML string and return page source 【发布时间】:2014-05-15 13:04:52 【问题描述】:

对于 C# 中的网络爬虫项目,我尝试执行 javascript 和 Ajax 来检索已爬取页面的完整页面源。

我正在使用需要有效 HttpWebResponse 对象的现有网络爬虫 (Abot)。因此我不能简单地使用driver.Navigate().GoToUrl() 方法来检索页面源。

爬虫下载页面源码,我想在源码里面执行已有的Javascript/Ajax。

在一个示例项目中,我尝试了以下操作但没有成功:

        WebClient wc = new WebClient();
        string content = wc.DownloadString("http://www.newegg.com/Product/Product.aspx?Item=N82E16834257697");
        string tmpPath = Path.Combine(Path.GetTempPath(), "temp.htm");
        File.WriteAllText(tmpPath, content);

        var driverService = PhantomJSDriverService.CreateDefaultService();            
        var driver = new PhantomJSDriver(driverService);
        driver.Navigate().GoToUrl(new Uri(tmpPath));
        string renderedContent = driver.PageSource;
        driver.Quit();

您需要以下 nuget 包来运行示例: https://www.nuget.org/packages/phantomjs.exe/ http://www.nuget.org/packages/selenium.webdriver

这里的问题是代码在GoToUrl() 处停止,并且程序终止需要几分钟甚至没有给我驱动程序.PageSource。

这样做会返回正确的 html

driver.Navigate().GoToUrl("http://www.newegg.com/Product/Product.aspx?Item=N82E16834257697");
string renderedContent = driver.PageSource;

但我不想两次下载数据。爬虫(Abot)下载 HTML,我只想解析/渲染 javascript 和 ajax。

谢谢!

【问题讨论】:

再次阅读您的问题后,我认为让它在本地文件上运行并没有那么快,因为仍然需要下载javascript和样式等外部文件。您只需减少一个请求。 【参考方案1】:

如果不运行它,我敢打赌你需要 file:/// 在 tmpPath 之前。那就是:

    WebClient wc = new WebClient();
    string content = wc.DownloadString("http://www.newegg.com/Product/Product.aspx?Item=N82E16834257697");
    string tmpPath = Path.Combine(Path.GetTempPath(), "temp.htm");
    File.WriteAllText(tmpPath, content);

    var driverService = PhantomJSDriverService.CreateDefaultService();            
    var driver = new PhantomJSDriver(driverService);
    driver.Navigate().GoToUrl(new Uri("file:///" + tmpPath));
    string renderedContent = driver.PageSource;
    driver.Quit();

【讨论】:

文件路径中是否需要将\替换为/?【参考方案2】:

您可能需要允许 PhantomJS 发出任意请求。当域/协议不匹配时,请求会被阻止,就像打开本地文件时一样。

var driverService = PhantomJSDriverService.CreateDefaultService();
driverService.LocalToRemoteUrlAccess = true;
driverService.WebSecurity = false; // may not be necessary
var driver = new PhantomJSDriver(driverService);

您可能需要将此与 Dave Bush 的解决方案结合起来:

driver.Navigate().GoToUrl(new Uri("file:///" + tmpPath));

某些资源的 URL 以 // 开头,这意味着当浏览器检索这些资源时会使用页面的协议。读取本地文件时,此协议为file://,在这种情况下,将找不到这些资源。必须将协议添加到本地文件才能下载所有这些资源。

File.WriteAllText(tmpPath, content.Replace('"//', '"http://'));

从您的output 可以看出您使用的是 PhantomJS 1.9.8。可能是newly introduced bug 负责这类事情。您应该使用 driverService.SslProcotol = 'tlsv1' 来使用 PhantomJS 1.9.7。


如果您对同一个域多次执行此操作,您还应该启用磁盘缓存。否则,每次尝试抓取资源时都会下载资源。这可以通过driverService.DiskCache = true;来完成

【讨论】:

我没有测试过这个,但这通常是普通 PhantomJS 的解决方案。 感谢您的快速回答,但您的解决方案不起作用。除了您的解决方案之外,我尝试了有无戴夫的建议。在 GoToUrl() 处仍然无限加载 它终止时显示什么?有错误吗? 我看过你的输出,但没有说任何有用的东西。我不能自己运行它,所以我无法验证它。可以尝试的一些事情: 1. 当您传递实际的 newegg url 而不是临时文件时,它会加载页面吗?这将验证这是文件问题还是站点问题。 2. 检查不存在的文件是否抛出错误。 3. 尝试使用 PhantomJS 1.9.7 而不是 1.9.8。这应该没什么区别,但在 1.9.8 中引入了一个新错误。 4.将扩展名从htm改为html。 1.是的。 2. 不存在的文件没有错误。然后 PageSource 返回一个空的 html 结构。 3. 这可行,但速度极慢(大约 1 分钟的加载时间)。这同样适用于将 1.9.8 与解决方法 driverService.SslProtocol = "tlsv1" 一起使用。 4.没有区别。谢谢你这么有帮助。如果您能帮助我解决极慢的加载时间,我会很高兴。

以上是关于PhantomJS 传递 HTML 字符串并返回页面源的主要内容,如果未能解决你的问题,请参考以下文章

uniapp返回上一页并传递参数

如何获取嵌入在 PhantomJS 运行的 JS 的 HTML 页面结果中的 JSON 对象并将它们传递给 java 代码?

[错误:PhantomJS退出并返回值为127]

当URL错误时,PhantomJS不会返回错误(python)

Phantomjs 不会使用自定义样式呈现页脚

如何为搜索引擎优化 PhantomJS 以索引单页应用程序?