c# ajax网页 截图

风雨兼程头发茂盛 2018-07-27 02:25:08
试过几种方法都没有成功,静态站的网页可以截图下来,但是动态加载的要么截图不全,要么干脆就是一张空白图片,有前辈会吗?
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{

//StreamReader sr = new StreamReader(webBrowser1.DocumentStream, Encoding.GetEncoding("gb2312"));
//textBox2.Text = sr.ReadToEnd();
WebBrowser wb = (WebBrowser)sender;
// 网页加载完毕才保存
if (wb.ReadyState == WebBrowserReadyState.Complete)
{
// 获取网页高度和宽度,也可以自己设置
int height = wb.Document.Body.ScrollRectangle.Height;
int width = wb.Document.Body.ScrollRectangle.Width;

// 调节webBrowser的高度和宽度
wb.Height = height;
wb.Width = width;

Bitmap bitmap = new Bitmap(width, height); // 创建高度和宽度与网页相同的图片
Rectangle rectangle = new Rectangle(0, 0, width, height); // 绘图区域
wb.DrawToBitmap(bitmap, rectangle); // 截图

// 保存图片对话框
SaveFileDialog saveFileDialog = new SaveFileDialog();
saveFileDialog.Filter = "JPEG (*.jpg)|*.jpg|PNG (*.png)|*.png";
saveFileDialog.ShowDialog();

bitmap.Save(saveFileDialog.FileName); // 保存图片
}



}
...全文
1486 34 打赏 收藏 转发到动态 举报
写回复
用AI写文章
34 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
在 webbrowser 中,当页面上有资源下载时,会不断地触发 DocumentCompleted 事件。你也已经写了你是判断了
 if (wb.ReadyState == WebBrowserReadyState.Complete)
这个条件的了。

那么现在是因为有很多异步操作,你并不是要等待页面 html 加载完毕!!那么自然就要回归自然,去搞明白自己到底要等待什么东西?

比如说,等待 DocumentCompleted 事件“消停了5秒钟”,那么你就用一个定时器来控制你的任务处理机制,每当 DocumentCompleted 事件触发时就推迟 5 秒钟才触发。

总之,编程设计要回归自然。真正的逻辑设计不是来自于代码,而是来自于软件以外的东西。
  • 打赏
  • 举报
回复
我上面只是随便举一个例子。实际的设计绝对不是限于什么“消停了5秒钟”这种想当然之中。设计靠你自己反复说明,你都说不出来,别人更不知道来源。
  • 打赏
  • 举报
回复
抛开什么“程序”,你自己说清楚一点,假设你是手工操作者,你怎么保证开始打印或者滚动截图的时候整个页面已经显示完毕了呢?

你把这个说清楚,那么编程设计才有根基。如果这个都不说清楚,其实编程就是蒙。
闭包客 2018-08-01
  • 打赏
  • 举报
回复
有一些网页元素,比如京东首页的目录,要鼠标移过才会加载,所以还需要程序触发鼠标移过的事件。

现在还有一种流行做法,有些网页元素,一般是 img,要显示在浏览器的可视范围内,才会加载,这些都需要程序去控制。
闭包客 2018-08-01
  • 打赏
  • 举报
回复
ajax 的网页截图有一个关键问题,就是截图的时间点。

一般的做法是要检查自己需要的元素是否已经加载,还没加载就继续等待,加载完成才截图。
qq_42200051 2018-07-29
  • 打赏
  • 举报
回复
谢谢楼主分享
  • 打赏
  • 举报
回复
引用 29 楼 qq_39648087 的回复:
逛逛,谢谢楼主分享

客气了老哥,这个问题我也还没解决
qq_39648087 2018-07-28
  • 打赏
  • 举报
回复
逛逛,谢谢楼主分享
  • 打赏
  • 举报
回复

  • 打赏
  • 举报
回复
引用 23 楼 qwjcy0078 的回复:
如果已经执行到Console.ReadLine();
你就看看C:/Users/xl/Desktop/test.jpeg这个目录下这张图片是不是存在。

前辈试试打印这个页面试试:https://item.jd.com/6117535.html
为啥csdn的可以打印,天猫和京东的就不行呢
  • 打赏
  • 举报
回复
引用 23 楼 qwjcy0078 的回复:
如果已经执行到Console.ReadLine();
你就看看C:/Users/xl/Desktop/test.jpeg这个目录下这张图片是不是存在。


using System;
using System.Windows.Forms;
using System.Threading;
using System.Diagnostics;
using System.IO;

