Java爬虫 爬取bing必应每日一图背景图下载到本地(HttpClient+Jsoup+Jackson)

bing每日一图适合作桌面背景,也经常作为我们网站某个页面的背景,效果非常好,下面我们来介绍Java如何爬取。

这次爬取介绍两个方法
方法一,爬取目标网页,通过网页元素得到图片路径
方法二,爬取图片url地址的接口,通过返回的json数据爬取图片


方法一:

  1. 分析: 首先我们打开bing首页 https://www.bing.com/?mkt=zh-CN,按照正常的思路,我们右键检查,在页面上寻找目标图片,然后我们可以找到一个看起来很像背景图的:在这里插入图片描述
    我们复制出来/th?id=OHR.MatiSiTemple_ZH-CN1153907273_UHD.jpg&rf=LaDigue_UHD.jpg&pid=hp&w=1920&h=1080&rs=1&c=4 /代表使用的是相对路径,我们只需要拼接上网站根路径(https://www.bing.com)即可, 我们在浏览器输入,发现,这个就是我们想要的图片地址了。
        但是,浏览器最终解析的可能和我们看到的不一样,因为存在很多js请求,所以我们打开network,清空,输入bing主页,查看请求的返回值。
    在这里插入图片描述
    如图,果然和我们在页面上看到的不一样,我们再尝试去寻找返回的数据中是否有我们想要的。(我们在页面中已经找到了图片的url,所以我们在返回值搜索url即可),我们就也在返回值中找到了图片的url,我们找到了两处,一个在一个id为bgImgProgLoad的div中,另一个在id为bgLink的link中,我们使用哪个都可以
    在这里插入图片描述
    在这里插入图片描述
    分析至此,我们就已经捋清了要爬取的步骤了,首先发送Get请求访问bing首页,再使用Jsoup解析返回的页面,获取到id为bgLink的元素的url,然后再次发送Get请求图片,将图片下载即可。

  2. 编码 (pom文件我放到了最后)

因为有两种方法,所以我代码抽取到一个工具类中

  • 工具类 HttpUtils

代码中打了部分注释,如果对哪部分觉得不清楚可以查看上一篇爬取豆瓣的博客,注释非常详细

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.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;

public class HttpUtils {
	// 配置HttpClients连接池管理器,可以自动释放连接池资源
    static PoolingHttpClientConnectionManager manager;
    static {
    	// 为了方便我直接丢到静态代码块中初始化
        manager = new PoolingHttpClientConnectionManager();
        manager.setMaxTotal(100);
        manager.setDefaultMaxPerRoute(10);
    }


    public static String doGetHtml(String url) {
    	// 创建httpclient对象用于发起请求
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(manager).build();
        // 创建get请求,指定uri
        HttpGet httpGet = new HttpGet(url);
        // 设置连接的一些参数,可以不设置
        httpGet.setConfig(getConfig());
        // 设置user-agent来欺骗网站是浏览器访问
        httpGet.setHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36");

        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpGet);
            if (response.getStatusLine().getStatusCode() == 200) {
            	// 如果返回状态码为200代表成功,则将响应数据返回
                return EntityUtils.toString(response.getEntity(), "utf8");
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                try {
                	// 这里只需要释放response,httpclient由连接池管理器释放
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return "";
    }

	/**
	* 下载图片的方法基本与get请求类似
	* 主要区别在我们不返回响应字符串,而是将响应数据直接通过字节流写入文件
	*/
    public static void doGetImage(String url) {
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(manager).build();
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36");

        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpGet);
            if (response.getStatusLine().getStatusCode() == 200) {
            	// 这里格式化下时间作为文件名
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss-S");
                String dateStr = simpleDateFormat.format(new Date());
                // 创建字节缓冲输出流,大家要先创建F:/img/bing文件夹,我这里没有进行判断
                BufferedOutputStream bs = new BufferedOutputStream(new FileOutputStream("F:\\img\\bing\\" + dateStr + ".png"));
                // 响应数据直接写入输出流中
                response.getEntity().writeTo(bs);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                try {
                    response.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    private static RequestConfig getConfig() {
        RequestConfig config = RequestConfig.custom().setConnectionRequestTimeout(2000)
                .setConnectTimeout(3000)
                .setSocketTimeout(10 * 1000)
                .build();
        return config;
    }

}

  • 测试
    我们创建个Main进行测试下
import cn.jayjia.util.HttpUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
public class Main {

    public static void main(String[] args) {
        // 方法1 抓取页面数据
        String html = HttpUtils.doGetHtml("https://www.bing.com/?mkt=zh-CN");
        Document document = Jsoup.parse(html);
        Elements e = document.select("#bgLink");
        System.out.println(e.attr("href"));
        HttpUtils.doGetImage("https://www.bing.com" + e.attr("href"));
    }
}

执行就可以下载成功了。



方法二

  1. 分析
    我们除了可以从网页拿到数据,那么能不能直接从接口拿到返回数据呢?这两种思路我们在爬虫的时候都应该考虑一下,因此,我们F12,打开network重新刷新网页,点击All观察所有请求,可以找到这样一条看起来很像的请求在这里插入图片描述
    我们点击进去查看reponse
    在这里插入图片描述
    发现这和上一个获取到的url是一样的,看来我们找到了想要的接口,请求这个地址返回的是JSON数据,所以我们可以使用JackSon进行解析,获取到url就能进行下载了。

  2. 编码

我们可以使用工具类中的doGetHtml获取返回的JSON数据,这就是封装工具类的好处了,解析完JSON数据后,再调用doGetImage方法下载即可,所以我们只需要进行解析JSON,那么就直接写测试吧

  1. 测试
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Main {

    public static void main(String[] args) {
        // 方法2 抓取接口数据 https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&nc=1603114218081&pid=hp&mkt=zh-CN
        String json = HttpUtils.doGetHtml("https://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&nc=1603114218081&pid=hp&mkt=zh-CN");
        // 这里解析JSON我用的Jackson,大家也可以使用别的如GSON等
        ObjectMapper mapper = new ObjectMapper();
        try {
            JsonNode jsonNode = mapper.readTree(json);
            String url  = jsonNode.get("images").get(0).get("url").asText();
            System.out.println(url);
            HttpUtils.doGetImage("http://www.bing.com" + url);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

    }
}

测试就可以下载成功了。

  1. POM文件依赖
    <dependencies>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.7</version>
        </dependency>

        <dependency>
            <groupId>org.jsoup</groupId>
            <artifactId>jsoup</artifactId>
            <version>1.10.3</version>
        </dependency>
        <!--解析JSON-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.10.2</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.2</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.10.2</version>
        </dependency>
    </dependencies>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值