软件开发

[译文]构建一个高性能现代网络爬虫

原文链接: https://creekorful.me/building-fast-modern-web-crawler/ 文章目录 构建一个高性能现代网络爬虫 什么是爬虫? Trandoshan:一个暗网爬虫 什么是暗网? Trandoshan是如何设计的? 怎么运行Trandoshan? 如何使用Trandoshan? 构建一个高性能现代网络爬虫 PS:本文为Building a fast modern web crawker的中文译文。 我一直对于爬虫具有很强烈的兴趣。我曾经使用过多种语言比如C++,Node.JS,Python等等来撰写爬虫程序,并且更吸引我的是爬虫背后的理论。 但是首先我们要讨论的问题是:什么是爬虫? 什么是爬虫? 爬虫是一个通过浏览整个因特网从而去定位一些存在的页面、图片、PDF等等的计算机程序,并且允许用户去通过一个搜索引擎去检索它们。这就是隐藏在著名的Google搜索引擎背后的技术。 一个高性能的爬虫程序通常被设计为分布式结构:区别于运行在特定机器上的单个程序,它会在云上的多台机器上运行多个实例,这样的结构带来更好的任务再分配、更好的性能和更大的带宽。(ps:这里使用吞吐量会不会更合适?) 但是分布式软件并不是没有瑕疵的:一些因素可能会给你的的程序带来额外的延迟、或者可能会降低你的程序的性能,比如说网络的延迟、同步的问题、缺乏设计的通信协议等等。 为了追求更好的性能,一个分布式的爬虫应该有足够良好的设计:这让消除许多性能上的瓶颈成为可能,就像法国的海军上将Olivier Lajous说的: 一个链子的强度取决于最薄弱的一环。 Trandoshan:一个暗网爬虫 你可能知道很多非常成功的网络爬虫,比如Google。所以我并不想去做一个同样的东西。我当下想要去构建一个基于暗网的爬虫。(ps:trandoshan是星球大战中的狩猎种族) 什么是暗网? 没必要去使用很多术语去形容什么是暗网,要写起暗网的来龙去脉可能要新建一篇文章。 Web是由三层结构组成的,我们可以将其视为一座冰山: 第一层:表面网络,或者说是净网是我们每天最常接触的网络的那部分。它们被一些炙手可热的网络爬虫比如Google,Qwant,Duckduckgo等等所定位。 第二层:更深层次的网络,是由一些无法被定位的网页组成的,这意味着你是用搜索引擎都找不到这些网页,但是你却可以直接使用URL和IP地址来访问这些页面。 第三层:暗网,这是一类你是用浏览器都无法访问到的网页。你需要使用特定的应用程序或者特定的代理才可以访问。最出名的暗网是隐藏在洋葱头网络下的。你可以使用以.onion结尾的URL去访问它们。 Trandoshan是如何设计的? 在分别讲解这些进程的作用之前,我觉得首先要讲清楚的是这些进程之间如何通信。 进程间通讯(Inter Process Communication, IPC),主要是通过使用一个基于生产者/消费者模式的名为NATS(图中黄色的线)的通讯协议,每个在NATS中的消息都有一个主题(就像邮件里的那样),支持其他进程去识别并且仅读取它们想要读取的消息。NATS支持扩展:比如可以支持十个爬虫进程从一个消息服务器并发的读取消息(许多实例可以同时运行而不出任何bug)并因此可以提升性能。 Trandoshan分为四个主要的进程: 爬虫:用于爬取页面的进程:它们从NATS读取将要爬取的页面的URL(消息的主题是”todoUrls”),爬取它,并且获取整个页面中显示的全部URL,并且发送这些URL到NATS中(这些消息的主题是”crawledUrls”),而页面的内容则以主题”content”发送到NATS。 调度器:这个进程用于检查URL:它读取主题为”crawledUrls”,检查其是否是已经爬取过的URL,如果还没有被爬取过,则将URL以主题”todoUrls”发送到NATS。 持久器:这个进程用于网页内容的构建:它读取以”content”为主题的消息,并且存储到非关系型数据库中(MongoDB) 接口:给其他进程开放用于聚合数据的进程。比如开放给调度器的用于确定URL是否被爬取过的接口,相比于调度器直接和数据库进行交互,更倾向于调度器和API们交互。 不同的进程们都是使用Go语言进行编写的:因为它的性能很好(可以被编译为二进制文件)并且有很多的库。Go是用来构建高性能的分布式系统的完美解决方案。 Trandoshan的源码在github的这里:https://github.com/trandoshan-io 怎么运行Trandoshan? 就像之前讲过的一样,Trandoshan被设计为运行在一个分布式的系统上,并且可以使用Docker的镜像来运行,这对于云来说是很好的支持。事实上我整理了一个存储着所有部署需要的配置文件的仓库,可以用于部署Trandoshan实例在K8S上。这些文件在这里:https://github.com/trandoshan-io/k8s 并且docker的镜像也都上传到了Docker Hub。 如果你拥有一个配置成功的kubectl(K8S的控制程序),你可以通过一条简单的命令部署Trandoshan: ./bootstrap.sh 不然的话你可以使用Docker和docker-compose在本地运行Trandoshan。在trandoshan-parent这个仓库中有构建文件和shell脚本,所以你可以使用以下命令来运行这个应用: ./deploy.sh 如何使用Trandoshan? 现在有一个小型的Angular应用去检索定位内容。这个页面使用了API进程去完成对于数据库的检索工作。

