English

关于海猫

海猫是全球最好网页截图软件,基于FIREFOX浏览器构建,运行于LINUX系统上。 海猫可以抓拍整幅图片,可以抓拍页面上指定区域的图片,更可以抓拍以ID或classd或xpath标识的页面元素,可生成多种大小的缩略图,灵活性非常高。 对于美工、普通用户,海猫可以成批地抓拍他们感兴趣的网页,保存为图片,方便收藏与管理。 对于互联网站,诸如大型搜索引擎、垂直搜索引擎、在线书签、网址大全、地图等类网站,更是海猫大显身手的地方。 利用海猫来预览网站内容,如同snap.com一样,可显著提升用户体验,提高搜索准确度。 利用海猫抓拍的图片来作为网址或书签的标志,如alexa.com一样,更能有效提升网站观感、新鲜感,增加用户粘性。 利用海猫来抓拍地图,可为用户提供彩铃等增值服务。 随着时间的推移,带宽的增加,这种技术将会得到更广泛的应用。

功能特色

  1. 后台运行

    海猫作为一款LINUX服务器软件,运行于后台,不需要X-Windows。通过命令行工具和SOCKET调用与海猫进行通讯,获得服务。
  2. 采用线程池技术,多线程运行

    因为运行于多线程模式,又采用了线程池技术,所以海猫服务效率很高,能够同时接受来自不同用户的网页拍照请求。
  3. 缩略图大小可随意指定

    默认缩略图大小为160x120,但用户可以自行选择一个或多个不同的大小,海猫会根据要求生成指定大小的缩略图。
  4. 缩略图图片格式可指定

    默认输出png格式,但用户可以指定gif等其它格式,以适应不同情况。
  5. 能够抓拍整个页面

    一般的网页转图片软件只能转网页的第一页,但海猫能将整个页面抓拍下来,另存为图片,功能非常强大,发送请求只需指定enable-full为1即可,简单有效。
  6. 能够抓拍指定区域内容

    抓拍指定区域,需要用户指定抓拍左上角的坐标和区域宽高。提供这些数据后,海猫就能帮你自动完成抓拍工作。
  7. 能够抓拍由class或id或xpath标识的页面元素

    给定一个或多个class或id值,或者给定一个xpath,海猫就能帮你在页面中定位到这些元素,自动完成抓拍工作,方便用户抓拍页面部分内容。
  8. 接口简单

    海猫采用类似HTTP的操作协议,客户端程序通过SOCKET与其通讯,接受抓拍结果。这种方式的好处是WEB应用程序嵌入方便,一般的网站非常容易使用上海猫。最明显的应用例子就是抓糖网的“海猫抓图”了。

下载

seacat-5.5-1.en_US.fc9.i386.rpm (适用于Fedora Core 9兼容的Linux系统)
seacat-5.5-1.en_US.el5.i386.rpm (适用于RedHat EL 5/CentOS兼容的Linux系统)

安装前提条件

由于海猫使用ImageMagick软件作为图片处理的工具,所以必须首先安装ImageMagick, 确保存在/usr/bin/convert和/usr/bin/composite两个可执行文件。

安装

安装RPM包: rpm -ivh seacat*.rpm

海猫服务器管理

配置管理工具 - seacatctl

usage: seacatctl command
where command is: 
1)  list
list current settings
2) set [port|rcj|vxsmin|vxsmax|pictureHome|captureWaitTime|waterMark|maxMatch|maxWidth|maxHeight] value
set config
3) proxy [ on <IP> <PORT> | off ]
set or clear proxy setting
4) help
print this help info
例1: seacatctl list
列出当前配置信息。
例2: seacatctl set port 4444
设定海猫侦听4444端口, 在此端口中接收请求。
例3: seacatctl set rcj 4444-5555-6666
设置注册码为4444-5555-6666。
例4: seacatctl set vxsmin 5
设定最少启动5个虚拟浏览器。此数字决定了海猫能并发接受多少个抓拍请求。
例5: seacatctl set pictureHome /root
设定默认图片存贮目录为/root。
例6: seacatctl set captureWaitTime 1500
设定默认抓拍等待时间为1500毫秒。
例7: seacatctl set waterMark zhuatang.com
设定全图抓拍时加注的水印文字为zhuatang.com。
例8: seacatctl proxy on 192.168.28.91 8080
设定使用代理服务器192.168.28.91,端口8080。
例9: seacatctl proxy off
清除代理设置,不使用代理了。
例10: seacatctl set maxMatch 2
设定viewport-class和viewport-xpath最多匹配的元素个数为2,超出的元素被忽略,不会被抓拍。
例11: seacatctl set maxWidth 1200
设定全图最大宽度为1200像素,若全图实际宽度超出此设定值,则海猫不予抓取。maxWidth为0时表示无限制。
例12: seacatctl set maxHeight 2000
设定全图最大高度为2000像素,若全图实际高度超出此设定值,则海猫不予抓取。maxHeight为0时表示无限制。
注:vxsmax暂无意义,系统保留。

