网络爬虫(一)
1、爬虫入门案例
public class SpiderDemo {
public static void main(String[] args) throws IOException {
// 相当于打开浏览器
CloseableHttpClient httpClient = HttpClients.createDefault();
// 输入 url 地址
HttpGet httpGet = new HttpGet("http://news.baidu.com");
// 得到访问界面的起始时间
long start = System.currentTimeMillis();
// 访问地址
CloseableHttpResponse response = httpClient.execute(httpGet);
// 得到访问界面的结束时间
long end = System.currentTimeMillis();
// 解析返回的值
if(response.getStatusLine().getStatusCode() == 200){
// 得到实体
HttpEntity entity = response.getEntity();
// 得到页面数据
String contents = EntityUtils.toString(entity);
System.out.println((end - start) / 1000);
System.out.println(contents);
}
}
}
浏览器访问某一个网站的流程如下:
- 打开一个浏览器客户端
- 输入url
- 访问
- 得到响应结果
- 关闭浏览器
爬虫访问的流程和此我们手动访问浏览器的流程类似
2、请求的配置信息
有时,我们需要对请求增加一些配置,例如对get请求的配置
RequestConfig config = RequestConfig.custom()
// 创建连接的时间
.setConnectTimeout(1000)
// 获取连接的时间
.setConnectionRequestTimeout(500)
// 数据传输的时间
.setSocketTimeout(10000)
.build();
HttpGet httpGet = new HttpGet(url);
httpGet.setConfig(config;
其中配置了3个字段,创建连接的时间、获取连接的时间、数据传输的时间。
3、 带参数的get请求
public static void main(String[] args) throws Exception {
CloseableHttpClient httpClient = HttpClients.createDefault();
// https://www.baidu.com/s?ie=UTF-8&wd=%E7%99%BE%E5%BA%A6
URIBuilder uriBuilder = new URIBuilder("http://wwww.baidu.com/s");
// uriBuilder通过setParameter设置多个参数,可以使用对象链
uriBuilder.setParameter("ie", "UTF-8")
.setParameter("wd", "百度");
HttpGet httpGet = new HttpGet(uriBuilder.build());
// try-with-resource
try(CloseableHttpResponse execute = httpClient.execute(httpGet)) {
if(execute.getStatusLine().getStatusCode() == 200){
String content = EntityUtils.toString(execute.getEntity(), "utf-8");
System.out.println(content);
}
}catch (Exception e){
e.printStackTrace();
}finally {
httpClient.close();
}
}
来看一下这步
我们可以把多个get请求的参数设置到UriBuilder中,就是通过setParameter方法
4、带参数的post请求
public class PostParam {
public static void main(String[] args) throws Exception {
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("https://music.163.com/weapi/login/cellphone");
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("params", "43543543"));
// 得到表单实体
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(params, "utf8");
// 设置表实体到post请求中
httpPost.setEntity(formEntity);
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
if (response.getStatusLine().getStatusCode() == 200) {
String comment = EntityUtils.toString(response.getEntity(), "utf8");
System.out.println(comment);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
httpClient.close();
}
}
}
为什么NameValuePair中放入了一个对象呢,因为NameValuePair是一个接口,可以看到
要想在add进去键值对,就需要创建一个NameValuePair的实体类,看一下实现了这个接口的实现类
而且该实现类的构造器传入的是一个name和string,所以我们可以把要请求的参数可以直接放在这个集合中
5、HttpClient连接池
为什么使用连接池,学过jdbc的可能知道,频繁的建立连接和销毁连接会带来性能上的影响,浏览器客户端也一样,频繁的开关浏览器进行访问也是会带来性能上的影响的,所以我们使用HttpClient的连接池,每次用的时候直接从池里拿,用完之后归还到池中
public class PoolDemo {
public static void main(String[] args) throws Exception {
// 得到连接池管理器
PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager();
// 设置最大连接数量
manager.setMaxTotal(100);
// 每个主机的最大连接数量
manager.setDefaultMaxPerRoute(10);
doGet(manager);
}
private static void doGet(PoolingHttpClientConnectionManager manager) throws Exception {
// 建造者模式得到建造者
HttpClientBuilder clientBuilder = HttpClients.custom();
CloseableHttpClient httpClient = clientBuilder.build();
URIBuilder uriBuilder = new URIBuilder("http://wwww.baidu.com/s");
uriBuilder.setParameter("ie", "UTF-8")
.setParameter("wd", "百度");
HttpGet httpGet = new HttpGet(uriBuilder.build());
CloseableHttpResponse response = httpClient.execute(httpGet);
if(response.getStatusLine().getStatusCode() == 200){
String content = EntityUtils.toString(response.getEntity(), "utf8");
System.out.println(content);
}
// CloseableHttpClient 使用完后千万不要关闭,千万不要关闭,千万不要关闭,执行完后会自动归还到 连接池
}
}
PoolingHttpClientConnectionManager
连接池管理器,其实这就是一个连接池,我们可以从这个池里拿HttpClient客户端,还有就是连接池里的属性了,setMaxTotal
这个属性的意思是这个连接池里一共有多少个HttpClient客户端,setDefaultMaxPerRoute
这个属性的意思是设置每个主机的最大连接数,何为每个主机的最大连接数呢,例如我们想爬取一些新闻信息,可以同时从百度新闻、今日头条、微博上去获取,但是有一个资源分配的问题,如果我不去限制每台主机的最大连接数,那么可能造成的问题可能就是所有的连接都去爬取百度新闻和今日头条了,就没有去爬取微博的连接了,链接资源都已经被抢占了。
所以就要限制访问每个主机的最大连接数,使其资源分配均匀