Bean named ‘xxx’ is expected to be of type ‘cn.xxx’ but was actually of type ‘com.sun.proxy.$Proxy22

在学习spring aop中的动态代理时,碰到了一个问题: “名为“xxx”的Bean的类型应该是“com”.xxx’,但实际上是’com.sun.proxy.$Proxy22’类型的。” spring使用的动态代理有两种:JDK Proxy 和CGLIB。 使用前者必须实现至少一个接口才能实现对方法的拦截。 使用后者需要两个jar包:asm.jar和cglib.jar ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); System.out.println(ac); UserServiceImpl bean = ac.getBean("userService",UserServiceImpl.class); **问题出在这句代码上 UserServiceImpl bean = ac.getBean(“userService”,UserServiceImpl.class);不能用接口的实现类( UserServiceImpl)来转换Proxy的实现类,它们是同级,应该用共同的接口(UserService)来转换 ** 把代码改为 UserService bean = ac.getBean(“userService”,UserService.class); 简单地说就是要用该类的接口来转换,而且必须是该类的接口

springboot开发环境低引起的依赖冲突问题

在我初学springboot的时候,碰到了一个深坑,记录下过程。 开发环境:eclipse4.6 刚在springboot官网上下载并导入一个springboot项目,就发现pom.xml文件报错,为了解决后续隐藏的麻烦(主观上看着也不爽),于是查到了原因:初步确定是Eclipse中自带的Maven插件版本太低的原因(我用的Eclipse是Eclipse Neon (4.6)版本,自带Maven插件),需要更新Maven插件。 解决办法:https://www.cnblogs.com/wanggangblog/p/8901516.html 终于不报错了,于是试试能否启动成功,结果又出现,SpringBoot应用部署到Tomcat中无法启动问题: 解决办法:https://www.cnblogs.com/a8457013/p/7687764.html 这里我只修改了tomcat版本,后续依赖并没有添加,于是又出现了: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean. at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:157) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) ~[spring-context-5.1.5.RELEASE.jar:5.1.5.RELEASE] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) ~[spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.3.RELEASE.jar:2.1.3.RELEASE] at cn.tedu.springboot.DemoApplication.main(DemoApplication.java:12) [classes/:na] Caused by: org.springframework.context.ApplicationContextException: Unable to start ServletWebServerApplicationContext due to missing ServletWebServerFactory bean. at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.getWebServerFactory(ServletWebServerApplicationContext.java:206) ~[spring-boot-2.

Windows10配置深度学习环境(使用GPU)

之前在学校一直用的Ubuntu来配置深度学习环境,这次尝试了一下在windows下用Anaconda来配置。 笔记本型号是惠普暗影精灵3,显卡1050TI,没有提前安装python、CUDA、CUDNN等,所有的库全部由Anaconda来安装,笔者比较强迫症,不喜欢在电脑上装得乱七八糟,用Anaconda管理是真滴舒服。 一.Anaconda安装 这一步网上已经有很多教程,下载Anaconda最好去清华镜像源下载,官网下载的速度太慢,注意要下载对应版本。 如windows64位系统下载Anaconda3-2018.12-Windows-x86_64.exe 后面安装过程基本就是跟着安装界面一步一步next,路径尽量保证不要包含中文,有一点能说的就是在下面这个界面 如果没有预先安装python那么第二个必须打勾,第一个是询问是否将Anaconda的路径加到PATH环境变量中,这里虽然系统不推荐(not recommended),给出的理由是会影响之前安装的软件,这里笔者之前是打勾了,刚开始的几天没出问题,但是后面突然某一天电脑不能正常开机了,所以经过验证还是推荐不打勾,不加环境变量也可以运行程序。(这里勾选添加环境变量后出现的问题会在下一篇博客详细描述) 安装完成之后可以打开cmd,输入 conda info 或者 python有输出证明安装过程没有问题。 二.环境配置 打开Anaconda Navigator进入环境配置的界面 Anaconda方便之处就在这里,可以创建各种独立的工作区间,每一个区间都可以配置不同的环境,这里笔者使用的是Keras的GPU版,应该下载的是keras-gpu,直接勾选keras-gpu下载后,anaconda会自动的将所有需要的依赖加入下载选项,例如这里没有预先安装tensorflow的gpu版,但是安装keras-gpu时tensorflow-gpu会同样进入安装队列并且其他依赖需要降版本的anaconda会一并处理,着实方便!下载的时候如果没有更换为国内镜像源可能会出错,但是笔者根据网上的一些方法更换下载源之后反而变得不能下载,暂时没有找出原因,于是挂了VPN用的Anaconda默认下载源成功下载并安装。 三.运行程序 环境配置好后,笔者运行了一个CNN的手写数字识别代码来测试,用的是jupyter notebook(真香)。 测试结果如下: 可以看到一个epoch需要3秒,并且GPU占用率很高(风扇呼呼的转),记得最开始用CPU训练的时候大概是三十多秒一个epoch,CPU和GPU在训练时间上的差距真的挺大的。 到这里一个基本的使用GPU训练的深度学习环境就配置好了,希望对大家能有一点帮助。

