深入了解Java爬虫的运用技术

您所在的位置:网站首页 1688一直不发货会有什么影响 深入了解Java爬虫的运用技术

深入了解Java爬虫的运用技术

#深入了解Java爬虫的运用技术| 来源: 网络整理| 查看: 265

首先我们需要知道关于爬虫的一些基本概念,下面我来做一些简单的介绍。

1.爬虫是什么?

爬虫又叫网络爬虫,是一种运行在互联网上为了获取数据的自动化程序或脚本

2.爬虫解决了什么问题

爬虫解决了获取数据的问题

3.爬虫爬取的数据有什么用

和搜索引擎结合使用,对数据进行分析,提取有价值的信息,得到数据的商业价值

这里写图片描述

4.爬虫的简单分类

• 通用爬虫:百度 爬取互联网所有数据的爬虫叫做通用爬虫 • 垂直爬虫:为做数据分析而爬取特定数据的爬虫叫做垂直爬虫。 总结:在互联网上,大多数都是垂直爬虫,也就是值爬取一定范围内的数据。

5.爬虫的运行原理及实现技术分析

这里写图片描述

• 1、将一个种子URL存放到队里中 • 2、从队列中读取一个URL • 3、发起网络请求(上图4-5-6步) o 3.1、域名解析,得到IP地址 o 3.2、发起HTTP请求 o 3.3、下载页面

• 4、解析HTML文档(上图7-8-9步) * 解析HMTL文档获取网页中所有URL o 分页页面是否爬取过  如果没有爬取就放入待抓取的URL队里中

总结:爬虫开发的两大核心技术

Httpclient:帮助我们更好发送网络请求 Jsoup:帮助我们更好的解析html

知道我们开发爬虫的两大核心技术后,我们简单的写一个入门级程序吧! 首先我们先导入2个核心依赖包:

org.apache.httpcomponents httpclient 4.5.3 org.jsoup jsoup 1.10.3

使用Httpclient来发送一个Get请求:

package com.yida.spider.httpclient; import java.io.IOException; import org.apache.http.HttpEntity; import org.apache.http.clienthods.CloseableHttpResponse; import org.apache.http.clienthods.HttpGet; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; public class HttpClientGet { public static void main(String[] args) throws Exception { //1.指定一个url String url = "https://www.tianyancha.com/"; //2.创建一个默认的httpclient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); //3.如果是get请求那就创建一个get对象 HttpGet httpGet = new HttpGet(url); 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"); //4.发起请求 CloseableHttpResponse execute = httpClient.execute(httpGet); //5.获取数据 HttpEntity entity = execute.getEntity(); //6.打印数据 String html = EntityUtils.toString(entity,"utf-8"); System.out.println(html); } }

使用Httpclient发送一个post请求:

package com.yida.spider.httpclient; import java.io.IOException; import java.util.ArrayList; import org.apache.http.HttpEntity; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.clienthods.CloseableHttpResponse; import org.apache.http.clienthods.HttpPost; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; public class HttpClientPost { public static void main(String[] args) throws Exception { //1.指定一个url String url = "https://www.tianyancha.com/login"; //2.创建一个默认的httpclient对象 CloseableHttpClient httpClient = HttpClients.createDefault(); //3.如果是post请求那就创建一个post对象 HttpPost httpPost = new HttpPost(url); //set header httpPost.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"); ArrayList basicNameValuePairs = new ArrayList(); //设置参数(设置登录名和密码实现自动登录) basicNameValuePairs.add(new BasicNameValuePair("username", "zhoujie")); basicNameValuePairs.add(new BasicNameValuePair("password", "1314520")); httpPost.setEntity(new UrlEncodedFormEntity(basicNameValuePairs)); CloseableHttpResponse execute = httpClient.execute(httpPost); HttpEntity entity = execute.getEntity(); String html = EntityUtils.toString(entity,"utf-8"); System.out.println(html); } }

使用Httpclient发送了get或者post请求后,给我们返回的其实是一个html文档对象,我们需要提取html文档里面有用的数据,可以使用js的getElementById等操作dom的方式来获取我们想要的数据,但是不推荐使用此方法,太繁琐,不方便,这里给大家推荐的是jsoup来解析,使用jsoup可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。

一下 既然我们已经知道了这2大核心技术的基本用法,是不是 该来运用一下呢!接下来给大家做一个比较高级的案例,挑战一下自己吧!!!案例演示的是爬取虎嗅网站的所有新闻数据,爬取之前先进行一下要使用的技术点分析。

①爬取的新闻数据这里我们选择放在mysql数据库里,由于mybatis框架比较大 ,我们这里仅仅演示的是一个案例,所以这里 采用的是Spring自带的jdbctmplate来操作 数据库 就可以了。 ②爬取 一个网站所有的新闻数据这个量是十分庞大的,为了提高我们的爬取速度,我们使用多线程来提高我们爬取新闻数据的速度,又由于创建和销毁线程开销很大,可能需要上千个时钟周期,为了避免cpu花费不必要的时间在这上面,由此使用线程池的技术。 ③我们爬取新闻的数据 过程分析:首先进入虎嗅首页(http://www.huxiu.com),按F12进入开发者模式查看新闻数据源码。发现每一条新闻数据div有一个data-id的属性对应一串数据,比如是 aid,点开几条新闻数据进行分析,我们惊奇的发现新闻的详情页url的格式是String url = “https://www.huxiu.com/article/“+aid+”.html”;那么我们先把首页所有的新闻列的data-id的属性爬取出来放进 一个消息队列里(ArrayBlockingQueue消息队列这里不做过多的介绍,有不清楚的可以留言,有必要的话我可以单独开一篇文章来进行说明),然后一直往下拉,发现虎嗅新闻的网站分页是点击加载更多来进行一个ajax请求,来获取分页数据,然后分析出分页请求必要的三个参数,由此可以进行分页数据的请求,获取所有的aid后,就可以进行详情页的url解析了,开多线程来 解析新闻的详情页,然后将解析出来的html文档放进 articleHtmlQueue消息队列中,后面的分析过程都是一样的,按照此思路进行分析下去 。。。。。。。。。。。。(略)为此结合下面的一张图来帮助大家的理解:

这里写图片描述

下面先给大家看一下整个案例的项目结构:

这里写图片描述

然后项目所需依赖 pom.xml如下 :

4.0.0 com.yida.spider spider_huxiu 0.0.1-SNAPSHOT org.apache.httpcomponents httpclient 4.5.3 org.jsoup jsoup 1.10.3 org.springframework spring-jdbc 4.2.6.RELEASE mysql mysql-connector-java 5.1.41 c3p0 c3p0 0.9.1.2 com.alibaba fastjson 1.2.31 com.google.code.gson gson 2.8.1 org.apache.maven.plugins maven-compiler-plugin 3.1 1.8 1.8 utf-8

封装新闻数据的pojo类(这里为了方便,全部使用的String):

package com.yida.spider.huxiu.pojo; public class Article { private String id; private String url; private String title; private String author; private String createTime; private String pl; private String zan; private String sc; private String content; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public String getCreateTime() { return createTime; } public void setCreateTime(String createTime) { this.createTime = createTime; } public String getPl() { return pl; } public void setPl(String pl) { this.pl = pl; } public String getZan() { return zan; } public void setZan(String zan) { this.zan = zan; } public String getSc() { return sc; } public void setSc(String sc) { this.sc = sc; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } @Override public String toString() { return "Article [url=" + url + ", title=" + title + ", author=" + author + ", createTime=" + createTime + ", pl=" + pl + ", zan=" + zan + ", sc=" + sc + ", content=" + content + "]"; } }

封装分页数据所需的HuxiuPagingResponse类:

package com.yida.spider.huxiu.pojo; public class HuxiuPagingResponse { private String data; private String last_dateline; private String msg; private String result; private String total_page; public String getData() { return data; } public void setData(String data) { this.data = data; } public String getLast_dateline() { return last_dateline; } public void setLast_dateline(String last_dateline) { this.last_dateline = last_dateline; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public String getResult() { return result; } public void setResult(String result) { this.result = result; } public String getTotal_page() { return total_page; } public void setTotal_page(String total_page) { this.total_page = total_page; } @Override public String toString() { return "HuxiuPagingResponse [data=" + data + ", last_dateline=" + last_dateline + ", msg=" + msg + ", result=" + result + ", total_page=" + total_page + "]"; } }

操作数据库的ArticleDao:

package com.yida.spider.huxiu.Dao; import org.springframework.jdbc.core.JdbcTemplate; import com.mchange.v2.c3p0.ComboPooledDataSource; import com.yida.spider.huxiu.pojo.Article; /** * JdbcTemplate 指定数据源 * drivermanagersource 数据源bug * c3p0,druid * ComboPooledDataSource * @author zhoujie * */ public class ArticleDao extends JdbcTemplate{ //通过构造方法加载数据源 public ArticleDao() { // 创建C3P0的datasource 1.配置 2.代码 ComboPooledDataSource dataSource = new ComboPooledDataSource(); // 1.url // 2.driver // 3.username&password dataSource.setUser("root"); dataSource.setPassword("root"); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/spider?characterEncoding=utf-8"); setDataSource(dataSource); } public void save(Article article) { String sql = "INSERT INTO `spider`.`huxiu_article` (`id`, `title`, `author`, `createTime`, `zan`, `pl`, `sc`, `content`, `url` ) VALUES( ?,?,?,?,?,?,?,?,?)"; update(sql, article.getId(),article.getTitle(),article.getAuthor(),article.getCreateTime(),article.getZan(),article.getPl(),article.getSc(),article.getContent(),article.getUrl()); } }

主入口HuxiuSpiderThreadPool:

package com.yida.spider.huxiu; import java.io.IOException; import java.util.ArrayList; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import org.apache.http.HttpEntity; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.clienthods.CloseableHttpResponse; import org.apache.http.clienthods.HttpGet; import org.apache.http.clienthods.HttpPost; import org.apache.http.clienthods.HttpRequestBase; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import com.google.gson.Gson; import com.yida.spider.huxiu.Dao.ArticleDao; import com.yida.spider.huxiu.pojo.Article; import com.yida.spider.huxiu.pojo.HuxiuPagingResponse; import com.yida.spider.huxiu.thread.ParseHtmlRunnable; import com.yida.spider.huxiu.thread.ProcessSinglePageRunnable; import com.yida.spider.huxiu.thread.SaveArticleRunnable; public class HuxiuSpiderThreadPool { // 保存数据 public static ArticleDao articleDao = new ArticleDao(); //创建固定线程池 private static ExecutorService threadPool = Executors.newFixedThreadPool(30); // dataline用来做分页的请求 private static String dateLine = null; //队列---从首页和分页解析出来的文章url,存放在这个队列中 public static ArrayBlockingQueue urlQueue = new ArrayBlockingQueue(1000); //队列---每个文章解析出来的html文档,放在这个队列中 public static ArrayBlockingQueue articleHtmlQueue = new ArrayBlockingQueue(1000); //队列---每个文章的内容,也就是article对象,存放这个队列中 public static ArrayBlockingQueue articleContentQueue = new ArrayBlockingQueue(1000); public static void main(String[] args) { //提交线程 用来针对每个文章的url ----进行网络请求 for(int i = 1;i @Override public void run() { while(true){ try { // 从articleContentQueue队列取出article对象放到数据库中 Article article = HuxiuSpiderThreadPool.articleContentQueue.take(); HuxiuSpiderThreadPool.articleDao.save(article); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }

最后运行一下我们的程序吧!等待程序跑几小时的结果!(我只跑了1个小时,查看一下趴了多少条数据吧~)

这里写图片描述

这里写图片描述

这里再来扩展一下,随着越来越多的企业开始注重数据这一块的安全性,马云说过,在过去拥有石油就是拥有财富,但是未来是大数据的时代,拥有数据就是拥有财富,人工智能、自动驾驶的小汽车(每秒产生大约100G的庞大数据)……数据更是一块宝地,相信在未来更能体现出来! 当然涉及到爬虫技术,这里介绍的只是一些,还有爬虫的攻防技术。想想如果你是虎嗅的老板,如果这些数据都是你花钱辛辛苦苦收集来的,你会让别人轻易去爬取你的数据吗?肯定是不会的!

那么如何发现爬虫呢?这里简单介绍一下(主要通过如下的技术手段):

单一IP非常规的访问频次 单一IP非常规的数据流量 大量重复简单点的网站浏览行为 只下载网页,没有后续的JS\CSS请求 设置陷阱,使用hidden属性对用户隐藏标签但爬虫可见。 判断请求头 判断cookie

自古以来 ,有攻就有受,这是自然而然的道理!那么如果我们非要去爬取数据并且避免被发现呢?(主要通过如下的技术手段)

多主机策略,分布式爬取。 调整爬取速度 通过变换IP地址或者使用代理服务器来演示 频繁修改自己的User-Agent Header中的Cache-Control修改为no-cache 当返回状态码是403(服务器资源禁止访问),改变Header和IP。不断改变。

好了,有关爬虫的介绍就到这里了,喜欢本文的点个赞吧!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3