命令行抓拍工具 - capture

usage: usage: capture [-h host] [-p port] [-f] [-s WWWxHHH...] [-w timeToWait] [-o imageFormat] [-P prefix] [-i ids ] [-c classes] [-x xpath] [-r rects] url1 url2 ...
选项:
 -h host : 海猫所在主机,默认值:localhost
 -p port : 海猫所在端口,默认值:5060
 -f : 设定抓拍全图
 -s WWWxHHH... : 缩略图宽高列表,WWW为宽度,HHH为高度
 -w timeToWait : 设定抓拍前等待时间,单位:毫秒
 -o imageFormat : 指定图片格式,默认为png
 -P prefix : 图片文件前缀
 -i ids : ID值列表,指定一个或多个要抓拍的元素ID
 -c classes : class值列表,指定一个或多个要抓拍的元素class名
 -x xpath : xpath表达式,此表达式可匹配多个要抓拍的元素
 -r rects: 指定一个或多个矩形区域,默认值"0 0 1024 768",意即左上角坐标(0,0),宽1024,高768
url1 url2...为需要抓拍的网址
输出:
<url> {+++|---} <scid>

+++ 表示抓拍成功
--- 表示抓拍失败
抓拍成功后,会显示一个<scid>(图片前缀ID)。这个<scid>是抓拍到的图片的文件名前缀(含绝对路径)。 根据此图及用户指定的缩略图大小的设置,能产生多种大小的图片, 而产生的缩略图片文件名格式为<scid>-WWWxHHH.png,其中WWW表示缩略图宽度,HHH表示缩略图高度。 如果允许抓拍整个页面,则会产生一个名为<scid>-full.png的图片。
例1: capture http://www.zhuatang.com
例2: capture -s "109x82 330x220" http://www.zhuatang.com
例3: capture -f -s "82x78 400x300" http://www.zhuatang.com http://www.zaobao.com

注册

海猫是个共享软件,未注册时只能使用30天,注册以后就无限制了。为了您的工作能正常进行,请及时注册。
联络方式: Email/MSN: zhsoft88@gmail.com QQ: 353239635. 注册版投资额人民币12000.00元。

通讯协议

相关文章: 如何使用海猫抓拍页面局部

示范代码

Seacat.java 下载

package com.zhsoft88.commons;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FilenameFilter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Arrays;

import org.apache.commons.lang.math.NumberUtils;

/**
 * seacat capture
 * @author zhsoft88
 * @since 2008-4-13
 * @update 2008-12-13
 */
public class Seacat {

	public static final int PORT = 5060;
	
	/**
	 * capture result
	 * @author zhsoft88
	 * @since 2008-4-13
	 */
	public static class SeacatResult {
		private int statusCode;
		private String statusText;
		private String scid;
		private String geometry;
		private long elaspedTime;
		private String prefix;
		private String pictureHome;
		private String[] suffixList;

		public SeacatResult() {
			// TODO Auto-generated constructor stub
		}

		public int getStatusCode() {
			return statusCode;
		}

		public String getStatusText() {
			return statusText;
		}

		public String getScid() {
			return scid;
		}

		public String getGeometry() {
			return geometry;
		}

		public long getElaspedTime() {
			return elaspedTime;
		}

		public String getPrefix() {
			return prefix;
		}

		public String getPictureHome() {
			return pictureHome;
		}

		public String[] getSuffixList() {
			return suffixList;
		}

		protected void setStatusCode(int statusCode) {
			this.statusCode = statusCode;
		}

		protected void setStatusText(String statusText) {
			this.statusText = statusText;
		}

		protected void setScid(String scid) {
			this.scid = scid;
		}

		protected void setGeometry(String geometry) {
			this.geometry = geometry;
		}

		protected void setElaspedTime(long elaspedTime) {
			this.elaspedTime = elaspedTime;
		}

		protected void setPrefix(String prefix) {
			this.prefix = prefix;
		}

		protected void setPictureHome(String pictureHome) {
			this.pictureHome = pictureHome;
		}

		protected void setSuffixList(String[] suffixList) {
			this.suffixList = suffixList;
		}

