分布式爬虫系统(1)-什么是网络爬虫?

分布式爬虫系统(1)-什么是网络爬虫?

一句话概况的话,网络爬虫是一种运行在互联网上为了获取数据的自动化程序或者脚本。
它有三个特点:

  • 运行在互联网上
  • 是为了获取数据
  • 是一种自动化程序或者脚本

从它的三个特点来看,第一个特点是运行在互联网上,这个概念不需要解释。

第二种特点是为了获取数据,这时候产生了一个子问题,爬虫是为了获取什么样的数据呢?
互联网上的数据千千万万,爬虫不可能完全都爬下来,所以爬虫爬取的数据肯定是互联网上所有数据子集。
那这个子集,究竟有多大呢?其实这个数据子集有多大,完全是根据我们对数据的需求来计算的。
比如,我想获取起点中文网上所有的小说数据,那么爬虫爬取的数据量就是起点中文网上所有的小说数据。
也就是说,爬虫获取数据量的大小完全是根据业务需求来的。

第三个特点是自动化程序或者脚本,既然爬虫是程序或者脚本,那么就决定了使用任意一种编程语言都可以来进行爬虫开发,因为任何编程语言写出来的代码都可以叫做程序和脚本。所以,我们要进一步探索到爬虫的内在核心,其实爬虫的内在核心是网络通信,而网络通信是所有编程语言都能够做的事情。

获取起点中文网的小说(使用爬虫技术)

如何获取起点中文网的小说

对于普通用户来讲,起点中文网的小说是无法通过鼠标操作进行复制粘贴的。
略微懂一些的网页原理的同学,可能知道右键查看源代码。但是起点小说网,无法执行右键。
所以如何获取起点中文网的小说内容,就成了普通用户的一个问题?

接下来我们通过技术手段,来获取下起点小说的内容。

创建一个Java的Maven工程,导入依赖

 <dependencies>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.3</version>
        </dependency>
        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.10.3</version>
        </dependency>
    </dependencies>

编写代码

public static void main(String[] args)  {
        //1、set start url 你在起点上任意找一篇小说,第一章的URL
         String nextUrl = "https://read.qidian.com/chapter/_AaqI-dPJJ4uTkiRw_sFYA2/TPYBmAARksLgn4SMoDUcDQ2";
        while (nextUrl!=null) {
            try {
                //2、httpclient
                CloseableHttpClient httpClient = HttpClients.createDefault();
                //3.execute
                CloseableHttpResponse response = httpClient.execute(new HttpGet(nextUrl));
                //4.get html dcoment
                String html = EntityUtils.toString(response.getEntity());
                //5.parse content and next url
                Document document = Jsoup.parse(html);
                //5.1 parse content
                Elements contents = document.select("[class=read-content j_readContent]");
                System.out.println(contents.text());
                System.out.println("------------------------------");
                Elements nextUrls = document.select("#j_chapterNext");
                //5.2 parser next url
                nextUrl = "http:" + nextUrls.get(0).attr("href");
                Thread.sleep(2 * 1000);
            }catch (Exception e){
                System.out.println(nextUrl);
                System.out.println(e);
            }
        }
    }

起点小说网VIP章节获取