namespace testss
{
class WebHelper
{
private string link;
private string path;
private string serverPath;
public WebHelper(string link, string path, string serverpath)
{
this.link = link;
this.path = path;
this.serverPath = serverpath;
}
/// <summary>
/// 启用新线程
/// </summary>
public void GetImg()
{
var m_thread = new Thread(GetHtmlImage);
m_thread.SetApartmentState(ApartmentState.STA);
m_thread.Start();
m_thread.Join();
}
/// <summary>
/// 调用截图方法,然后进行等待,一直到图片生成为止
/// </summary>
private void GetHtmlImage()
{

GetImg1(link, path, serverPath);
while (true)
{
if (File.Exists(serverPath + "\\" + path))
{
break;
}
DateTime current = DateTime.Now;
while (current.AddMilliseconds(2000) > DateTime.Now)
{
Application.DoEvents();//转让控制权
}
}
}
/// <summary>
/// 进行截图
/// </summary>
/// <param name="links">截图网页链接</param>
/// <param name="path">截图生成的文件存放的路径及其文件名</param>
/// <param name="serverPath">phantomjs.exe与screenshot.js所在目录的路径</param>
/// <returns></returns>
public bool GetImg1(string links, string path, string serverPath)
{
try
{
Process p = new Process();
p.StartInfo.FileName = serverPath + @"\phantomjs.exe";
// p.StartInfo.FileName = @"E:\SoftWare\phantomjs-2.1.1-windows\bin\phantomjs.exe";
p.StartInfo.WorkingDirectory = serverPath + @"\";
p.StartInfo.Arguments = string.Format(serverPath + @"\test.js " + links + " " + path);

p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;

p.Start();
return true;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
// Console.WriteLine(ex.Message);
return false;
}
}

}
}




//WebHelper web = new WebHelper("", "", @"C:\Users\xl\Desktop\testss\testss\Pic");
web.GetImg();


我这样调用倒是成功了,打印了这个页面,我把js里面的代码修改了网址,就没反应了 还在研究中
镜之新开 2018-07-27
  • 打赏
  • 举报
回复
如果已经执行到Console.ReadLine();
你就看看C:/Users/xl/Desktop/test.jpeg这个目录下这张图片是不是存在。
  • 打赏
  • 举报
回复
引用 5 楼 qwjcy0078 的回复:
你可以尝试外部调取phantomjs来截取页面

JS:

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

page.viewportSize = { width: 1920, height: 1080 };
page.open("https://bbs.csdn.net/topics/392422441?page=1#post-403373637", function start(status) {
window.setTimeout(function(){
//var base64 = page.renderBase64('PNG');
//console.log(base64);
page.render('C:/Users/xl/Desktop/test.jpeg', {format: 'jpeg', quality: '100'});
phantom.exit();
},5000);

});

C#:

using System;
using System.Diagnostics;

namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo = new System.Diagnostics.ProcessStartInfo(@"cmd.exe", @"/d " + "C:/Users/xl/source/repos/ConsoleApp1/ConsoleApp1/Pic/phantomjs.exe " + "C:/Users/xl/source/repos/ConsoleApp1/ConsoleApp1/Pic/test.js");
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.UseShellExecute = false; //是否使用操作系统shell启动
process.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
process.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
process.StartInfo.RedirectStandardError = true;//重定向标准错误输出
process.StartInfo.CreateNoWindow = false;//不显示程序窗口


try
{
/*
* 异步调用
*/
process.Start();

}
catch (System.Exception ex)
{
Debug.WriteLine(ex.Message);
}

Console.WriteLine(process.StandardOutput.ReadToEnd());

Console.ReadLine();
}
}
}

不知道哪里出了问题,程序没反应
  • 打赏
  • 举报
回复
引用 20 楼 qwjcy0078 的回复:
可以借助phantomjs工具来实现截图,用控制台调取这个工具。
先到官网下载http://phantomjs.org/download.html,windows版。
安装好之后把phantomjs.exe放到一个目录下,并编辑一个js文件同样放到这个目录下:


test.js:

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

page.viewportSize = { width: 1920, height: 1080 };
page.open("https://bbs.csdn.net/topics/392422441?page=1#post-403373637", function start(status) {
window.setTimeout(function(){
//var base64 = page.renderBase64('PNG');
//console.log(base64);
page.render('c:/Utils/bin/test.jpeg', {format: 'jpeg', quality: '100'});
phantom.exit();
},5000);

});

这里设置5秒延迟是为了加载图片什么的。

然后程序进行调用:

static void Main(string[] args)
{
//ClientInit();

System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo = new System.Diagnostics.ProcessStartInfo(@"cmd.exe", @"/d " + "C: /c /Utils/bin/phantomjs.exe " + "C:/Utils/bin/test.js");
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.UseShellExecute = false; //是否使用操作系统shell启动
process.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
process.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
process.StartInfo.RedirectStandardError = true;//重定向标准错误输出
process.StartInfo.CreateNoWindow = false;//不显示程序窗口


try
{
/*
* 异步调用
*/
process.Start();

}
catch (System.Exception ex)
{
Debug.WriteLine(ex.Message);
}

Console.WriteLine(process.StandardOutput.ReadToEnd());

Console.ReadLine();
}


截图保存在c:/Utils/bin/test.jpeg。

也可以直接返回Base64编码的数据,test.js换成这样:
var webPage = require('webpage');
var page = webPage.create();