		public void dump() {
			System.out.println("SeacatResult:");
			System.out.println("statusCode="+statusCode);
			System.out.println("statusText="+statusText);
			System.out.println("scid="+scid);
			System.out.println("geometry="+geometry);
			System.out.println("prefix="+prefix);
			System.out.println("suffixList length="+suffixList.length);
			for (int i=0;i<suffixList.length;i++) {
				System.out.println("suffixList["+i+"]="+suffixList[i]);
			}
		}
	}
	
	/**
	 * capture configuration
	 * @author zhsoft88
	 * @since 2008-4-13
	 * @update 2008-12-13
	 */
	public static class SeacatConf {
		private String url;
		private String viewportId;
		private String viewportClass;
		private String viewportXpath;
		private String viewportRect;
		private String thumbSizes;
		private int waitTime;
		private boolean enableFull;
		private String pictureHome;
		private String prefix;
		private String suffix;
		private String postData;
		private boolean keepOrigin;

		public SeacatConf() {
			waitTime = -1;
			enableFull = false;
			keepOrigin = false;
			pictureHome = "/tmp";
		}
		public String getUrl() {
			return url;
		}
		public void setUrl(String url) {
			this.url = url;
		}
		public String getThumbSizes() {
			return thumbSizes;
		}
		public void setThumbSizes(String thumbSizes) {
			this.thumbSizes = thumbSizes;
		}
		public int getWaitTime() {
			return waitTime;
		}
		public void setWaitTime(int waitTime) {
			this.waitTime = waitTime;
		}
		public boolean isEnableFull() {
			return enableFull;
		}
		public void setEnableFull(boolean enableFull) {
			this.enableFull = enableFull;
		}
		public String getPictureHome() {
			return pictureHome;
		}
		public void setPictureHome(String pictureHome) {
			this.pictureHome = pictureHome;
		}
		public String getPrefix() {
			return prefix;
		}
		public void setPrefix(String prefix) {
			this.prefix = prefix;
		}
		public String getSuffix() {
			return suffix;
		}
		public void setSuffix(String suffix) {
			this.suffix = suffix;
		}
		public String getPostData() {
			return postData;
		}
		public void setPostData(String postData) {
			this.postData = postData;
		}
		public String getViewportId() {
			return viewportId;
		}
		public void setViewportId(String viewportId) {
			this.viewportId = viewportId;
		}
		public String getViewportClass() {
			return viewportClass;
		}
		public void setViewportClass(String viewportClass) {
			this.viewportClass = viewportClass;
		}
		public String getViewportXpath() {
			return viewportXpath;
		}
		public void setViewportXpath(String viewportXpath) {
			this.viewportXpath = viewportXpath;
		}
		public String getViewportRect() {
			return viewportRect;
		}
		public void setViewportRect(String viewportRect) {
			this.viewportRect = viewportRect;
		}
		public boolean isKeepOrigin() {
			return keepOrigin;
		}
		public void setKeepOrigin(boolean keepOrigin) {
			this.keepOrigin = keepOrigin;
		}
		
	}
	
	private String host;
	private int port;
	
	public Seacat() {
		this("localhost");
	}
	
	public Seacat(String host) {
		this(host,PORT);
	}
	
	public Seacat(String host,int port) {
		this.host = host;
		this.port = port;
	}
	
