利用Webbrowser类实现超长网页的截屏的实现.docx

上传人:b****5 文档编号:6830847 上传时间:2023-01-10 格式:DOCX 页数:15 大小:20.99KB
下载 相关 举报
利用Webbrowser类实现超长网页的截屏的实现.docx_第1页
第1页 / 共15页
利用Webbrowser类实现超长网页的截屏的实现.docx_第2页
第2页 / 共15页
利用Webbrowser类实现超长网页的截屏的实现.docx_第3页
第3页 / 共15页
利用Webbrowser类实现超长网页的截屏的实现.docx_第4页
第4页 / 共15页
利用Webbrowser类实现超长网页的截屏的实现.docx_第5页
第5页 / 共15页
点击查看更多>>
下载资源
资源描述

利用Webbrowser类实现超长网页的截屏的实现.docx

《利用Webbrowser类实现超长网页的截屏的实现.docx》由会员分享,可在线阅读,更多相关《利用Webbrowser类实现超长网页的截屏的实现.docx(15页珍藏版)》请在冰豆网上搜索。

利用Webbrowser类实现超长网页的截屏的实现.docx

利用Webbrowser类实现超长网页的截屏的实现

截这个网页图的时候,总是报错,说是无效的参数

后来分析代码发现,这个网页的大小为1024px*81175px。

当时,一激灵,立刻想到是不是太长了,超过系统的默认范围。

查了资料后,在MSDN上有一处说到GDI+的bitmap对象在保存为PNG格式的时候,单维不能超过65536,但是并没有说其它格式也有类似的局限。

于是,自已做了一个实验,构造一个bitmap对象,大小1024px*80000px,保存为PNG格式,系统报错;保存为JPG格式,系统报错;保存为bmp格式,系统没有报错,但是在其他的软件中不能打开。

于是,笔者坚信一点

GDI+中的bitmap对象处理的单维不能超过65526

很显然,上面的网址,用GDI+来截取的话,肯定是不能截取到一张图片上了

有一点,在机器上用FF浏览器浏览网页,发现右上角有一个“网页截图”的插件,于是尝试用FF截取上面的网址,发现丝毫没有反映。

笔者尝试截取其他的网址以证实不是笔者自己的误操作问题,其他网页截取正常。

说明了一点

截取超长网页(长度超过65536)是个难题

于是,反思自己截图的意图。

为何要截图?

截图是为了保存网页,以便日后再看,避免网址失效的尴尬。

那有的人就会说,没和不保存网页(MHT格式或其他格式)。

保存网页或多或少都有各种问题

用IE保存网页的时候,Flash只是保存链接地址,而不是保存swf文件

有的网页中的内容是通过JS用Ajax方式后台读取呈现,这部分在保存网页的时候,仅仅保存了JS代码,而没有保存JS用Ajax方式后台读取的内容

有的网页在JS中再动态调用CSS或其他的JS代码,这部分在保存网页的时候,也仅仅是保存了JS代码,而动态调用的CSS和JS代码什么的都没有保存

上述这些情况,都是以保存链接地址的形式(swf地址或者是JS地址)出现的

在日后浏览的时候,如果是在一台没有联网的机器上,会出现两种情况。

一是:

由于保存了链接地址,于是会尝试读取这些地址,而这些地址又没法读取(没联网或者是链接地址失效),则会导致长时间的假死状态(尤其以IE保存的网页为甚);二是:

由于缺失部分的文件(swf文件、CSS文件、JS文件等),导致页面的结构出现了变形(甚至是无法忍受的地步)。

这也就是为什么要截图的原因,图是静止的,不会出现上述的情况

还是要截图的,截超长网页的图的一种办法就是分开截图,截成若干个图

于是把之前的代码改写一下,把原来多次截图,后覆写到一张图片,改写为多次截图,把多个bitmap对象存入到一个对象

于是信心满满的尝试文章开始的网址,天啊,还是报错

在截超长网页的时候,在截60000+这部分的时候,Webbrowser类的DrawToBitmap函数就会报错,说是无效的参数。

无效的参数?

没道理呀,若是参数无效,在截0+和20000+的时候就会报错,怎么会到60000+的时候报错呢?

而且是每次到60000+都会报错,排除了系统随机性错误的问题(有时在截一些网页的时候,也会报参数无效的错误,但是重启软件后,就不会报错)

