本爬虫进行部署 : 部署的基本流程, maven的jar项目应该如何打包处理
注意: 在进行项目打包的过程中, 如果使用maven的项目. 而且maven的项目是一个jar项目, 在进行打包的时候必须添加打包插件, 因为maven在进行jar工程打包的时候, 默认不会将这个jar工程所依赖第三方的jar打入到包中
需要注意, 在打包插件中有一个用于设置jar包的执行的主入口类的设置
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.1version>
<configuration>
<source>1.8source>
<target>1.8target>
<encoding>utf-8encoding>
configuration>
plugin>
<plugin>
<artifactId>maven-assembly-pluginartifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.itheima.jd.spider.SlaveJdmainClass>
manifest>
archive>
<descriptorRefs>
<descriptorRef>jar-with-dependenciesdescriptorRef>
descriptorRefs>
configuration>
plugin>
plugins>
build>
[外链图片转存失败(img-gyu6WM7j-1563324057116)(assets/1538298002386.png)]
[外链图片转存失败(img-silodIca-1563324057119)(assets/1538298062360.png)]
[外链图片转存失败(img-WwnudF4o-1563324057119)(assets/1538298166074.png)]
[外链图片转存失败(img-PPdNhhep-1563324057120)(assets/1538298257688.png)]
[外链图片转存失败(img-JcLGP8AO-1563324057121)(assets/1538298293513.png)]
[外链图片转存失败(img-XkxOjgkX-1563324057121)(assets/1538298445273.png)]
这里推荐使用的 rz 上传命令, 如果需要使用rz, 需要先按照rz命令
安装命令: yum -y install lrzsz
默认上传的位置就是输入rz命令的位置
上传命令: rz
上传的目录: /export/servers/spider
mkdir -p /export/servers/spider
cd /export/servers/spider
rz # 上传
java -jar xxx.jar 即可
[外链图片转存失败(img-rFJNbbYN-1563324057122)(assets/1538298738373.png)]
解决方案: 在 dao类中, 连接数据库的字符串中添加如下内容: characterEncoding=UTF-8
[外链图片转存失败(img-Umrofjkz-1563324057123)(assets/1538298857744.png)]
出现的主要原因是 本地连接的密码, 有可能和远程连接的密码不一致, 执行下列操作, 修改本地和远程的密码
修改数据库密码
use mysql;
UPDATE user SET Password = PASSWORD('123456') WHERE user = 'root';
flush privileges;
开启远程连接
use mysql;
grant all privileges on *.* to root@"%" identified by "123456" with grant option;
flush privileges;
执行上述命令后, 使用Navicat打开远程数据库, 删除下列数据即可
[外链图片转存失败(img-BUUQ30f7-1563324057125)(assets/1538299336033.png)]
删除后, 然后重新启动mysql服务即可: service mysql restart
[外链图片转存失败(img-gc1Fa1b7-1563324057125)(assets/1557712789450.png)]
分布式: 分布式指的就是某一个模块, 或者某个系统, 拆分成不同的业务,并进行分开部署,
集群: 集群更多强调的是将相同的模块或者是系统, 重复部署多次
一般来说, 在大多数的情况下, 集群和分布式是同时存在, 共同作用于整个项目
通俗描述:
小饭店原来只有一个厨师,切菜洗菜备料炒菜全干。
后来客人多了,厨房一个厨师忙不过来,又请了个厨师,两个厨师都能炒一样的菜,这两个厨师的关系是集群。
为了让厨师专心炒菜,把菜做到极致,又请了个配菜师负责切菜,备菜,备料,厨师和配菜师的关系是分布式。
一个配菜师也忙不过来了,又请了个配菜师,两个配菜师关系是集群。
从刚才的案例中, 请分析出, 集群和分布式能解决什么样的问题?
缺点: 提高开发难度
[外链图片转存失败(img-PruV9YBe-1563324057126)(assets/1538301333207.png)]
专门用来获取163新闻详情页url程序
专门用来解析163新闻详情页的程序
专门用来保存数据的程序 (公共的程序)
专门用来获取腾讯新闻数据的程序
[外链图片转存失败(img-xnR5GhXf-1563324057127)(assets/1538573149803.png)]
1) 用来执行去重的公共的key: set
bigData:spider:docurl
2) 用来保存详情页docurl的key: list
bigData:spider:163itemUrl:docurl
3) 用来保存news对象key : list
bigData:spider:newsJson
说明: 163爬虫一共要拆分成三个子工程, 目前将第一个工程命名为News163Master 第二个工程命名为 News163Slave 第三个工程命名为 PublicDaoNode
package com.itheima.spider.version2;
//需求: 获取详情页的url
import com.google.gson.Gson;
import com.itheima.spider.pojo.News;
import com.itheima.spider.utils.HttpClientUtils;
import com.itheima.spider.utils.JedisUtils;
import redis.clients.jedis.Jedis;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 1) 确定首页url 2) 发送请求, 获取数据 3) 解析数据 4) 去重判断 5) 将docurl保存到redis中 6) 获取下一页
*/
public class News163Master {
public static void main(String[] args) throws Exception {
//1. 确定首页url:
List<String> urlList = new ArrayList<String>();
urlList.add("https://ent.163.com/special/000380VU/newsdata_index.js?callback=data_callback");
urlList.add("https://ent.163.com/special/000380VU/newsdata_star.js?callback=data_callback");
urlList.add("https://ent.163.com/special/000380VU/newsdata_movie.js?callback=data_callback");
urlList.add("https://ent.163.com/special/000380VU/newsdata_tv.js?callback=data_callback");
urlList.add("https://ent.163.com/special/000380VU/newsdata_show.js?callback=data_callback");
urlList.add("https://ent.163.com/special/000380VU/newsdata_music.js?callback=data_callback");
//5. 分页获取数据
while(!urlList.isEmpty()) {
String indexUrl = urlList.remove(0);
System.out.println("获取了下一个栏目的数据#######################################" );
page(indexUrl);
}
}
// 执行分页的方法
public static void page(String indexUrl) throws Exception{
String page = "02";
while(true) {
//1. 发送请求获取数据
// 此处获取的json的数据, 并不是一个非标准的json
String jsonStr = HttpClientUtils.doGet(indexUrl);
if(jsonStr==null){
System.out.println("数据获取完成");
break;
}
// 转换为标准json方法
jsonStr = splitJson(jsonStr);
//2. 解析数据, 3 保存数据
parseJson(jsonStr);
//4. 获取下一页的url
if(indexUrl.contains("newsdata_index")){
indexUrl = "https://ent.163.com/special/000380VU/newsdata_index_" + page + ".js?callback=data_callback";
}
if(indexUrl.contains("newsdata_star")){
indexUrl = "https://ent.163.com/special/000380VU/newsdata_star_" + page + ".js?callback=data_callback";
}
if(indexUrl.contains("newsdata_movie")){
indexUrl = "https://ent.163.com/special/000380VU/newsdata_movie_" + page + ".js?callback=data_callback";
}
if(indexUrl.contains("newsdata_tv")){
indexUrl = "https://ent.163.com/special/000380VU/newsdata_tv_" + page + ".js?callback=data_callback";
}
if(indexUrl.contains("newsdata_show")){
indexUrl = "https://ent.163.com/special/000380VU/newsdata_show_" + page + ".js?callback=data_callback";
}
if(indexUrl.contains("newsdata_music")){
indexUrl = "https://ent.163.com/special/000380VU/newsdata_music_" + page + ".js?callback=data_callback";
}
System.out.println(indexUrl);
//5. page ++
int pageNum = Integer.parseInt(page);
pageNum++;
if(pageNum <10){
page = "0"+pageNum;
}else{
page = pageNum+"";
}
}
}
// 解析json的方法
private static void parseJson(String jsonStr) throws Exception{
//3.1 将json字符串转换成 指定的对象
Gson gson = new Gson();
List<Map<String, Object>> newsList = gson.fromJson(jsonStr, List.class);
// 3.2 遍历整个新闻的结合, 获取每一个新闻的对象
for (Map<String, Object> newsObj : newsList) {
// 新闻 : 标题, 时间,来源 , 内容 , 新闻编辑 , 新闻的url
//3.2.1 获取新闻的url , 需要根据url, 获取详情页中新闻数据
String docUrl = (String) newsObj.get("docurl");
// 过滤掉一些不是新闻数据的url
if(docUrl.contains("photoview")){
continue;
}
if(docUrl.contains("v.163.com")){
continue;
}
if(docUrl.contains("c.m.163.com")){
continue;
}
if(docUrl.contains("dy.163.com")){
continue;
}
// ###################去重处理代码######################
Jedis jedis = JedisUtils.getJedis();
Boolean flag = jedis.sismember("bigData:spider:docurl", docUrl);
jedis.close();//一定一定一定不要忘记关闭, 否则用着用着没了, 导致程序卡死不动
if(flag){
// 代表存在, 表示已经爬取过了
continue;
}
// ###################去重处理代码######################
// 将docurl存储到redis的list集合中
jedis = JedisUtils.getJedis();
jedis.lpush("bigData:spider:163itemUrl:docurl",docUrl);
jedis.close();
}
}
// 将非标准的json转换为标准的json字符串
private static String splitJson(String jsonStr) {
int firstIndex = jsonStr.indexOf("(");
int lastIndex = jsonStr.lastIndexOf(")");
return jsonStr.substring(firstIndex + 1, lastIndex);
}
}
package com.itheima.spider.version2;
import com.google.gson.Gson;
import com.itheima.spider.pojo.News;
import com.itheima.spider.utils.HttpClientUtils;
import com.itheima.spider.utils.IdWorker;
import com.itheima.spider.utils.JedisUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import redis.clients.jedis.Jedis;
import java.util.List;
// 需求 : 解析新闻详情页的数据
// 步骤: 1) 从redis中获取docurl 2) 根据url解析商品的详情页 3) 封装成news对象 4) 将news对象转换为json数据
// 5) 将newsJson存储到redis的list中 6) 循环
public class News163Slave {
private static IdWorker idWorker = new IdWorker(0,1);
public static void main(String[] args) throws Exception {
while (true) {
//1.从redis中获取docurl
Jedis jedis = JedisUtils.getJedis();
//String docurl = jedis.rpop("bigData:spider:163itemUrl:docurl"); // 取不到的时候出来
// 第一个参数: 阻塞的时间 如果list中没有数据了, 就会进行阻塞, 最多阻塞20s. 如果在23s之内有数据进来, 马上解除阻塞
// 返回值: list 在这个list中只会有两个元素, 第一个元素为key值 第二个元素为弹出的元素
List<String> list = jedis.brpop(20, "bigData:spider:163itemUrl:docurl");
jedis.close();
if(list == null || list.size()==0 ){
break;
}
String docurl = list.get(1);
//2. 根据url解析商品的详情页 封装成news对象
News news = parseNewsItem(docurl);
//3. 将news对象转换为json数据
Gson gson = new Gson();
String newsJson = gson.toJson(news);
//4. 将newsJson存储到redis中
jedis = JedisUtils.getJedis();
jedis.lpush("bigData:spider:newsJson", newsJson);
jedis.close();
}
}
// 根据url 解析新闻详情页:
private static News parseNewsItem(String docUrl) throws Exception {
System.out.println(docUrl);
// 3.3.1 发送请求, 获取新闻详情页数据
String html = HttpClientUtils.doGet(docUrl);
//3.3.2 解析新闻详情页:
Document document = Jsoup.parse(html);
//3.3.2.1 : 解析新闻的标题:
News news = new News();
Elements h1El = document.select("#epContentLeft h1");
String title = h1El.text();
news.setTitle(title);
//3.3.2.2 : 解析新闻的时间:
Elements timeAndSourceEl = document.select(".post_time_source");
String timeAndSource = timeAndSourceEl.text();
String[] split = timeAndSource.split(" 来源: ");// 请各位一定一定一定要复制, 否则会切割失败
news.setTime(split[0]);
//3.3.2.3 : 解析新闻的来源:
news.setSource(split[1]);
//3.3.2.4 : 解析新闻的正文:
Elements ps = document.select("#endText p");
String content = ps.text();
news.setContent(content);
//3.3.2.5 : 解析新闻的编辑:
Elements spanEl = document.select(".ep-editor");
// 责任编辑:陈少杰_b6952
String editor = spanEl.text();
// 一定要接收返回值, 否则白写了
editor = editor.substring(editor.indexOf(":") + 1, editor.lastIndexOf("_"));
news.setEditor(editor);
//3.3.2.6 : 解析新闻的url:
news.setDocurl(docUrl);
//3.3.2.7: id
long id = idWorker.nextId();
news.setId(id + "");
return news;
}
}
package com.itheima.spider.version2;
import com.google.gson.Gson;
import com.itheima.spider.dao.NewsDao;
import com.itheima.spider.pojo.News;
import com.itheima.spider.utils.JedisUtils;
import redis.clients.jedis.Jedis;
import java.util.List;
// 需求 : 公共的保存数据库的程序:
// 步骤: 1) 从redis中获取newsJson数据 2) 将newsJson转换成news对象 3) 去重判断 4) 保存数据
// 5) 将docurl存储到redis的去重的set集合中 6) 循环
public class PublicDaoNode {
private static NewsDao newsDao = new NewsDao();
public static void main(String[] args) {
while(true) {
//1) 从redis中获取newsJson数据
Jedis jedis = JedisUtils.getJedis();
List<String> list = jedis.brpop(20, "bigData:spider:newsJson");
jedis.close();
if (list == null || list.size() == 0) {
break;
}
String newsJson = list.get(1);
System.out.println(newsJson);
//2. 将newsJson转换成news对象
Gson gson = new Gson();
News news = gson.fromJson(newsJson, News.class);
//3) 去重判断
jedis = JedisUtils.getJedis();
Boolean flag = jedis.sismember("bigData:spider:docurl", news.getDocurl());
jedis.close();
if (flag) {
continue;
}
//4) 保存数据
newsDao.saveNews(news);
// 5) 将docurl存储到redis的去重的set集合中
jedis = JedisUtils.getJedis();
jedis.sadd("bigData:spider:docurl", news.getDocurl());
jedis.close();
}
}
}
说明: 腾讯娱乐爬虫需要拆分成二个子工程, 一个子工程用于获取数据,封装news对象, 一个公共的子工程用于保存数据, 其中公共的已经开发完毕, 只需要拆分另一个子工程名为NewsTencentMaster即可
package com.itheima.spider.version2;
import com.google.gson.Gson;
import com.itheima.spider.pojo.News;
import com.itheima.spider.utils.HttpClientUtils;
import com.itheima.spider.utils.IdWorker;
import com.itheima.spider.utils.JedisUtils;
import redis.clients.jedis.Jedis;
import sun.security.jgss.GSSCaller;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
// 需求 : 解析数据, 封装成news对象, 将news对象保存到redis中
// 1) 确定首页url 2) 发送请求, 获取数据 3) 解析数据 4) 去重判断 5) 封装news对象 6) 将news对象转换为newsJson
// 7) 将newsJson保存到Redis中 8) 分页获取
public class NewsTencentMaster {
private static IdWorker idWorker = new IdWorker(0,2);
public static void main(String[] args) throws Exception {
//1. 确定首页url
String topNewsUrl = "https://pacaio.match.qq.com/irs/rcd?cid=137&token=d0f13d594edfc180f5bf6b845456f3ea&ext=ent&num=60";
String noTopNewsUrl = "https://pacaio.match.qq.com/irs/rcd?cid=146&token=49cbb2154853ef1a74ff4e53723372ce&ext=ent&page=0";
//2. 执行分页:
page(topNewsUrl, noTopNewsUrl);
}
// 执行分页的方法
public static void page(String topNewsUrl, String noTopNewsUrl) throws Exception {
//1. 热点新闻数据的获取: 只有一页数据
//1.1 发送请求, 获取数据
String topNewsJsonStr = HttpClientUtils.doGet(topNewsUrl);
//1.2 解析数据
List<News> topNewsList = parseJson(topNewsJsonStr);
//1.3 保存数据
saveNews(topNewsList);
//2. 处理非热点数据
int page = 1;
while (true) {
//2.1 发送请求, 获取数据
String noTopNewsJsonStr = HttpClientUtils.doGet(noTopNewsUrl);
//2.2 解析数据
List<News> noTopNewsList = parseJson(noTopNewsJsonStr);
if (noTopNewsList == null) {
break;
}
//2.3 保存数据
saveNews(noTopNewsList);
//2.4 获取下一页url
noTopNewsUrl = "https://pacaio.match.qq.com/irs/rcd?cid=146&token=49cbb2154853ef1a74ff4e53723372ce&ext=ent&page=" + page;
//2.5 自增 +1
page++;
System.out.println(page);
}
}
// 保存数据的操作 : 腾讯返回数据的时候, 就会有重复的数据
public static void saveNews(List<News> newsList) {
Jedis jedis = JedisUtils.getJedis();
Gson gson = new Gson();
for (News news : newsList) {
// 需要将news对象转换为newsJson
String newsJson = gson.toJson(news);
// 将newsJson存储到redis的list集合中
jedis.lpush("bigData:spider:newsJson",newsJson);
}
jedis.close();
}
// 解析新闻数据
private static List<News> parseJson(String newsJsonStr) {
//3.1 将字符串json数据转换为指定的类型: map
Gson gson = new Gson();
Map<String, Object> map = gson.fromJson(newsJsonStr, Map.class);
//获取一下, 本次获取了多少条数据
Double datanum = (Double) map.get("datanum");
if (datanum.intValue() == 0) {
return null;
}
//3.2 获取data中数据 : 列表页中数据
List<Map<String, Object>> newsList = (List<Map<String, Object>>) map.get("data");
//3.3 遍历这个列表, 获取每一个新闻的数据
List<News> tencentNewList = new ArrayList<News>();
for (Map<String, Object> newsMap : newsList) {
String docurl = (String) newsMap.get("vurl");
if (docurl.contains("video")) {
continue;
}
//######################去重处理############################33
Jedis jedis = JedisUtils.getJedis();
Boolean flag = jedis.sismember("bigData:spider:docurl", docurl);
jedis.close();
if (flag) {
// 如果为true, 表示已经存在, 已经爬取过了
continue;
}
//######################去重处理############################33
//3.3.1 封装news对象
News news = new News();
news.setTitle((String) newsMap.get("title"));
news.setTime((String) newsMap.get("update_time"));
news.setSource((String) newsMap.get("source"));
news.setContent((String) newsMap.get("intro"));
news.setEditor((String) newsMap.get("source"));
news.setDocurl(docurl);
news.setId(idWorker.nextId() + "");
tencentNewList.add(news);
System.out.println(docurl);
}
return tencentNewList;
}
}
注意: 开发完成以后., 一定要进行测试:如果能够在本地全部跑通, 才可以进行部署, 否则不要进行部署
说明: 目前一共有四个子项目, 其中二个master各占用一台虚拟机, 其中一个用来解析新闻详情页, 可以部署一个两台的集群, 其中一个用来保存数据的, 可以部署三台,构建一个集群, 一共为七台, 外加一台mysql和一台redis, 共需要九台服务器
[外链图片转存失败(img-msjCNTCu-1563324057128)(assets/1538574257790.png)]
将项目进行打包:一共有四个子项目, 共需要打包四个jar
[外链图片转存失败(img-kv0Ot3Ex-1563324057129)(assets/1544080592257.png)]
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<version>3.1version>
<configuration>
<source>1.8source>
<target>1.8target>
<encoding>utf-8encoding>
configuration>
plugin>
<plugin>
<artifactId>maven-assembly-pluginartifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.itheima.jdSpider.JdSlavemainClass>
manifest>
archive>
<descriptorRefs>
<descriptorRef>jar-with-dependenciesdescriptorRef>
descriptorRefs>
configuration>
plugin>
plugins>
[外链图片转存失败(img-lSONUX9r-1563324057129)(assets/1538574857793.png)]
[外链图片转存失败(img-1dl3FrXP-1563324057129)(assets/1538574959362.png)]
[外链图片转存失败(img-Qtv2tJDb-1563324057130)(assets/1538575008618.png)]
[外链图片转存失败(img-2uV9vj0J-1563324057131)(assets/1538575060321.png)]
[外链图片转存失败(img-bbG27cjy-1563324057131)(assets/1538575219745.png)]
注意: 需要单独对163slave程序再次进行打包操作. 在导包的时候, 需要修改idwork中编号,否则在部署的时候, 会出现id冲突的问题
因为, IDwork如果编号都一致了, 那么在同一时刻产生的id值是一样的
[外链图片转存失败(img-2wiNen8i-1563324057132)(assets/1544081473781.png)]
使用三台虚拟机模拟9台服务器, 其本质上就是使用xshell 或者 CRT 将三台虚拟机的连接窗口开启各开启三次即可, 然后自己进行分配, 那一台是MySQL, 那一台是Redis, 那一台是master…
统一jar包上传至 ; /export/servers/spider 目录下
mkdir -p /export/servers/spider
rm -rf /export/servers/spider/*
cd /export/servers/spider
1) 安装 rz 命令:
安装命令: yum -y install lrzsz
2) 上传命令: rz
注意: 上传的位置和输入rz命令的位置是一样的
启动命令: java -jar xxx.jar
将爬虫设置为定时执行获取数据的操作: 目前采用的shell脚本的方式来操作
需求: 每二十分钟执行一次爬虫程序, 用于爬取最新的新闻信息
实现步骤:
vi /etc/hosts
修改如下内容:
192.168.72.141 node01
192.168.72.142 node02
192.168.72.143 node03
三台服务器必须要配置免密登录
注意: 在进行修改shell脚本的时候, 一定要明确, 那台机子上部署了什么jar包
vi startSpider.sh
i
#脚本内容: 以下脚本为示例内容, 只提供大体逻辑, 根据实际进行局部修改
#!/bin/sh
echo "开始执行"
for host in node01 node02 node03
do
ssh -q $host "source /etc/profile; nohup java -jar /export/servers/spider/PublicDaoNode.jar >>/dev/daoLog.log 2>&1 &"
if [ $host == node01 ]
then
ssh -q $host "source /etc/profile; nohup java -jar /export/servers/spider/News163Slave.jar >>/dev/163Slave.log 2>&1 &"
fi
if [ $host == node02 ]
then
ssh -q $host "source /etc/profile; nohup java -jar /export/servers/spider/News163Slave.jar >>/dev/163Slave.log 2>&1 &"
fi
if [ $host == node03 ]
then
ssh -q $host "source /etc/profile; nohup java -jar /export/servers/spider/News163Master.jar >>/dev/163Master.log 2>&1 &"
ssh -q $host "source /etc/profile; nohup java -jar /export/servers/spider/NewsTencentMaster.jar >>/dev/tencent.log 2>&1 &"
fi
done
echo "结束了"
crontab -e // 设置定时, 输入完成后会自动进入一个设置文档中
输入 i 进入编辑模式
*/10 * * * * sh /export/servers/spider/startSpider.sh // 表示每隔10分钟执行一次 启动爬虫的脚本
输入 esc 退出命令行模式, 输入 :wq 保存退出即可
[外链图片转存失败(img-kOqqxhAt-1563324057132)(assets/1541345656514.png)]
掌握的程度: 能够拿自己的话, 将攻防技术说出来即可
public static void main(String[] args) throws Exception {
HttpGet httpGet = new HttpGet("https://news.163.com/");
//我是专门用来模拟浏览器,让我的请求看起来和真实的浏览器一样
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, br");
httpGet.setHeader("Accept-Language", "zh-CN,zh;q=0.8");
httpGet.setHeader("Cache-Control", "no-cache");
httpGet.setHeader("Cookie", "_ntes_nnid=4b1a6bbc71e14269912bdc23980b3fb1,1531559784738; _ntes_nuid=4b1a6bbc71e14269912bdc23980b3fb1;");
httpGet.setHeader("Host", "news.163.com");
httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36");
httpGet.setHeader("referer","http://news.163.com/");
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse res = httpClient.execute(httpGet);
HttpEntity entity = res.getEntity();
String html = EntityUtils.toString(entity,"utf-8");
System.out.println(html);
}
[外链图片转存失败(img-QIQplQ4n-1563324057133)(assets/代理方式.png)]
总结: 使用代理服务器(ip)可以掩盖爬虫程序所在的服务器的真实ip地址, 导致另一方无法获取到其真实的ip,也就无法将其截获
[外链图片转存失败(img-p1PwIJ3W-1563324057134)(assets/西刺代理.png)]
[外链图片转存失败(img-2B0QJAFf-1563324057135)(assets/站大爷.png)]
[外链图片转存失败(img-IM9Cxaxt-1563324057135)(assets/站大爷购买.png)]
参考文章:说说代理IP哪家好 https://www.zhihu.com/question/55807309
火箭代理购买
网址:http://www.httpdaili.com/
购买:淘宝链接 https://item.taobao.com/item.htm?id=557165570553
提取:http://www.httpdaili.com/#c-5
[外链图片转存失败(img-rKZfJJUj-1563324057135)(assets/火箭代理API调用方案.png)]
使用花刺软件验证带来IP是否可用
使用资料中提供的花刺软件进行检测即可
解压之后启动程序
[外链图片转存失败(img-nexh4Jmo-1563324057136)(assets/西刺1.jpg)]
粘贴购买的代理IP
[外链图片转存失败(img-PH6HmzDU-1563324057137)(assets/西刺2.jpg)]
选择验证
[外链图片转存失败(img-jH5RyfTK-1563324057137)(assets/西刺3.jpg)]
去除连接失败、响应时间比较长的,最后导出
[外链图片转存失败(img-kvpfbmf0-1563324057137)(assets/西刺4.jpg)]
http://hc.apache.org/httpcomponents-client-4.5.x/tutorial/html/connmgmt.html#d5e485
HttpHost proxy = new HttpHost("someproxy", 8080);
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
CloseableHttpClient httpclient = HttpClients.custom()
.setRoutePlanner(routePlanner)
.build();
public void testInitIP() throws Exception {
Jedis conn = JedisUtil.getConn();
BufferedReader bufferedReader = new BufferedReader(
new FileReader(new File("C:\\Users\\maoxiangyi\\Desktop\\Proxies2018-06-06.txt")));
String line = null;
while ((line=bufferedReader.readLine())!=null) {
conn.lpush("spider:ip", line);
}
bufferedReader.close();
conn.close();
}
private static String execute(HttpRequestBase request) {
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(5000)// 设置创建连接的最长时间
.setConnectionRequestTimeout(5000)// 设置获取连接的最长时间
.setSocketTimeout(10 * 1000)// 设置数据传输的最长时间
.build();
request.setConfig(requestConfig);
String html = null;
// 从redis中获取代理IP
Jedis conn = JedisUtil.getConn();
// 从右边弹出一个元素之后,从新放回左边
List<String> ipkv = conn.brpop(0, "spider:ip");
// CloseableHttpClient httpClient = getHttpClient();
CloseableHttpClient httpClient = getProxyHttpClient(ipkv.get(1));
try {
CloseableHttpResponse res = httpClient.execute(request);
if (200 == res.getStatusLine().getStatusCode()) {
html = EntityUtils.toString(res.getEntity(), Charset.forName("utf-8"));
//请求成功之后,将代理IP放回去,下次继续使用
conn.lpush("spider:ip", ipkv.get(1));
conn.close();
}
} catch (Exception e) {
System.out.println("请求失败");
// TODO 需要开发自动重试功能
throw new RuntimeException(e);
}
return html;
}
private static PoolingHttpClientConnectionManager cm;
private static CloseableHttpClient getProxyHttpClient(String ipkv) {
String[] vals = ipkv.split(":");
System.out.println(vals);
HttpHost proxy = new HttpHost(vals[0], Integer.parseInt(vals[1]));
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
return HttpClients.custom().setConnectionManager(connectionManager).setRoutePlanner(routePlanner).build();
}
String> ipkv = conn.brpop(0, “spider:ip”);
// CloseableHttpClient httpClient = getHttpClient();
CloseableHttpClient httpClient = getProxyHttpClient(ipkv.get(1));
try {
CloseableHttpResponse res = httpClient.execute(request);
if (200 == res.getStatusLine().getStatusCode()) {
html = EntityUtils.toString(res.getEntity(), Charset.forName(“utf-8”));
//请求成功之后,将代理IP放回去,下次继续使用
conn.lpush(“spider:ip”, ipkv.get(1));
conn.close();
}
} catch (Exception e) {
System.out.println(“请求失败”);
// TODO 需要开发自动重试功能
throw new RuntimeException(e);
}
return html;
}
private static PoolingHttpClientConnectionManager cm;
private static CloseableHttpClient getProxyHttpClient(String ipkv) {
String[] vals = ipkv.split(":");
System.out.println(vals);
HttpHost proxy = new HttpHost(vals[0], Integer.parseInt(vals[1]));
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
return HttpClients.custom().setConnectionManager(connectionManager).setRoutePlanner(routePlanner).build();
}