- 许珈毓的技术思考
- Just Make it happen
- 成就梦想---唯有执..
- Reinember
- 唐良的Office 365..
- 高文龙
- 马骏一的奔跑空间
- 胖哥技术堂
- 云中漫步的老猫
- 从心开始
- 绝对领域
- 叶俊生
- 火线科技兄弟伙的博客
- SQLServer2014丛书
- PinkneyLeo
- gs_hao
- 51CTO博客管家
- 周平的微软技术交..
- 孟纪超的技术博客
- 杜飞
- 菜鸟起航
- 锦绣前程
- IT-Standardization
- 听闻
- @天行健中国元素
- 千山岛主之微软技..
- MVP盆盆
- 九叔-微软私有云
- Citrix的虚拟世界..
- 博客大管家-蘑菇
- 东妮学IT
- 周平的微软统一沟通
- 大向技术分享
- VMCloud网络研究实..
- 一个倔强的孤岛
- 孙亮的IT运维技术
- 微软MVP专题
- 技术不宅
- 星星落在我头上
- 钟迎锋的技术博客
- 无敌议长之铁腕
- iLync
- 蛮子的博客-我的IT..
- 岳雷的微软网络课堂
- 归零
- IT----你---我---..
- 运维人生
- 阳光☆奋进
- 李博客-微软技术..
- IT精品课程
- 技术人才招聘
Windows insider会员计划并没有随着Windows 10正式版的发布而终止,相反一直保持的继续前进,为Windows客户带来更多体验。近期微软推送了最新的windows 10预览版10565,除了带来相关功能性、稳定性、BUG修复之外,还带来了微软年初承诺的技术�D�DNested Virtualization,意即微软的第二个容器�DHyper-V Container,第一个容器技术Windows Server Container已于8月份的Windows Server 2016 Technical Preview 3来到。
通过嵌套虚拟化技术,用户可以在Hyper-V虚拟机中运行Hyper-V容器,即在Hyper-V虚拟机中跑Hyper-V虚拟机,该技术是针对系统自带Hyper-V虚拟机的。关于在Windows 10中启用Hyper-V功能您可以参加之前写的博文:在Windows 10中启用客户端Hyper-V
http://ericxuting.blog.51cto.com/8995534/1684339
从本质上讲,此功能上是把在虚拟机中运行虚拟机监控程序所需的一些硬件功能进行了虚拟化。Hyper-V虚拟化技术依靠硬件虚拟化支持(如英特尔VT-x和AMD-V)来运行虚拟机。通常情况下,一旦Hyper-V的安装,管理程序隐藏了客户虚拟机这种能力,防止来宾虚拟机再次安装Hyper-V。
在最新预览版本10565中,宿主机的Hyper-V虚拟机监控程序则对客户机开放虚拟化扩展功能,因此客户机也可
因为项目需要,做了一个网络爬虫的小DEMO。
为实现高性能的网络爬虫,首先考虑采用APACE的HttpClient进行页面的采集和解析,HttpClient可以很方便的通过URL获得远程内容,例如一个小程序:
CloseableHttpClienthttp client = HttpClients.createDefault(); HttpGet httpget = newHttpGet("http://localhost/"); CloseableHttpResponse response = httpclient.execute(httpget); try { HttpEntity entity =response.getEntity(); if (entity != null) { long len =entity.getContentLength(); if (len != -1 && len <2048) { System.out.println(EntityUtils.toString(entity)); } else { // Stream contentout } } } finally { response.close(); }
还可以做页面解析和模拟登陆等,功能相当强大。
其次,如果是网络爬虫或者网络采集,可能需要做大量的URL地址收集和分析,所以需要通过NoSQL数据库来提高执行的效率,Redis、Memcache、BerkeleyDB都是不错的选择。这里选择了BerkeleyDB数据库。虽然采用传统队列或其他形式可能性能会更高,但会带来大量的内存消耗,并不一定能找到符合条件的大内存服务器。
然后,对URL地址需要进行过滤,判断是否是已读的URL地址,如果已读就存入已读数据库,如果未读则放入未读数据库,有点类似队列的形式,以此避免重复读取URL地址。当然更进一步的需要判断页面内容是否重复,降低读取重复页面的概率。
再然后,对页面进行解析,提取关键内容和URL地址。
最后,为了保证性能,采用多线程的实现方式,在多服务器的模式下还可以采用分布式算法来实现更高的性能。
按照上面的思路,写了一个小程序:
1、部分配置信息,以CrawlConfig来做配置,也可以把这些存储为xml文件,这里采集的是163网站
(1)CrawlConfig.java
…… public class CrawlConfig { public static final String CRAWL_PATH = "http://www.163.com"; public static final String CRAWL_LIMIT_PATH = "http://www.163.com"; public static final String CRAWL_VISITED_FRONTIER = "d:\\cache\\hevisited"; public static final String CRAWL_UNVISITED_FRONTIER = "d:\\cache\\heunvisited"; public static final String CRAWL_DOWNLOAD_PATH = "d:\\download\\163\\"; public static final int CRAWL_THREAD_NUM = 6; }
(2) CrawlUrl.java作为URL地址的对象,当然除了URL属性外还可以存储其他信息
…… public class CrawlUrl implements Serializable{ private static final long serialVersionUID = 79332323432323L; public CrawlUrl() { } private String oriUrl; //原始url private String url; //url地址 public String getOriUrl() { return oriUrl; } public void setOriUrl(String oriUrl) { this.oriUrl = oriUrl; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } }
(3)LinkFilter.java ,作为URL地址的过滤器
public interface LinkFilter { public boolean accept(String url); }
2、编写访问BerkelyDB的代码(请先安装BerkeleyDB,并引入BerkeleyDB的Je包
(1)AbstractFrontier.java
…… public abstract class AbstractFrontier { private Environment env; private static String CLASS_CATALOG = "java_class_catalog"; protected StoredClassCatalog javaCatalog; protected Database catalogdatabase; protected static Database database = null ; protected String homeDirectory = null; public AbstractFrontier(String homeDirectory) throws DatabaseException, FileNotFoundException { this.homeDirectory = homeDirectory; System.out.println("open environment: " + homeDirectory); //设置环境参数,打开env EnvironmentConfig envConfig = new EnvironmentConfig(); envConfig.setTransactional(true); envConfig.setAllowCreate(true); env = new Environment(new File(homeDirectory), envConfig); //设置数据库参数 DatabaseConfig dbConfig = new DatabaseConfig(); dbConfig.setTransactional(true); dbConfig.setAllowCreate(true); //打开数据库 catalogdatabase = env.openDatabase(null, CLASS_CATALOG, dbConfig); javaCatalog = new StoredClassCatalog(catalogdatabase); //设置参数 DatabaseConfig dbConfigTe = new DatabaseConfig(); dbConfigTe.setTransactional(true); dbConfigTe.setAllowCreate(true); //打开数据库 database = env.openDatabase(null, "URL", dbConfig); } public void close() throws DatabaseException { database.close(); javaCatalog.close(); env.close(); } protected abstract void put(Object key, Object value); protected abstract Object get(Object key); protected abstract Object delete(Object key); }
(2)Frontier.java
…… public interface Frontier { public CrawlUrl getNext() throws Exception; public boolean putUrl(CrawlUrl url) throws Exception; }
(3)考虑到并发的BDBFrontier.java
…… public class BDBFrontier extends AbstractFrontier implements Frontier{ private StoredMap pendingUrisDB = null; public static int threads = CrawlConfig.CRAWL_THREAD_NUM; /** * Creates a new instance of BDBFrontier. * * @param homeDirectory * @throws DatabaseException * @throws FileNotFoundException */ public BDBFrontier(String homeDirectory) throws DatabaseException, FileNotFoundException { super(homeDirectory); EntryBinding keyBinding = new SerialBinding(javaCatalog, String.class); EntryBinding valueBinding = new SerialBinding(javaCatalog, CrawlUrl.class); pendingUrisDB = new StoredMap(database, keyBinding, valueBinding, true); } /** * * clearAll: * 清除数据库 * * @param 参数 * @return void 返回值 * @throws * */ public void clearAll() { if(!pendingUrisDB.isEmpty()) pendingUrisDB.clear(); } /** * 获得下一条记录 * @see com.fc.frontier.Frontier#getNext() */ @Override public synchronized CrawlUrl getNext() throws Exception { CrawlUrl result = null; while(true) { if(!pendingUrisDB.isEmpty()) { Set entrys = pendingUrisDB.entrySet(); Entry<String, CrawlUrl> entry = (Entry<String, CrawlUrl>) pendingUrisDB.entrySet().iterator().next(); result = entry.getValue(); //下一条记录 delete(entry.getKey()); //删除当前记录 System.out.println("get:" + homeDirectory + entrys); return result; } else { threads --; if(threads > 0) { wait(); threads ++; } else { notifyAll(); return null; } } } } /** * 存入url * @see com.fc.frontier.Frontier#putUrl(com.fc.CrawlUrl) */ @Override public synchronized boolean putUrl(CrawlUrl url) throws Exception { if(url.getOriUrl() != null && !url.getOriUrl().equals("") && !pendingUrisDB.containsKey(url.getOriUrl())) { Set entrys = pendingUrisDB.entrySet(); put(url.getOriUrl(), url); notifyAll(); System.out.println("put:" + homeDirectory + entrys); return true; } return false; } public boolean contains(Object key) { if(pendingUrisDB.containsKey(key)) return true; return false; } /** * 存入数据库 * @see com.fc.frontier.AbstractFrontier#put(java.lang.Object, java.lang.Object) */ @Override protected synchronized void put(Object key, Object value) { pendingUrisDB.put(key, value); } /** * 从数据库取出 * @see com.fc.frontier.AbstractFrontier#get(java.lang.Object) */ @Over
没有评论:
发表评论