突然有一个想法,会不会是Webbrowser类的DrawToBitmap方法有资源没有释放,在同一个Webbrowser的实例中的DrawToBitmap方法执行完后,没有释放资源,所以当上面的代码尝试截取60000+的时候,超过了DrawToBitmap方法的资源限制,于是报了错误。

如果能尝试释放DrawToBitmap方法所占的资源是不是就可以呢?

在网上找了一圈后,没有发现释放DrawToBitmap方法所占的资源的问题。

这真是一个超级难题了。

有一个笨办法涌上心头。

一个Webbrowser实例不能解决超长网页的截图问题,多个Webbrowser实例能不能解决该问题呢?

将一个网页分成几个部分,每个部分分给一个Webbrowser实例去截图,最后将这些截图再存入到一个对象。

这样做的优点是:

如果成功,解决了超长网页的截图问题;缺点是:

每个部分都分给一个Webbrowser类的实例去截图,每个实例都需要访问同一个网址,造成了重复访问,形成了资源浪费。

不过,目前最重要的是实现超长网页的截图。

于是,修改代码。

进行截图实验。

嗯。

这样终于成功了。

下面是修改后代码。

由于功能上的需要,我对代码进行了扩展

PublicClassclsCaptureWebSettings

PublicUrlAsString

PublicTimeOutAsInteger

PublicWidthAsInteger

PublicDelayAsInteger

PublicHtmlElementID()AsString={}

PublicSubNew(UrlAsString,OptionalDelayAsInteger=15,OptionalTimeOutAsInteger=180,OptionalWidthAsInteger=1024)

Me.Url=Url

Me.TimeOut=TimeOut

Me.Width=Width

Me.Delay=Delay

Me.HtmlElementID={}

EndSub

PublicSubNew(UrlAsString,IDAsString,OptionalDelayAsInteger=15,OptionalTimeOutAsInteger=180,OptionalWidthAsInteger=1024)

DimtS(0)AsString

tS(0)=ID

Me.Url=Url

Me.TimeOut=TimeOut

Me.Width=Width

Me.Delay=Delay

Me.HtmlElementID=tS

EndSub

PublicSubNew(UrlAsString,ID()AsString,OptionalDelayAsInteger=15,OptionalTimeOutAsInteger=180,OptionalWidthAsInteger=1024)

Me.Url=Url

Me.TimeOut=TimeOut

Me.Width=Width

Me.Delay=Delay

Me.HtmlElementID=ID

EndSub

EndClass

clsCaptureWebSettings类,截取网页的参数类,有如下的几个参数:

URL

网页截图的网址。

注:

有些网页要提供Cookies或者是Session才能访问,这部分目前还没有做到。

Delay

网页截图的延迟。

由于有部分网页会利用AJAX技术填充内容,而Webbrowser类又不能很好的判断AJAX技术的结束时刻,故统一一个延迟时间,等延迟时间结束以后再截图。

默认是15秒。

注:

由于有的超长网页会交给几个Webbrowser类截图,每个Webbrowser类的延迟时间都是由Delay决定的,故在截超长网页的时候,会显得比较漫长,但是用了Delay参数以后,截图的效果好了很多。

TimeOut

网页截图的超时。

在访问某些网站的时候,由于种种原因,导致访问失败。

设置这个参数避免在访问失败的时候,程序陷入假死情况。

默认是180秒

Width

网页截图的宽度。

由于网页的布局都是竖式布局,故先指定宽度,再截图。

默认是1024,现今的网页基本上都兼容1024的宽度

HtmlElementID

网页截图中的目标ID。

我们在截网页的时候,有时特别想只截其中的一部分(例如,不想截取包含广告的部分),我们可以提供网页上的元素的ID,返回该元素在网页上的位置(Rectangle结构)。

该参数是字符串的数组,数组中每个元素就是网页上元素的ID。

注意:

程序中只返回能找到的元素的位置,如果没有找到,则直接忽略掉

PublicClassclsCaptureImages

Private_BmpAsList(OfBitmap)

Private_RectAsDictionary(OfString,Rectangle)

Private_HeightPerImageAsInteger

PublicSubNew()

Me.New(20000)

EndSub

PublicSubNew(HeightPerImageAsInteger)

_HeightPerImage=HeightPerImage

_Bmp=NewList(OfBitmap)

_Rect=NewDictionary(OfString,Rectangle)

EndSub

PublicSubAddBitmap(BmpAsBitmap)

_Bmp.Add(Bmp)

EndSub

PublicSubAddRect(IDAsString,RAsRectangle)

