网络爬虫介绍及HttpClient使用

网络爬虫介绍及HttpClient使用

微信搜索 zze_coding 或扫描 👉 二维码关注我的微信公众号获取更多资源推送:

网络爬虫介绍

网络爬虫(Web crawler),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。
在大数据时代,信息的采集是一项重要的工作,而互联网中的数据是海量的,如果单纯靠人力进行信息采集,不仅低效繁琐,搜集的成本也会提高。如何自动高效地获取互联网中我们感兴趣的信息并为我们所用是一个重要的问题,而爬虫技术就是为了解决这些问题而生的。
网络爬虫(Web crawler)也叫做网络机器人,可以代替人们自动地在互联网中进行数据信息的采集与整理。它是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本,可以自动采集所有其能够访问到的页面内容,以获取相关数据。
从功能上来讲,爬虫一般分为数据采集,处理,储存三个部分。爬虫从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件。

网络爬虫的作用

可以实现搜索引擎

我们学会了爬虫编写之后,就可以利用爬虫自动地采集互联网中的信息,采集回来后进行相应的存储或处理,在需要检索某些信息的时候,只需在采集回来的信息中进行检索,即实现了私人的搜索引擎。

大数据时代,可以让我们获取更多的数据源

在进行大数据分析或者进行数据挖掘的时候,需要有数据源进行分析。我们可以从某些提供数据统计的网站获得,也可以从某些文献或内部资料中获得,但是这些获得数据的方式,有时很难满足我们对数据的需求,而手动从互联网中去寻找这些数据,则耗费的精力过大。此时就可以利用爬虫技术,自动地从互联网中获取我们感兴趣的数据内容,并将这些数据内容爬取回来,作为我们的数据源,再进行更深层次的数据分析,并获得更多有价值的信息。

可以更好地进行搜索引擎优化(SEO)

对于很多 SEO 从业者来说,为了更好的完成工作,那么就必须要对搜索引擎的工作原理非常清楚,同时也需要掌握搜索引擎爬虫的工作原理。而学习爬虫,可以更深层次地理解搜索引擎爬虫的工作原理,这样在进行搜索引擎优化时,才能知己知彼,百战不殆。

入门程序

环境

  • JDK1.8
  • Intellij IDEA
  • Maven

依赖

<!--HttpClient支持-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
<!--日志整合-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>

日志文件

log4j.rootLogger=DEBUG,A1
log4j.logger.xyz.zze=DEBUG

log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-d{yyyy-MM-dd HH:mm:ss,SSS}[%t] [%c]-[%p] %m%n

编写代码

package xyz.zze.crawler.test;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class CrawlerFirst {

    public static void main(String[] args) throws Exception {
        // 打开浏览器,对应创建 HttpClient 对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 输入网址,创建 HttpGet 对象发起 get 请求
        HttpGet httpGet = new HttpGet("http://jd.com");
        // 按回车,发起请求,返回响应
        CloseableHttpResponse response = httpClient.execute(httpGet);
        // 解析响应数据
        if(response.getStatusLine().getStatusCode() ==200){
            HttpEntity httpEntity = response.getEntity();
            String content = EntityUtils.toString(httpEntity);
            System.out.println(content);
        }
    }
}

可以看到京东的 html 页面已经被打印到控制台了。

HttpClient 使用

网络爬虫就是用程序帮助我们访问网络上的资源,我们一直以来都是使用 HTTP 协议访问互联网的网页,网络爬虫需要编写程序,同样是需要通过 HTTP 协议访问网页。
这里我们使用 Java 的 HTTP 协议客户端 HttpClient 这个技术,来实现抓取网页数据。

请求

GET请求

再次回顾一下入门程序。

package xyz.zze.crawler.test;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class CrawlerFirst {

    public static void main(String[] args) throws Exception {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet("http://zze.xyz/index.html");
        CloseableHttpResponse response = httpClient.execute(httpGet);
        if(response.getStatusLine().getStatusCode() ==200){
            HttpEntity httpEntity = response.getEntity();
            String content = EntityUtils.toString(httpEntity);
            System.out.println(content);
        }
    }
}

这里就是使用了 HttpClient 发送了一个 GET请求拿到了京东首页的 Html 页。

带参数的 GET 请求

示例:在某博客中通过关键字搜索内容包含"Java"的博客。

