博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
模拟Snap.com,支持js引入对链接预览的简单实现
阅读量:7095 次
发布时间:2019-06-28

本文共 4643 字,大约阅读时间需要 15 分钟。

 在前天的POST中,实现了的类,今天改善了一下,修正了内部的资源释放问题。并且完善了WebPageSnapshot类,将目标页面的错误对话框和新窗口问题处理了一下。总之抓图速度过慢,还想不出什么改善的办法;在它的代码中实现了一个很好的改善速度的办法,就是把抓的图直接存盘,只是还缺少一个更新机制,所以我在此基础上增加了一个Hashtable,它的key 存放原始url,value 保存抓取的时间,当产生抓取请求的时候,先访问该hashtable,如果不存在则记录一笔,否则就比较一下时间,是否超过1天,超过的话继续抓取,否则直接传递上次抓取的图象文件,为了简单,该hashtable未持久化处理。

简单的cache机制:

ContractedBlock.gif
ExpandedBlockStart.gif
简单CACHE机制的实现
None.gif
using System;
None.gif
using System.Web;
None.gif
using System.Web.Caching;
None.gif
using System.Web.Security;
None.gif
using System.Text;
None.gif
using SnapLibrary;
None.gif
using System.Threading;
None.gif
using System.Drawing;
None.gif
using System.Collections;
None.gif
using System.IO;
None.gif
ExpandedBlockStart.gif
ContractedBlock.gif
/**/
///
<summary>
InBlock.gif
///
简单CACHE机制的实现
ExpandedBlockEnd.gif
///
</summary>
None.gif
public
static
class SnapPreviewCache
ExpandedBlockStart.gif
ContractedBlock.gif
dot.gif{
InBlock.gif
//
线程超时(毫秒)
InBlock.gif
static
int ThreadTimeOut = 120000;
InBlock.gif
//
页面的超时(毫秒)
InBlock.gif
static
int GetPageTimeOut = 100000;
InBlock.gif
//
hashtable,登记每笔的抓取时间
InBlock.gif
static Hashtable cacheTable =
new Hashtable();
InBlock.gif
InBlock.gif
static SnapPreviewCache()
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
ExpandedSubBlockEnd.gif }
InBlock.gif
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
/**/
///
<summary>
InBlock.gif
///
简单处理url 到 file的方法,base64编码
InBlock.gif
///
</summary>
InBlock.gif
///
<param name="previewUrl">
url
</param>
ExpandedSubBlockEnd.gif
///
<returns>
文件名
</returns>
InBlock.gif
static
string adjustPreviewUrl(
string previewUrl)
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
InBlock.gif
return Convert.ToBase64String(Encoding.GetEncoding("GB2312").GetBytes(previewUrl), Base64FormattingOptions.None);
ExpandedSubBlockEnd.gif }
InBlock.gif
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
/**/
///
<summary>
InBlock.gif
///
创建一个图象
InBlock.gif
///
</summary>
InBlock.gif
///
<param name="previewUrl">
url
</param>
ExpandedSubBlockEnd.gif
///
<returns>
物理文件名
</returns>
InBlock.gif
public
static
string CreateSnapPreviewFile(
string previewUrl)
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
InBlock.gif
//
STA线程模式
InBlock.gif
Thread threadProc =
new Thread(STAThreadProc);
InBlock.gif threadProc.SetApartmentState(ApartmentState.STA);
InBlock.gif
//
线程函数参
InBlock.gif
SnapPreviewFileParam sp =
new SnapPreviewFileParam();
InBlock.gif sp.Exception =
null;
InBlock.gif sp.File = HttpContext.Current.Request.PhysicalApplicationPath + "Caches\\" + adjustPreviewUrl(previewUrl) + ".jpg";
InBlock.gif sp.Url = previewUrl;
InBlock.gif
//
图体积(参考snap.com)
InBlock.gif
sp.Width = 274;
InBlock.gif sp.Height = 161;
InBlock.gif threadProc.Start(sp);
InBlock.gif
try
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
InBlock.gif
if (!threadProc.Join(ThreadTimeOut))
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
InBlock.gif threadProc.Abort();
InBlock.gif
throw
new TimeoutException();
ExpandedSubBlockEnd.gif }
InBlock.gif
InBlock.gif
if (sp.Exception !=
null)
InBlock.gif
return sp.Exception.Message;
ExpandedSubBlockEnd.gif }
InBlock.gif
catch
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
InBlock.gif sp.File = HttpContext.Current.Request.PhysicalApplicationPath + "Caches\\loading.gif";
ExpandedSubBlockEnd.gif }
InBlock.gif
return sp.File;
ExpandedSubBlockEnd.gif }
InBlock.gif
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
/**/
///
<summary>
InBlock.gif
///
线程函数
InBlock.gif
///
</summary>
ExpandedSubBlockEnd.gif
///
<param name="p"></param>
InBlock.gif
static
void STAThreadProc(
object p)
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
InBlock.gif SnapPreviewFileParam sp = (p
as SnapPreviewFileParam);
InBlock.gif
InBlock.gif
//
检查是否需要更新
InBlock.gif
bool update =
false;
InBlock.gif
InBlock.gif
if (cacheTable.ContainsKey(sp.Url))
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
InBlock.gif DateTime dt = (DateTime)cacheTable[sp.Url];
InBlock.gif TimeSpan ts = DateTime.Now - dt;
InBlock.gif
if (ts.TotalDays > 1)
InBlock.gif update =
true;
ExpandedSubBlockEnd.gif }
InBlock.gif
else
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
InBlock.gif update =
true;
InBlock.gif cacheTable.Add(sp.Url, DateTime.Now);
ExpandedSubBlockEnd.gif }
InBlock.gif
InBlock.gif cacheTable[sp.Url] = DateTime.Now;
InBlock.gif
if (!update && File.Exists(sp.File))
InBlock.gif
return;
InBlock.gif
InBlock.gif
//
构造webpage snapshot class
InBlock.gif
WebPageSnapshot wpsh =
new WebPageSnapshot();
InBlock.gif wpsh.Width = 300;
InBlock.gif wpsh.Height = 300;
InBlock.gif wpsh.Url = sp.Url;
InBlock.gif wpsh.TimeOut = GetPageTimeOut;
InBlock.gif
InBlock.gif Bitmap bmp =
new Bitmap(sp.Width, sp.Height);
InBlock.gif Graphics g = Graphics.FromImage(bmp);
InBlock.gif
InBlock.gif
try
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
InBlock.gif
//
局部复制
InBlock.gif
g.DrawImage(wpsh.TakeSnapshot(), 0, 0);
InBlock.gif bmp.Save(sp.File);
ExpandedSubBlockEnd.gif }
InBlock.gif
catch (Exception ex)
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
InBlock.gif sp.Exception = ex;
ExpandedSubBlockEnd.gif }
InBlock.gif
finally
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
InBlock.gif g.Dispose();
InBlock.gif bmp.Dispose();
ExpandedSubBlockEnd.gif }
ExpandedSubBlockEnd.gif }
ExpandedBlockEnd.gif}
None.gif
ExpandedBlockStart.gif
ContractedBlock.gif
/**/
///
<summary>
InBlock.gif
///
线程函数参类
ExpandedBlockEnd.gif
///
</summary>
None.gif
class SnapPreviewFileParam
ExpandedBlockStart.gif
ContractedBlock.gif
dot.gif{
InBlock.gif
public
string File;
InBlock.gif
public
string Url;
InBlock.gif
public
int Width;
InBlock.gif
public
int Height;
InBlock.gif
public Exception Exception;
ExpandedBlockEnd.gif}