If_Rect.ContainsKey(ID)=TrueThen

_Rect(ID)=R

Else

_Rect.Add(ID,R)

EndIf

EndSub

PublicFunctionImageRect()AsRectangle

If_Bmp.Count=0ThenReturnNewRectangle(0,0,0,0)

DimWidthAsInteger=_Bmp(0).Width

DimHeightAsInteger=_HeightPerImage*(_Bmp.Count-1)+_Bmp(_Bmp.Count-1).Height

ReturnNewRectangle(0,0,Width,Height)

EndFunction

PrivateFunctionGetRectImage(RAsRectangle)AsBitmap

DimtBAsNewBitmap(R.Width,R.Height)

UsingtGAsGraphics=Graphics.FromImage(tB)

DimIAsInteger=Int(R.Y/_Bmp(0).Height)

DimJAsInteger=Int((R.Bottom-1)/_Bmp(0).Height)

DimKAsInteger

IfI=JThen

R.Y=R.YMod_Bmp(0).Height

tG.DrawImage(_Bmp(I),0,0,R,GraphicsUnit.Pixel)

Else

DimtRAsRectangle=R

tR.Y=tR.YMod_Bmp(0).Height

tR.Height=_Bmp(0).Height-tR.Y

tG.DrawImage(_Bmp(I),0,0,tR,GraphicsUnit.Pixel)

DimtTopAsInteger=tR.Height

ForK=I+1ToJ-1Step1

tR=R

tR.Y=0

tR.Height=_Bmp(0).Height

tG.DrawImage(_Bmp(K),0,tTop,tR,GraphicsUnit.Pixel)

tTop+=tR.Height

Next

tR=R

tR.Height=(tR.Bottom-1)Mod_Bmp(0).Height+1

tR.Y=0

tG.DrawImage(_Bmp(J),0,tTop,tR,GraphicsUnit.Pixel)

EndIf

EndUsing

ReturntB

EndFunction

PublicFunctionRenderImage(RAsRectangle,HeightPerImageAsInteger)AsList(OfBitmap)

DimtRAsRectangle=ImageRect()

If_Bmp.Count=0OrElseR.IntersectsWith(tR)=FalseThenReturnNewList(OfBitmap)

R.Intersect(tR)

IfR.Equals(tR)=TrueAndAlsoHeightPerImage=_HeightPerImageThenReturn_Bmp

ReturnRenderImageBase(R,HeightPerImage)

EndFunction

PublicFunctionRenderImage(RAsRectangle)AsList(OfBitmap)

ReturnRenderImage(R,_HeightPerImage)

EndFunction

PublicFunctionRenderImage(HeightPerImageAsInteger)AsList(OfBitmap)

If_Bmp.Count=0ThenReturnNewList(OfBitmap)

IfHeightPerImage=_HeightPerImageThenReturn_Bmp

ReturnRenderImageBase(ImageRect,HeightPerImage)

EndFunction

PublicFunctionRenderImage()AsList(OfBitmap)

Return_Bmp

EndFunction

PrivateFunctionRenderImageBase(RAsRectangle,HeightPerImageAsInteger)AsList(OfBitmap)

DimtRAsRectangle=R

tR.Height=HeightPerImage

DimBmpListAsNewList(OfBitmap)

DoWhileR.IntersectsWith(tR)=True

tR.Intersect(R)

BmpList.Add(GetRectImage(tR))

tR.Offset(0,HeightPerImage)

Loop

ReturnBmpList

EndFunction

PublicFunctionRenderImage(HeightPerImageAsInteger,ID1AsString)AsList(OfBitmap)

If_Rect.ContainsKey(ID1)=FalseThenReturnNewList(OfBitmap)

ReturnRenderImage(_Rect(ID1),HeightPerImage)

EndFunction

PublicFunctionRenderImage(ID1AsString)AsList(OfBitmap)

If_Rect.ContainsKey(ID1)=FalseThenReturnNewList(OfBitmap)

ReturnRenderImage(_Rect(ID1),_HeightPerImage)

EndFunction

PublicFunctionRenderImage(ID1AsString,ParamArrayID()AsString)AsList(OfBitmap)

ReturnRenderImage(_HeightPerImage,ID1,ID)

EndFunction

PublicFunctionRenderImage(HeightPerImageAsInteger,ID1AsString,ParamArrayID()AsString)AsList(OfBitmap)

DimHasRectAsBoolean=False

DimRAsRectangle