page.viewportSize = { width: 1920, height: 1080 };
page.open("https://bbs.csdn.net/topics/392422441?page=1#post-403373637", function start(status) {
window.setTimeout(function(){
var base64 = page.renderBase64('PNG');
console.log(base64);
phantom.exit();
},5000);

});


控制台就直接输出数据了,你也可以调取这个数据再在其它地方渲染成图片。

再次谢谢前辈,我试试哈,辛苦了,拜谢
镜之新开 2018-07-27
  • 打赏
  • 举报
回复
可以借助phantomjs工具来实现截图,用控制台调取这个工具。
先到官网下载http://phantomjs.org/download.html,windows版。
安装好之后把phantomjs.exe放到一个目录下,并编辑一个js文件同样放到这个目录下:


test.js:

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

page.viewportSize = { width: 1920, height: 1080 };
page.open("https://bbs.csdn.net/topics/392422441?page=1#post-403373637", function start(status) {
window.setTimeout(function(){
//var base64 = page.renderBase64('PNG');
//console.log(base64);
page.render('c:/Utils/bin/test.jpeg', {format: 'jpeg', quality: '100'});
phantom.exit();
},5000);

});

这里设置5秒延迟是为了加载图片什么的。

然后程序进行调用:

static void Main(string[] args)
{
//ClientInit();

System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo = new System.Diagnostics.ProcessStartInfo(@"cmd.exe", @"/d " + "C: /c /Utils/bin/phantomjs.exe " + "C:/Utils/bin/test.js");
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.UseShellExecute = false; //是否使用操作系统shell启动
process.StartInfo.RedirectStandardInput = true;//接受来自调用程序的输入信息
process.StartInfo.RedirectStandardOutput = true;//由调用程序获取输出信息
process.StartInfo.RedirectStandardError = true;//重定向标准错误输出
process.StartInfo.CreateNoWindow = false;//不显示程序窗口


try
{
/*
* 异步调用
*/
process.Start();

}
catch (System.Exception ex)
{
Debug.WriteLine(ex.Message);
}

Console.WriteLine(process.StandardOutput.ReadToEnd());

Console.ReadLine();
}


截图保存在c:/Utils/bin/test.jpeg。

也可以直接返回Base64编码的数据,test.js换成这样:
var webPage = require('webpage');
var page = webPage.create();

page.viewportSize = { width: 1920, height: 1080 };
page.open("https://bbs.csdn.net/topics/392422441?page=1#post-403373637", function start(status) {
window.setTimeout(function(){
var base64 = page.renderBase64('PNG');
console.log(base64);
phantom.exit();
},5000);

});


控制台就直接输出数据了,你也可以调取这个数据再在其它地方渲染成图片。

  • 打赏
  • 举报
回复
引用 17 楼 xuzuning 的回复:
DrawToBitmap 需要重新加载一次页面,第二次加载时可能失败了
你或许可以考虑屏幕截图

屏幕截图有点尴尬啊,如果网页够长的话会有部分超出浏览器了,做截屏的话又要考虑滚屏拼接问题了
  • 打赏
  • 举报
回复
引用 14 楼 xomix 的回复:
webblower截图比较好的方案是在页面中注入js,然后利用页面js截图后调用后台事件。

上面有前辈说用phantomjs,现在熟悉中,不知道可不可行。直接在webblower里面插入js还没试,等下试试看看效果如何,谢谢前辈哈
xuzuning 2018-07-27
  • 打赏
  • 举报
回复
DrawToBitmap 需要重新加载一次页面,第二次加载时可能失败了
你或许可以考虑屏幕截图
  • 打赏
  • 举报
回复
引用 13 楼 closurer 的回复:
你还需要解决一个问题就是,怎么判断一个 ajax 加载的网页已经加载完成?

如果好用的第三方插件的话,那估计只能用浏览器插件了,间隔下滚,滚到底了为止
  • 打赏
  • 举报
回复
引用 12 楼 StratosBlue 的回复:

[DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
private static extern int BitBlt(HandleRef hDC, int x, int y, int nWidth, int nHeight, HandleRef hSrcDC, int xSrc, int ySrc, int dwRop);

private Bitmap ScreenShuts(int x, int y, int width, int height, int left, int right)
{
Rectangle rect = new Rectangle();

rect = this.Bounds;
Graphics g1 = this.CreateGraphics();
Bitmap result = new Bitmap(width, height, g1);

Graphics g2 = Graphics.FromImage(result);
IntPtr dc1 = g1.GetHdc();
HandleRef hDcSrc = new HandleRef(null, dc1);
IntPtr dc2 = g2.GetHdc();
HandleRef hDcSave = new HandleRef(null, dc2);
const int SRCCOPY = 0xcc0020;

BitBlt(hDcSave, x, y, width, height, hDcSrc, left, right, SRCCOPY);

g1.ReleaseHdc(dc1);
g2.ReleaseHdc(dc2);

return result;
}

这样截图看看能满足你的需求不

这是截屏吗老哥
加载更多回复(14)

110,566

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