SpringBoot 集成 JavaMelody实现 性能监控

1、JavaMelody JavaMelody能够在运行环境监测Java或Java EE应用程序服务器。并以图表的形式显示:Java内存和Java CPU使用情况,用户Session数量,JDBC连接数,和http请求、sql请求、jsp页面与业务接口方法(EJB3、spring、Guice)的执行数量,平均执行时间,错误百分比等。图表可以按天,周,月,年或自定义时间段查看。 2、Maven依赖 net.bull.javamelody javamelody-core 1.73.1 com.lowagie itext 2.1.7 3、配置JavaMelody @Configuration public class MelodyConfig { /** * 配置javamelody监控 * spring boot 会按照order值的大小,从小到大的顺序来依次过滤 */ @Bean @Order(Integer.MAX_VALUE - 1) public FilterRegistrationBean monitoringFilter() { FilterRegistrationBean registration = new FilterRegistrationBean(); registration.setFilter(new MonitoringFilter()); registration.addUrlPatterns("/*"); registration.setName("monitoring"); return registration; } /** * 配置javamelody监听器sessionListener */ @Bean public ServletListenerRegistrationBean servletListenerRegistrationBean() { ServletListenerRegistrationBean slrBean = new ServletListenerRegistrationBean(); slrBean.setListener(new SessionListener()); return slrBean; } } 4、启动项目 访问路径为: http://ip:port/项目名/monitoring

ThinkPad E470 win10-64bit显示问题和声音播放问题

本文针对win10 64位系统,话不多说,直接解决。 一、显示器自动变暗 问题描述:在打开黑色背景的软件时候屏幕自动变暗,并且按照网上各位大牛的方法均未能解决,心里着实不爽。如果按照网上各位大牛的方案还不奏效,那么,我这个解决方案可能是你在做系统前的最后一次垂死挣扎了。 解决方法: 1,打开设备管理器(我的电脑 –> 右键 –> 属性 –> 设备管理器),找到显示适配器,先卸载驱动NVIDIA xxxx,后卸载驱动Intel(R) xxxx(必须是这个顺序卸载)。 2、下载新驱动 :驱动下载点我 3、下载完成,一路next,I Agree,Finish即可。 4,重启。 二、无外放 下载一个热键驱动下载点我,安装,重启即可。

SpringBoot使用WebSocket实现服务端推送—单机实现(1)