获取vip章节需要在浏览器上登录下,然后拷贝登录的信息,个人猜测主要是cookies信息。
当然vip章节肯定是你订阅过的。

 public static void main(String[] args) throws IOException, InterruptedException {
        //1、set start url
        String nextUrl = "http://vipreader.qidian.com/chapter/1004608738/346953690";
        //2、httpclient
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //3.execute
        // set user login info
        HttpGet httpGet = new HttpGet(nextUrl);
        httpGet.setHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        httpGet.setHeader("Accept-Encoding","gzip, deflate, sdch");
        httpGet.setHeader("Accept-Language","zh-CN,zh;q=0.8");
        httpGet.setHeader("Connection","keep-alive");
        httpGet.setHeader("Cookie","e1=%7B%22pid%22%3A%22qd_P_vipread%22%2C%22eid%22%3A%22%22%2C%22l1%22%3A3%7D; e2=%7B%22pid%22%3A%22qd_P_vipread%22%2C%22eid%22%3A%22%22%2C%22l1%22%3A3%7D; _csrfToken=3ghtgsa7WWP84kbVUr2cYib4JNSViebbmuNPTmQd; newstatisticUUID=1508327144_264602072; qdrs=0%7C3%7C0%7C0%7C1; qdgd=1; bc=1004608738; pageOps=1; e1=%7B%22pid%22%3A%22qd_P_qdlogin%22%2C%22eid%22%3A%22%22%7D; e2=%7B%22pid%22%3A%22qd_P_qdlogin%22%2C%22eid%22%3A%22%22%7D; ywkey=yw4mUkcoXq2z; ywguid=800161839511; lrbc=1004608738%7C346953260%7C1; rcr=1004608738");
        httpGet.setHeader("Host","vipreader.qidian.com");
        httpGet.setHeader("Upgrade-Insecure-Requests","1");
        httpGet.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36");
        CloseableHttpResponse response = httpClient.execute(httpGet);
        //4.get html dcoment
        String html = EntityUtils.toString(response.getEntity());
        //5.parse content and next url
        Document document = Jsoup.parse(html);
        //5.1 parse content
        Elements contents = document.select("[class=read-content j_readContent]");
        System.out.println(contents.text());
        System.out.println("------------------------------");
        Elements nextUrls = document.select("#j_chapterNext");
        //5.2 parse url
        nextUrl = "http:" + nextUrls.get(0).attr("href");
        System.out.println(nextUrl);
        Thread.sleep(2 * 1000);
    }

如何发送工作邮件

邮件是重要的沟通工具。
一般来说比较常见的是正式资料的递交、重要信息的通知、处理方案的告知和确认等都需要通过邮件告知涉及的人员。
但对于无伤大雅的执行细节,则一般应以电话和当面沟通为主,避免邮件过多干扰大家工作。(看公司文化了,有些公司邮件泛滥成灾、会议频率高得要死)此外,对于有系统支撑的信息汇总、工作流规范的,也应当在对应系统中处理,而不是通过邮件。

  • 收件人(TO):这件事情需要你处理或者是协助,请务必知晓。
    * 抄送(CC):这事你最好知道,有空还是扫一眼吧。 通常来说,下面达成共识准备执行时都应当抄送一下双方主管。总的来说,是让对这件事情有一定关注,但不直接相关的人,比如都在这个项目里,但不需要直接参与该邮件所述事宜的人。 一般不越级抄送老板时,但进度的重要节点等则有必要。
  • 暗送(BCC):少用。 这事你自己知道就好了,我不太方便让其他人知道我告诉你了。

收件人或抄送的次序,一般没有什么大讲究,喜欢看长列表的人很少。 如果企业里论资排辈或者是人际关系比较复杂,稍微注意些,让级别高的、你的直接主管排前面就好。

常用语:

  • RT - 如题,适用于简单通知,主题里已经说明一切的。
  • FYI - For your information/interest,供你参考或这个你或许有兴趣。
  • ASAP - As soon as possible 尽快处理。如果给别人发送时有这个要求,也可以给邮件标高优先级,并尽量在邮件外通过电话、口头的方式告知。

作者:黄良懿
链接:https://www.zhihu.com/question/20435681/answer/15480518
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

Hadoop会被Spark替代么

宣扬Hadoop将死的观点一直以来已经很久了,那这种观点究竟是对还是错,hadoop和spark是什么关系,Spark何德何能将一统大数据的江山,Spark在企业中应用的如何,我们有必要花大量的时间去掌握他么?答案是,1)hadoop不会死,spark也干不死hadoop,2)spark有必要去掌握,如果现在还没掌握,尽快掌握。

1.Spark和Hadoop关系

分布式计算平台=分布式文件系统+分布式计算模型,我们通常讲的hadoop一般是指分布式计算平台的统称,
分布式计算平台(hadoop)=分布式文件系统(HDFS)+分布式计算模型(MapReduce)
Spark=分布式计算模型+图计算模型+机器学习库+流等计算...
Spark包含了很多,但是唯独没有包含分布式计算模型,因为HDFS做的已经足够好了
hadoop包好了分布式文件系统,分布式计算模型,但是没有图计算、机器学习、流式计算。
所以要么是你有的,我没有,我有的,你没有。
hadoop和spark的关系就是:你依赖我,我加强你,互相补充,扬长避短。

2.Hdoop和Spark的区别

