今天说:httpclient,他是apache下的, 目前用它采集同步网站,
那么首先看这个代码之前,一定要先对request response 有所了解,这样可以更好懂一些,httpclient是对网络编程 也就是net包下的封装,因为URLConnection类 ,虽然也可以采集到东西,但是毕竟是原生的, 我先把异常抛出到main上 ,这样代码少一些
一会什么简介啦,ppt和我们老师上的视频都有的
一会我把所需要的jar包,放到百度网盘中 ,当然 可以添加maven依赖
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
//@Test
public void fun() throws Exception{
CloseableHttpClient httpClient = HttpClients.createDefault(); //创建实例对象
HttpGet httpGet = new HttpGet("https://www.tinaya.com/"); //这里面放需要链接的地址即可
httpGet.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36"); //为什么这里要设置请求头?
因为某些网站,是有反爬虫措施的, 这么设置,只是为了模拟人的操作而已,不然有可能封你的ip地址
/*
得到response之后,我们就需要对response进行解析了
*/
CloseableHttpResponse response = httpClient.execute(httpGet); ///执行http协议的get请求
HttpEntity entity = response.getEntity(); //得到实体
System.out.println("网页源码如下:");
String src = EntityUtils.toString(entity, "utf-8"); //以什么形式看源码?? 一般的网页在meta标签中都有一个content-type请求头,与那个对应即可
System.out.println(src);
//关流
response.close();
httpClient.close();
}
/*
为什么要得到content-type?
根据具体的MIME类型 ,来过滤
为什么要得到状态码?
因为200代表 成功, 404代表找不到,
如果不是200,那么下面的爬虫代码就不需要执行了
*/
//得到此页面的MIME类型
String value = entity.getContentType().getValue();
System.out.println(value); //输出content-type的值
//得到此页面的状态码
StatusLine line = response.getStatusLine();
System.out.println(line);//HTTP/1.1 200 OK 这个是把那一条信息都返回回来了
//但是我们一般只需要状态码,用它判断即可
int code = line.getStatusCode();
System.out.println(code);
2 HttpClient 抓取图片:
public void fun() throws Exception{
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet("http://xxxx/gg/sxt2.gif"); //只不过改为了图片地址而已
httpGet.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36");
CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
if(entity!=null){
System.out.println(entity.getContentType().getValue());
InputStream input = entity.getContent();//以流的形式(因为照片是字节,当然以流的形式传输和写入)
FileUtils.copyInputStreamToFile(input, new File("C:\\sxt.gif"));//这时你看,我保存的时候怎么知道文件是什么后缀,我可以上面写一个String imageHref 变量, 因为我知道我传入的图片路径 而路径中有名字,截取一下即可
这个方法是Commons.io包中的一个方法而已
}
设置代理ip
在爬取网页的时候,有的目标站点有反爬虫机制,对于频繁访问站点以及规则性访问站点的行为,会采集屏蔽IP措施。
这时候,代理IP就派上用场了。
关于代理IP的话 也分几种 透明代理、匿名代理、混淆代理、高匿代理
透明代理:虽然透明代理可以直接“隐藏”你的IP地址,但是还是可以查到你是谁
匿名代理比透明代理进步了一点:别人只能知道你用了代理,无法知道你是谁。
混淆代理,别人还是能知道你在用代理,但是会得到一个假的IP地址,伪装的更逼真:
高匿代理让别人根本无法发现你是在用代理,所以是最好的选择。我们使用的是高匿代理,
代理IP 从哪里搞呢 很简单 百度一下,你就知道 一大堆代理IP站点。 一般都会给出一些免费的,
CloseableHttpClient httpClient=HttpClients.createDefault(); // 创建httpClient实例
HttpGet httpGet=new HttpGet("https://www.taobao.com/"); // 创建httpget实例
HttpHost proxy=new HttpHost("116.226.217.54", 9999); //用来设置代理ip
/*
这个类位于 org.apache.http.client.config包下,主要用于获取和配置一些外部的网络环境,它下面有一个嵌套类 RequestConfig.Builder
使用方法是:先用 RequestConfig类的静态方法custom()获取requestConfig.Builder“配置器”,然后再用其下各种方法配置网络环境;
*/
RequestConfig requestConfig=RequestConfig.custom().setProxy(proxy).build();
httpGet.setConfig(requestConfig);
httpGet.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:50.0) Gecko/20100101 Firefox/50.0");
CloseableHttpResponse response=httpClient.execute(httpGet); // 执行http get请求
HttpEntity entity=response.getEntity(); // 获取返回实体
System.out.println("网页内容:"+EntityUtils.toString(entity, "utf-8")); // 获取网页内容
response.close(); // response关闭
httpClient.close(); // httpClient关闭
一般如果是你如果采集网站遇到403 ,那么可能就是被屏蔽了,这时你就应该换一个代理ip了
思路:
先做一个小爬虫,专门去 这些免费代理ip网站,得到 这ip和端口这两个数据
把代理ip和 端口 放到一个map中(队列中) 也可以
加一个判断,如果是403,取出下一个map的键值对并且移除掉这个ip
然后那么就会一直取,一直移除,再加一个判断,如果ip不够的时候,继续运作爬虫,爬取ip
httpClient在执行具体http请求时候 有一个连接的时间和读取内容的时间;
所谓连接的时候 是HttpClient发送请求的地方开始到连接上目标url主机地址的时间,
线路越通畅越快,但是由于路由复杂交错,往往连接上的时间都不固定,运气不好连不上,HttpClient的默认连接时间,
默认是1分钟,假如超过1分钟 过一会继续尝试连接,这样会有一个问题 假如遇到一个url老是连不上,会影响其他线程的线程进去,所以我们有必要进行特殊设置,比如设置10秒钟 假如10秒钟没有连接上 我们就报错,这样我们就可以进行业务上的处理,
比如我们业务上控制 过会再连接试试看。并且这个特殊url写到log4j日志里去。方便管理员查看。
ttpClient读取时间
所谓读取的时间 是HttpClient已经连接到了目标服务器,然后进行内容数据的获取,一般情况 读取数据都是很快速的,
但是假如读取的数据量大,或者是目标服务器本身的问题(比如读取数据库速度慢,并发量大等等..)也会影响读取时间。
同上,我们还是需要来特殊设置下,比如设置10秒钟 假如10秒钟还没读取完,就报错,同上,我们可以业务上处理。
如果连接超时 ,报的是connect timed out
如果读取超时 ,报的是read timed out
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet("https://www.tuicool.com/");
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(10000)//设置连接超时时间
.setSocketTimeout(10000)//设置读取超时时间
.build();
httpGet.setConfig(config);
httpGet.setHeader("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.84 Safari/537.36");
CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
System.out.println("网页源码如下:");
String src = EntityUtils.toString(entity, "utf-8");
System.out.println(src);
//关流
response.close();
httpClient.close();
/=====================================================
其实httpclient能做很多的事情,但是我们目前用它做这么多就可以,做别的哟也有别的比他做得更好,
以后你们会知道的
当解析到源码之后呢? 我们是不是就可以解析其中的内容了呢? 当然可以
但是你考虑过吗? 某些网站的前台人员代码写的不好,那么就有可能会出现,标签不能成对出现或者短标签的情况
这是htmlcleaner 或者htmlparser 登场了
个人推荐用htmlcleaner,更好用一点
HtmlCleaner clean = new HtmlCleaner();
TagNode tagNode = clean.clean(src); //就是这么用
他其中支持xpath ,我们可以用他解析内容
//标题
Object[] titles = tagNode.evaluateXPath("xpath表达式");
然后获取就行了
htmlcleaner还可以将源码转换成dom树 我们就可以用dom4j 来解析了,但是还是有点麻烦呀,因为它自带xpath了,何必再new一个xpathFacotry呢?
---------------------