通过google搜索到一个脚本提示的实现代码,简单的改了改,将行为模拟成snap.com 提供的服务那样,把鼠标指到超级链接并停顿1秒后,显

示目标PAGE的图象。js脚本我只做了微小的调整,原作者我无法得知,比较遗憾。

有了前端JS的实现,那么后端与脚本之间的接口也很简单。

后端Snap_Preview.aspx页面只接收2个参数,分别为: href 和 domain

domain 是指当传递的url只是相对地址的时候,整合为完整地址。

href 则就是目标页的地址。

在snap_preview.aspx页的 Load 事件内写入:

None.gif
protected
void Page_Load(
object sender, EventArgs e)
ExpandedBlockStart.gif
ContractedBlock.gif
dot.gif {
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
/**/
///
清空缓冲
InBlock.gif Response.Clear();
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
/**/
///
目标地址
InBlock.gif
string href = Request["href"];
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
/**/
///
调用页域名称
InBlock.gif
string domain = Request["domain"];
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
/**/
///
是否显示空白页
InBlock.gif
if (
string.IsNullOrEmpty(href) || href.Equals("about:blank", StringComparison.CurrentCultureIgnoreCase))
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
dot.gif{
InBlock.gif Response.TransmitFile(
InBlock.gif HttpContext.Current.Request.PhysicalApplicationPath + "Caches\\loading.gif"
InBlock.gif );
InBlock.gif
return;
ExpandedSubBlockEnd.gif }
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
/**/
///
处理url的简单办法
InBlock.gif
if (href.IndexOf("http://") == -1)
InBlock.gif
if (!
string.IsNullOrEmpty(domain))
InBlock.gif href = domain.TrimEnd('/') + "/" + href;
InBlock.gif
InBlock.gif
if (href.IndexOf("http://") == -1)
InBlock.gif href = "http://" + href;
InBlock.gif
ExpandedSubBlockStart.gif
ContractedSubBlock.gif
/**/
///
传送图象
InBlock.gif Response.TransmitFile(SnapPreviewCache.CreateSnapPreviewFile(href));
InBlock.gif
ExpandedBlockEnd.gif }

这样通过脚本代码的整合,即可简单的做成一个snap.com的功能雏形,不过它有很多的问题。其中最主要的就是速度慢的问题。

速度慢主要因为WebBrowser 的运行方式是;单线程单元模型 (STA):进程中一个或多个线程使用 COM ,并且 COM 对象的调用由 COM 进行同

步。在线程间对接口进行编组。单线程单元模型的退化情况(其中,在给定的进程中只有一个线程使用 COM)被称为单线程模型。以前的

Microsoft 信息与文档曾经将 STA 模型简单地称为“单元模型”。 它的运行线程应该是消息或用户界面 (UI) 线程。

而被封装到 web 组件里来隐含调用,则必须为它开辟一个STA线程,这样使它的性能大大降低,因为多次构造对象和释放对象都是非常浪费资

源的事情,初始化的速度太慢,是影响速度的最大原因。

另外,我将这次的工程代码全部发放出来,供各位研究,能有所改善则更好,也希望各位能发扬知识共享精神,让大家共同进步。

工程代码下载(含全部源码),可能有bug若干:

测试运行之前请确认Snap_Preview_Anywhere.js中的sServiceUrlRoot变量指向的是正确的地址。

运行外观:

本文转自suifei博客园博客,原文链接:http://www.cnblogs.com/Chinasf/archive/2006/12/27/605035.html,如需转载请自行联系原作者

你可能感兴趣的文章