2个都是开源框架,但是解决的问题侧重点不一样
第一,hadoop是分布式文件系统实现的经典方式,轻轻松松做到平台近乎傻瓜式的横向扩容,并且为分布式计算提供了基础,创造了可能(文件切分,分布式存储),而且依赖的硬件也是普通的PC服务器。这些特点如果没有经历IOE架构是没法深刻理解的,传统的企业以前几乎都是IOE的架构(IBM的服务器,做逻辑运算等功能,Oracle的数据库,做数据库服务,EMC的存储,存储都是SAN、阵列之类的专门服务器来做),硬件价格贵的要命,小型机一台都上百万,而且运维还要专门的团队,小型机一个团队,oracle一个团队,存储一个团队,这兼职就是噩梦。Spark,则是那么一个专门用来对那些分布式存储的大数据进行处理的工具,它并不会进行分布式数据的存储。
第二,还有一点也值得注意——这两者的灾难恢复方式迥异。因为Hadoop将每次处理后的数据都写入到磁盘上,所以其天生就能很有弹性的对系统错误进行处理。
Spark的数据对象存储在分布于数据集群中的叫做弹性分布式数据集(RDD: Resilient Distributed Dataset)中。这些数据对象既可以放在内存,也可以放在磁盘,所以RDD同样也可以提供完成的灾难恢复功能。
第三,使用场景不一样,hadoop适合离线,spark适合计算复杂,能迭代的计算场景,大部分hadoop的计算场景,spark都能做,个别场景只能haodop做,spark做不了。
第四,在我的使用经验里面,稳定性来说,hadoop更好一点,因为人家是磁盘里面做交互么,spark相对来说更差一点,这个和spark代码测试不足有关,因为Spark追求计算的灵活性,所以就复杂, 复杂就不好控制,不好控制就容易挂掉。

3.为什么Hadoop不被看好

很多人在谈到Spark代替Hadoop的时候,其实很大程度上指的是代替MapReduce。
MapReduce的缺陷很多,最大的缺陷之一是Map + Reduce的模型。这个模型并不适合描述复杂的数据处理过程。很多公司把各种奇怪的Machine Learning计算用MR模型描述,不断挖掘MR潜力,对系统工程师和Ops也是极大挑战了。很多计算,本质上并不是一个Map,Shuffle再Reduce的结构,比如我编译一个SubQuery的SQL,每个Query都做一次Group By,我可能需要Map,Reduce+Reduce,中间不希望有无用的Map;又或者我需要Join,这对MapReduce来说简直是噩梦,什么给左右表加标签,小表用Distributed Cache分发,各种不同Join的Hack,都是因为MapReduce本身是不直接支持Join的,其实我需要的是,两组不同的计算节点扫描了数据之后按照Key分发数据到下一个阶段再计算,就这么简单的规则而已;再或者我要表示一组复杂的数据Pipeline,数据在一个无数节点组成的图上流动,而因为MapReduce的呆板模型,我必须一次一次在一个Map/Reduce步骤完成之后不必要地把数据写到磁盘上再读出,才能继续下一个节点,因为Map Reduce2个阶段完成之后,就算是一个独立计算步骤完成,必定会写到磁盘上等待下一个Map Reduce计算。
上面这些问题,算是每个号称下一代平台都尝试解决的。现在号称次世代平台现在做的相对有前景的是Hortonworks的Tez和Databricks的Spark。他们都尝试解决了上面说的那些问题。Tez和Spark都可以很自由地描述一个Job里执行流。他们相对现在的MapReduce模型来说,极大的提升了对各种复杂处理的直接支持,不需要再绞尽脑汁“挖掘”MR模型的潜力。综上,Spark数据处理速度秒杀MapReduce因为其处理数据的方式不一样,会比MapReduce快上很多。

4.hadoop是不是要被淘汰

目前备受追捧的Spark还有很多缺陷,比如:
1、稳定性方面,由于代码质量问题,Spark长时间运行会经常出错,在架构方面,由于大量数据被缓存在RAM中,Java回收垃圾缓慢的情况严重,导致Spark性能不稳定,在复杂场景中SQL的性能甚至不如现有的Map/Reduce。
2、不能处理大数据,单独机器处理数据过大,或者由于数据出现问题导致中间结果超过RAM的大小时,常常出现RAM空间不足或无法得出结果。然而,Map/Reduce运算框架可以处理大数据,在这方面,Spark不如Map/Reduce运算框架有效。
3、不能支持复杂的SQL统计;目前Spark支持的SQL语法完整程度还不能应用在复杂数据分析中。在可管理性方面,SparkYARN的结合不完善,这就为使用过程中埋下隐忧,容易出现各种难题。在比较Hadoop和Spark方面要记住的最重要一点就是,它们并不是非此即彼的关系,因为它们不是相互排斥,也不是说一方是另一方的简易替代者。两者彼此兼容,这使得这对组合成为一种功能极其强大的解决方案,适合诸多大数据应用场合。