[![star](https://gitee.com/xxssyyyyssxx/websocket-springboot-starter/badge/star.svg?theme=dark)](https://gitee.com/xxssyyyyssxx/websocket-springboot-starter/stargazers) 最近开发中需要实现服务端的推送,经过一段时间的资料查询最终锁定使用websocket来实现。JavaEE本身就支持WebSocket。我们只需要开发一个EndPoint来处理连接、消息等即可。但是WebSocket的session管理是开发中的重中之重和难点,因为你需要知道推送给谁,就需要保存代表其连接的Session。 1.首先设计管理WebSocket的session的接口WebSocketManager。 /** * 管理websocket的session,可以使用Map * @author xiongshiyan at 2018/10/10 , contact me with email [email protected] or phone 15208384257 */ public interface WebSocketManager { /** * 在容器中的名字 */ String WEBSOCKET_MANAGER_NAME = "webSocketManager"; /** * 根据标识获取websocket session * @param identifier 标识 * @return WebSocket */ WebSocket get(String identifier); /** * 放入一个 websocket session * @param identifier 标识 * @param webSocket websocket */ void put(String identifier , WebSocket webSocket); /** * 删除 * @param identifier 标识 */ void remove(String identifier); /** * 获取当前机器上的保存的WebSocket * @return WebSocket Map */ Map localWebSocketMap(); /** * 统计所有在线人数 * @return 所有在线人数 */ default int size(){ return localWebSocketMap().

登录注册样例(附带输入信息检验) springmvc

1 注册界面 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> </span> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title>买家注册title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="${pageContext.request.contextPath}/conf1/css/font-awesome.min.css"> <link rel="stylesheet" href="${pageContext.request.contextPath}/conf1/css/ionicons.min.css"> <link rel="stylesheet" href="${pageContext.request.contextPath}/conf1/dist/css/adminlte.min.css"> <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700" > head> <script type="text/javascript"> function checkForm(){ if($.trim($("#name").val())==""){ alert("请填写名字"); $("#name").focus(); return false; } if($("#name").val().length>50){ alert("名字长度不得大于50个字符"); $("#name").focus(); return false; } if($.trim($("#username").val())==""){ alert("请填写用户名"); $("#username").focus(); return false; } if($("#username").val().length>50){ alert("用户名长度不得大于50个字符"); $("#username").focus(); return false; } if($.trim($("#password").val())==""){ alert("请填写密码"); $("#password").focus(); return false; } if($("

ubuntu下安装svn

ubuntu下安装svn 1、下载安装 apt install subversion 2、创建目录和仓库 mkdir -p /home/.svn/repository svnadmin create /home/.svn/repository/ 3、进入配置文件(我这里用的是隐藏目录) cd /home/.svn/repository/conf 4、打开svnserve.conf并配置 vim svnserve.conf 将 这三处改成 注意要顶格写 然后保存退出 5、修改passwd文件 vim passwd 添加用户名和密码,例如 zhaoyang = 123456 6、修改authz文件 vim authz 在[group]下面加上 admin=zhaoyang [/] @admin=rw 7、启动svn服务 svnserve -d -r /home/.svn 8、在客户端测试 地址就是 svn://ip/repository 注意默认端口是3690,要开放此端口 9、接下来配置开机自启 启动方法1: 先查一下svnserve的位置 which svnserve 例如返回 /usr/bin/svnserve 记住这个,后面脚本需要 开始写脚本 cd /etc/init.d vim svn.sh 打开后写入 #!/bin/bash /usr/bin/svnserve -d -r /home/.svn 保存退出后给文件添加可执行权限 chmod +x /etc/init.d/svn.sh 10、打开 /etc/rc.

关于“暗网”的问题

“暗网” 什么是“暗网”? 有图有真相,上图: 关于这个名词,大家还是百度下吧。这里简单地摘录下描述性的内容: 关于“暗网”,最出名的一句话应该是这句:暗网也称深网,也称隐形网,hideweb,deepweb。 深网的意思就是说冰山上露出的那一角使我们现在看到的 “明网”,据说整个数据量的 96% 在下面。 想了解的,这里推荐一个经典大片里可能引用的内容, 那就是“暗网”纪录片:BBC地平线系列纪录片《深入暗网》。 onion的网络是暗网中的一小部分,但里面的内容很多,这里不再描述了。 好奇害死猫,不要去挖冰山下面的那些大脚脚的内容。 Tor 浏览器可以突破GFW,很好滴保护好自己的隐私。 感兴趣的可以去利用这个工具,访问youtube学习英文,但不要让youtube的系统觉得你是一个机器人ROBOT就行。 ZeroNet 也算是深网的一种了。 “比特币”的流行 说起暗网,不得不提起虚拟货币,那就是比特币。 为了保护交易双方的个人隐私,大家在暗网中不会傻到使用自己的银行账号吧! 所以中间货币就成了双方的折中的比特币了。 近日,全球爆发加密勒索病毒WannaCry攻击,中国很多用户也收到了黑客发来的勒索信(2.25比特币等于500美元)。 很多人注意到,在勒索信中黑客索要的货币并非实体货币,而是之前引发投资热的“比特币”。 伟大的墙GFW 从某一层面上说,GFW有他自己的好处,至少能让我们生活在一个过滤过的互联网世界里。看到的都是相对美好的内容,尽管有些漏网之鱼。 但是出于对自由的追寻的人,你可以借个梯子翻过去,看看外面的世界,上天,入地,成佛,成魔就看你自己了。 明与暗的较量 未来这样的世界依然存在,只是你不曾了解而已。 网络的力量 我们身处在明与暗的交互中,就看你是否随波逐流了。 最后以谷歌创始人佩奇谈深网以及网络问题时所说的一句话来总结下吧:“不能因为洗澡水脏,就把水跟孩子一起倒掉。”