	/**
	 * capture web page
	 * @param conf
	 * @return
	 * @throws Exception
	 */
	public SeacatResult capture(SeacatConf conf) throws Exception {
		long t1 = System.currentTimeMillis();
		Socket socket = new Socket(host,port);
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
		if (conf.getUrl()!=null) {
			bw.write("get "+conf.getUrl()+"\r\n");
		}
		if (conf.getViewportId()!=null) {
			bw.write("viewport-id "+conf.getViewportId()+"\r\n");
		}
		if (conf.getViewportClass()!=null) {
			bw.write("viewport-class "+conf.getViewportClass()+"\r\n");
		}
		if (conf.getViewportXpath()!=null) {
			bw.write("viewport-xpath "+conf.getViewportXpath()+"\r\n");
		}
		if (conf.getViewportRect()!=null) {
			bw.write("viewport-rect "+conf.getViewportRect()+"\r\n");
		}
		if (conf.getThumbSizes()!=null) {
			bw.write("thumb-sizes "+conf.getThumbSizes()+"\r\n");
		}
		if (conf.isEnableFull()) {
			bw.write("enable-full\r\n");
		}
		if (conf.getWaitTime()!=-1) {
			bw.write("wait-time "+conf.getWaitTime()+"\r\n");
		}
		if (conf.getPictureHome()!=null) {
			bw.write("picture-home "+conf.getPictureHome()+"\r\n");
		}
		if (conf.getPrefix()!=null) {
			bw.write("prefix "+conf.getPrefix()+"\r\n");
		}
		if (conf.getSuffix()!=null) {
			bw.write("suffix "+conf.getSuffix()+"\r\n");
		}
		if (conf.getPostData()!=null&&conf.getPostData().length()>0) {
			bw.write("content-length "+conf.getPostData().length()+"\r\n");
		}
		if (conf.isKeepOrigin()) {
			bw.write("keep-origin\r\n");
		}
		bw.write("\r\n");
		if (conf.getPostData()!=null&&conf.getPostData().length()>0) {
			bw.write(conf.getPostData());
		}
		bw.flush();
		BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream(),"utf-8"));
		String line = br.readLine();
		char[] ca = line.toCharArray();
		int i = 0;
		while (i<ca.length&&ca[i]!=' ') i++;
		while (i<ca.length&&ca[i]==' ') i++;
		// get status code
		StringBuilder sb = new StringBuilder(4);
		while (i<ca.length&&ca[i]!=' ') {
			sb.append(ca[i]);
			i++;
		}
		int statusCode = NumberUtils.toInt(sb.toString());
		// get status text
		while (i<ca.length&&ca[i]==' ') i++;
		String statusText = line.substring(i);
		// get scid & geometry
		String scid = null;
		String geometry = null;
		while ((line=br.readLine())!=null) {
			if (line.length()==0) break;
			if (line.startsWith("SCID: ")) {
				scid = line.substring(6);
			} else if (line.startsWith("Geometry: ")) {
				geometry = line.substring(10);
			}
		}
		socket.close();
		//
		String pictureHome = null;
		String prefix = null;
		String[] suffixList = new String[0];
		if (scid!=null) {
			pictureHome = scid.substring(0,scid.lastIndexOf('/'));
			prefix = scid.substring(scid.lastIndexOf('/')+1);
			final String aPrefix = prefix;
			// get suffix list
			File[] list = new File(conf.getPictureHome()).listFiles(new FilenameFilter(){
				@Override
				public boolean accept(File dir, String name) {
					return name.startsWith(aPrefix);
				}
			});
			suffixList = new String[list.length];
			for (int k=0;k<list.length;k++) {
				suffixList[k] = list[k].getName().substring(prefix.length()+1);
			}
			Arrays.sort(suffixList);
		}
		long t2 = System.currentTimeMillis();
		SeacatResult result = new SeacatResult();
		result.setStatusCode(statusCode);
		result.setStatusText(statusText);
		result.setScid(scid);
		result.setElaspedTime(t2-t1);
		result.setGeometry(geometry);
		result.setPictureHome(pictureHome);
		result.setPrefix(prefix);
		result.setSuffixList(suffixList);
		return result;
	}
	
}

TestSeacat.java 下载

package com.zhsoft88.commons.tests;

import com.zhsoft88.commons.Seacat;
import com.zhsoft88.commons.Seacat.SeacatConf;
import com.zhsoft88.commons.Seacat.SeacatResult;

/**
 * seacat tester
 * @author zhsoft88
 *
 * @since 2008-12-13
 */
public class TestSeacat {

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		Seacat seacat = new Seacat();
		{
			// get snapshot by id
			SeacatConf conf = new SeacatConf();
			conf.setUrl("http://www.google.com");
			conf.setViewportId("gbar");
			conf.setThumbSizes("160x120");
			conf.setKeepOrigin(true);
			SeacatResult result = seacat.capture(conf);
			result.dump();
		}
		{
			// get snapshot by class
			SeacatConf conf = new SeacatConf();
			conf.setUrl("http://news.google.com");
			conf.setViewportClass("lh");
			conf.setThumbSizes("160x120");
			conf.setEnableFull(true);
			conf.setKeepOrigin(true);
			SeacatResult result = seacat.capture(conf);
			result.dump();
		}
		{
			// get snapshot by xpath
			SeacatConf conf = new SeacatConf();
			conf.setUrl("http://news.google.com");
			conf.setViewportXpath("//*[@id='topSection']");
			conf.setThumbSizes("160x120");
			conf.setKeepOrigin(true);
			SeacatResult result = seacat.capture(conf);
			result.dump();
		}
		{
			// get snapshot by specific region
			SeacatConf conf = new SeacatConf();
			conf.setUrl("http://news.google.com");
			conf.setViewportRect("200 200 400 300");
			conf.setThumbSizes("160x120");
			conf.setKeepOrigin(true);
			SeacatResult result = seacat.capture(conf);
			result.dump();
		}
	}

}

产品族: 海狮 海猫 海葵 海蛛 海鹞 海星 海狗 WBXL Xultray webapp
iDocSet iDocSetHelper Blink浏览器 templateJS 布偶猫 skiafy tranid
(C) 2018 抓糖网 版权所有

update: 2013-06-06