package xyz.zze.crawler.test;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class CrawlerFirst {

    public static void main(String[] args) throws Exception {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 创建 URIBuilder 对象
        URIBuilder uriBuilder = new URIBuilder("http://www.laruence.com/");
        // 设置参数,如果有多个参数继续 set 即可
        uriBuilder.setParameter("s", "java");
        HttpGet httpGet = new HttpGet(uriBuilder.build());
        CloseableHttpResponse response = httpClient.execute(httpGet);
        if(response.getStatusLine().getStatusCode() ==200){
            HttpEntity httpEntity = response.getEntity();
            String content = EntityUtils.toString(httpEntity);
            System.out.println(content);
        }
    }
}

POST 请求

要使用 post 方式发送请求只需要将入门程序中的 HttpGet 对象换成 HttpPost 对象即可,如下:

package xyz.zze.crawler.test;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class CrawlerFirst {

    public static void main(String[] args) throws Exception {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost("http://www.zze.xyz");
        CloseableHttpResponse response = httpClient.execute(httpPost);
        if(response.getStatusLine().getStatusCode() ==200){
            HttpEntity httpEntity = response.getEntity();
            String content = EntityUtils.toString(httpEntity);
            System.out.println(content);
        }
    }
}

带参数的 POST 请求

package xyz.zze.crawler.test;

import org.apache.commons.codec.Charsets;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.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;

import java.util.ArrayList;
import java.util.List;

public class CrawlerFirst {

    public static void main(String[] args) throws Exception {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost("http://www.zze.xyz");
        // 构建 List 封装请求参数
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        // 添加请求参数
        params.add(new BasicNameValuePair("testKey", "testValue"));
        // 构建表单 Entity 对象,第一个参数是请求参数,第二个参数是编码
        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(params, Charsets.UTF_8);
        // 将准备好的表单对象设置到 HttpPost 请求对象中
        httpPost.setEntity(formEntity);
        CloseableHttpResponse response = httpClient.execute(httpPost);
        if(response.getStatusLine().getStatusCode() ==200){
            HttpEntity httpEntity = response.getEntity();
            String content = EntityUtils.toString(httpEntity);
            System.out.println(content);
        }
    }
}

连接池

如果每次请求都要创建 HttpClient,会有频繁创建和销毁连接对象造成的性能问题,可以使用连接池来解决这个问题。

package xyz.zze.crawler.test;

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.nio.charset.Charset;

public class HttpClientPoolTest {

    public static void main(String[] args) {
        // 创建连接池管理器
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        // 设置最大连接数
        connectionManager.setMaxTotal(100);
        // 设置每个主机的最大连接数
        connectionManager.setDefaultMaxPerRoute(10);
        // 从连接池管理器中取得连接创建发起请求
        doGet(connectionManager);
        doGet(connectionManager);
    }

    private static void doGet(PoolingHttpClientConnectionManager connectionManager) {
        // 从连接池管理器中取得连接对象
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).build();
        // 后续的使用就和普通连接方式相同了
        HttpGet httpGet = new HttpGet("http://jd.com");

        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpGet);
            if (response.getStatusLine().getStatusCode() == 200){
                String content = EntityUtils.toString(response.getEntity(), Charset.defaultCharset());
                System.out.println(content);
            }
        }catch (IOException ex){
            ex.printStackTrace();
        }finally {
            if(response != null){
                try {
                    response.close();
                }catch (IOException ex){
                    ex.printStackTrace();
                }
            }
            // 不用关闭 HttpClient ,又连接池管理 HttpClient 对象的创建与回收
        }
    }
}

配置请求信息

package xyz.zze.crawler.test;

import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class HttpConfigTest {

    public static void main(String[] args) throws Exception {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet("http://www.zze.xyz");
        // 创建请求配置信息对象
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(1000)          // 创建连接的超时时间,单位毫秒
                .setConnectionRequestTimeout(500)      // 获取连接的最长时间,单位毫秒
                .setSocketTimeout(10 * 1000)              // 传输数据的最长时间,单位毫秒
                .build();
        // 给请求设置配置信息
        httpGet.setConfig(requestConfig);
        CloseableHttpResponse response = httpClient.execute(httpGet);
        if(response.getStatusLine().getStatusCode() ==200){
            HttpEntity httpEntity = response.getEntity();
            String content = EntityUtils.toString(httpEntity);
            System.out.println(content);
        }
    }
}

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.zze.xyz/archives/java-httpclient.html

Buy me a cup of coffee ☕.