If_Rect.ContainsKey(ID1)=TrueThen

HasRect=True

R=_Rect(ID1)

EndIf

DimIAsInteger

ForI=0ToID.Length-1

If_Rect.ContainsKey(ID(I))=TrueThen

IfHasRect=TrueThen

R=Rectangle.Union(R,_Rect(ID(I)))

Else

HasRect=True

R=_Rect(ID(I))

EndIf

EndIf

Next

IfHasRect=FalseThenReturnNewList(OfBitmap)

ReturnRenderImage(R,HeightPerImage)

EndFunction

EndClass

clsCaptureImages类,保存截图结果的类,由于超长网页不能截在一张图里,故用一个类保存截图的结果。

并提供一些扩展的功能

AddBitmap方法

PublicSubAddBitmap(BmpAsBitmap)

把截好的图片添加到类中

AddRect方法

PublicSubAddRect(IDAsString,RAsRectangle)

把ID对应的位置Rectangle添加到类中

RenderImage函数,返回图像的集合。

并可以根据某些参数定制图像集合。

例如:

只想获得某个Rectangle的范围的图像;只想获得某个ID的元素的图像;按照指定的高度划分图像集合等等。

如果我把截图放在Word里的话,最好每张的图片的高度不超过1200

返回值:

根据参数返回图像的集合List(OfBitmap)

它有如下的几个重载方式:

PublicFunctionRenderImage()AsList(OfBitmap)

不加修饰,直接把图像集合返回。

默认的图像集合中的每张图像的高度是20000

PublicFunctionRenderImage(RAsRectangle)AsList(OfBitmap)

返回指定区域R的截图图像集合。

程序会先计算整个图像的范围(利用ImageRect函数),然后返回的是R和ImageRect交集的图像集合,按照默认的高度(20000)划分每张图片

PublicFunctionRenderImage(HeightPerImageAsInteger)AsList(OfBitmap)

返回图像集合,每张图片的高度由HeightPerImage参数决定。

这个在将来要把图像放在Word里特别有用。

PublicFunctionRenderImage(RAsRectangle,HeightPerImageAsInteger)AsList(OfBitmap)

返回指定区域R的截图图像集合。

程序会先计算整个图像的范围(利用ImageRect函数),然后返回的是R和ImageRect交集的图像集合,按照参数HeightPerImage指定的高度划分每张图片的高度

PublicFunctionRenderImage(ID1AsString)AsList(OfBitmap)

返回指定ID1的元素所在位置的截图图像集合。

ID1所在的位置在之前的AddRect方法中添加到类中。

如果没有找到ID1对应的位置,则返回空的集合。

每张图像的高度由默认值(20000)决定

PublicFunctionRenderImage(HeightPerImageAsInteger,ID1AsString)AsList(OfBitmap)

返回指定ID1的元素所在位置的截图图像集合,每张图像的高度由HeightPerImage决定。

PublicFunctionRenderImage(ID1AsString,ParamArrayID()AsString)AsList(OfBitmap)

返回指定ID1和ID的元素所在位置的截图图像集合。

如果所有的ID指定的位置都不存在,返回空集合,否则返回存在的ID所在位置的并集所在位置的图像集合。

每张图像的高度由默认值(20000)决定

PublicFunctionRenderImage(HeightPerImageAsInteger,ID1AsString,ParamArrayID()AsString)AsList(OfBitmap)

返回指定ID1和ID的元素所在位置的截图图像集合。

如果所有的ID指定的位置都不存在,返回空集合,否则返回存在的ID所在位置的并集所在位置的图像集合。

每张图像的高度由HeightPerImage决定

PublicClassclsCaptureWebEx

PublicSharedFunctionCaptureWebEx(SettingsAsclsCaptureWebSettings)AsclsCaptureImages

Dim_ImagesAsNewclsCaptureImages

DimIAsInteger,JAsInteger

ConstWEB_HEIGHTAsInteger=20000

J=0

J=CaptureWebEx(_Images,Settings,J)

I=WEB_HEIGHT

DoWhileI

CaptureWebEx(_Images,Settings,I)

I+=WEB_HEIGHT

Loop

Return_Images

EndFunction

PrivateSharedFunctionCaptureWebEx(_ImagesAsclsCaptureImages,_SettingsAsclsCaptureWebSettings,_CapTopAsInteger)AsInteger

Dim_BmpAsBitmap

Dim

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 总结汇报 > 学习总结

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1