5.梅峰谷补充以下几点:

1)Spark能被业界接受,除了内存计算这点外还有很多原因,如DAG、生态丰富等等,从架构设计、生态设计、后续演进这几点考虑,Spark是有独到之处的。HDFS可以说是分布式的基础设施,在HDFS发展阶段,各种开源计算模型百花齐放,但是Spark终于做到一统江山了,成为一个事实上的标准,对开发人员、运维人员来说,这是福音。
2)对于大数据的学习,知识点多,有点开发基础的人,或者计算机先关专业毕业的人,找准点并不难切入; 知识点多不可怕,但没有计划的学习,比较可怕。碰到问题不怕,但是闭门造车可怕。
3)有些人常常问,要不要报培训班,报哪个。对于学习时间短要速成的人来时,是可以报个班督促下自己,但是现在的资料已经很丰富了,能消化一个完整的视频教程,基本上入门上手是没问题的,前面已经发了很多连贯完整的视频教程。
4)见到一些学生,2年前在问我大数据怎么学习,2年后还在问我同样的问题,大数据能自学好的人,我觉得已经具备了一些很好的学习素质了,无论后面技术怎么变化,学习的方法论都是同样的。记得之前读研的时候,导师(北大)并不教你什么技巧、资料,只告诉你一个方向,当时并不是很理解,工作多年后,才发现,就是让我们训练和培养出属于自己的学习方法论,这个是终生受益的,无论是新工作、新岗位、新技术、新课题,都不会害怕,技术变换无穷,问题无穷无穷,但是探索方法和流程大体是一致的。

内容转自微信公众号:大数据梅峰谷
更多文章请扫描二维码

使用代理IP编写Java网络爬虫

代理IP的获取

网络爬虫攻防常见技巧 中有获取代理IP的几种方式。

使用HttpClient编写爬虫

第一步:导入pom依赖

   <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.3</version>
        </dependency>

第二步:指定代理IP的信息
示例:

        ips.add("186.91.160.120:8080");
        ips.add("36.74.165.99:8080");
        ips.add("185.129.202.2:53281");
        ips.add("37.238.61.177:8080");
        ips.add("180.246.56.226:8080");

第三步:编写爬虫

private static void dovote(String ip, int port) throws IOException, ClientProtocolException {
        //1.投票的请求接口
        String url = "http://fendou.itcast.cn/article/updatevote";
        //2.准备请求头的信息
        Map<String, String> headers = getHeader();
        //3.创建POST请求对象
        HttpPost httpPost = new HttpPost(url);
        //4.准备请求头的信息
        for (Map.Entry<String, String> header : headers.entrySet()) {
            httpPost.addHeader(header.getKey(), header.getValue());
        }
        //5.创建代理HTTP请求
        HttpHost proxy = new HttpHost(ip, port);
        ConnectionConfig connectionConfig = ConnectionConfig.custom().setBufferSize(4128).build();
        DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
        CloseableHttpClient hc = HttpClients.custom().setDefaultConnectionConfig(connectionConfig)
                .setRoutePlanner(routePlanner).build();
        //6.使用代理HttpClient发起投票请求
        CloseableHttpResponse res = hc.execute(httpPost);
        //7.打印http请求状态码
        System.out.println("statusCode:" + res.getStatusLine().getStatusCode());
        for (Header header : res.getAllHeaders()) {
            //8.打印所有的response header信息,发现有set-cookie的信息就成功了。
            System.out.println(header);
        }
        //9.打印html信息 如果返回为空字符串 就是投票成功。有返回值的基本就是失败了。
        String html = EntityUtils.toString(res.getEntity(), Charset.forName("utf-8"));
        System.out.println("返回值:" + html);
    }

httpClient代理案例-官方手册

官方代码如下:

HttpHost proxy = new HttpHost("someproxy", 8080);
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
CloseableHttpClient httpclient = HttpClients.custom()
        .setRoutePlanner(routePlanner)
        .build();