使用Java爬虫今日头条武汉疫情统计数据信息

这几天在用手机版的APP头条时会发现,它开放了一个疫情数据的展示页面,作为一个有理想有抱负的,从事数据工作方面的程序员来说,想到了把他的数据拿下来就好了,这样我们自己也可以做一些数据处理的工作,从而进行数据的二次加工和历史留存,这个东西仔细想一下有很大益处的,可以提高对问题的分析能力,对视野的扩充,对头条系的程序员开发页面的思路和相关设计都是可以进行学习的。接下来分析一下我的简易过程。

1、首先通过代理或分享等方式,获取到该页面的URL,这里获取到的URL如下所示:

https://i.snssdk.com/feoffline/hot_list/template/hot_list/forum_tab.html?activeWidget=1

2、然后在浏览器端,查看网页的源代码可以知道这个页面的渲染方式为客户端渲染页面布局,调用服务端提供的数据接口返回JSON数据,再使用开发者工具对该页面的请求进行分析,最终获取到了如下相关的URL信息:

页面布局相关处理JS文件:

https://s3.pstatp.com/toutiao/feoffline/hot_list/resource/hot_list/js/forum_tab.6ed55a07.chunk.js

中国各个省份数据简易API:

https://i.snssdk.com/ncov2019/hospital/district?activeWidget=1&adcode=110000&level=1

包含了各个省份地市区的明细数据和一些统计数据API:

https://i.snssdk.com/forum/home/v1/info/?activeWidget=1&forum_id=1656784762444839

3、使用浏览器的开发者工具,查看布局附近相关的class的样式为:epidemic-brief,如下图所示:

使用Java爬虫今日头条武汉疫情统计数据信息_第1张图片

然后根据这个样式名称,在页面布局及处理的JS文件中,查询这个字符串,可以找到相关布局处理代码如下所示:

核心处理代码1,进行页面的渲染处理:

e.a = function(t) {
    var e = t.updateTime,
    i = t.confirmedCount,
    a = t.curedCount,
    s = t.deadCount,
    o = t.suspectedCount,
    c = t.deadDiff,
    l = t.confirmedDiff,
    h = t.curedDiff,
    p = t.suspectedDiff;
    return r.a.createElement("div", {
        className: "epidemic-brief"
    },
    r.a.createElement("div", {
        className: "epidemic-brief-header"
    },
    r.a.createElement("h2", null, "\\u5168\\u56fd\\u75ab\\u60c5\\u72b6\\u51b5"), r.a.createElement("p", {
        className: "epidemic-brief-label"
    },
    "\\u66f4\\u65b0\\u65f6\\u95f4 ", n()(e, "Y/MM/dd hh:mm"))), r.a.createElement("div", {
        className: "epidemic-brief-body"
    },
    r.a.createElement("div", {
        className: "epidemic-brief-stats"
    },
    r.a.createElement("span", {
        className: "epidemic-brief-stats-num confirmed"
    },
    i || "-"), r.a.createElement("span", {
        className: "epidemic-brief-stats-label"
    },
    "\\u786e\\u8bca\\u4eba\\u6570"), r.a.createElement("div", {
        className: "epidemic-brief-stats-label-small"
    },
    r.a.createElement("span", {
        className: "epidemic-brief-stats-label-small title"
    },
    "\\u8f83\\u6628\\u65e5"), r.a.createElement("span", {
        className: "epidemic-brief-stats-label-small left"
    },
    "+", l || 0))), r.a.createElement("div", {
        className: "epidemic-brief-stats"
    },
    r.a.createElement("span", {
        className: "epidemic-brief-stats-num suspected"
    },
    o || "-"), r.a.createElement("span", {
        className: "epidemic-brief-stats-label"
    },
    "\\u7591\\u4f3c\\u75c5\\u4f8b"), r.a.createElement("div", {
        className: "epidemic-brief-stats-label-small"
    },
    r.a.createElement("span", {
        className: "epidemic-brief-stats-label-small title"
    },
    "\\u8f83\\u6628\\u65e5"), r.a.createElement("span", {
        className: "epidemic-brief-stats-label-small center2"
    },
    "+", p || 0))), r.a.createElement("div", {
        className: "epidemic-brief-stats"
    },
    r.a.createElement("span", {
        className: "epidemic-brief-stats-num dead"
    },
    s || "-"), r.a.createElement("span", {
        className: "epidemic-brief-stats-label"
    },
    "\\u6b7b\\u4ea1\\u4eba\\u6570"), r.a.createElement("div", {
        className: "epidemic-brief-stats-label-small"
    },
    r.a.createElement("span", {
        className: "epidemic-brief-stats-label-small title"
    },
    

核心处理代码2,对返回的数据进行解析与处理:

case 3:
    e = t.sent,
    a = e[0],
    r = e[1],
    a.forum.extra.ncov_image_url = a.forum.extra.ncov_image_url.replace("http://p3.pstatp.com/large/", ""),
    s = JSON.parse(a.forum.extra.ncov_string_list);
    try {
        n = JSON.parse(a.forum.extra.ncov_image_url)
    } catch(d) {
        n = JSON.parse('[{"min":1,"max":9,"color":"rgba(250,243,187,1)"},{"min":10,"max":99,"color":"rgba(246,192,82,1)"},{"min":99,"max":499,"color":"rgba(226,110,28,1)"},{"min":500,"max":999,"color":"rgba(146,55,35,1)"},{"min":1000,"max":null,"color":"rgba(99,37,22,1)"}]')
    }
    o = s.nationwide,
    c = o[0],
    l = o[1],
    console.log("are", s, l, c, c.confirmedNum - l.confirmedNum),
    h = {
        seriesIndex: 0
    },
    [a.forum.extra.gps_city_code, a.forum.extra.cure_city_code, a.gps_city_code, a.cure_city_code].some(function(t) {
        if (t) {
            var e = C(r, "" + t.slice(0, 2));
            return e && (h.name = e.name),
            !!e
        }
    }),
    h.name || (h.name = "\\u6e56\\u5317"),
    p = {
        brief: {
            updateTime: 1e3 * s.updateTime,
            confirmedCount: c.confirmedNum,
            suspectedCount: c.suspectedNum,
            curedCount: c.curesNum,
            deadCount: c.deathsNum,
            confirmedDiff: l ? c.confirmedNum - l.confirmedNum: 0,
            nationwide curedDiff: l ? c.curesNum - l.curesNum: 0,
            deadDiff: l ? c.deathsNum - l.deathsNum: 0,
            suspectedDiff: l ? c.suspectedNum - l.suspectedNum: 0
        },
        map: {
            chinaData: s.provinces.filter(function(t) {
                return t.confirmedNum > 0 || t.suspectedNum > 0
            }).map(function(t) {
                var e = r.find(function(e) {
                    return t.id === String(e.id)
                });
                return e ? {
                    name: e.name,
                    value: t.confirmedNum,
                    confirmedCount: t.confirmedNum,
                    deadCount: t.deathsNum
                }: null
            }).filter(function(t) {
                return !! t
            }),
            ranges: n.map(function(t) {
                return {
                    start: t.min,
                    end: t.max,
                    color: t.color,
                    label: 0 === t.max ? "\\u7591\\u4f3c\\u611f\\u67d3": "undefined" === typeof t.max || null === t.max ? t.min + "\\u4eba\\u4ee5\\u4e0a": t.min + "-" + t.max + "\\u4eba"
                }
            }),
            defaultTipData: h
        },
        

从中找到了几个相关的变量:confirmedCount,curedCount,deadCount,suspectedCount,t.deadDiff,

confirmedDiff,curedDiff,suspectedDiff。并且知道了从某个接口中的返回数据中取出了forum中的extra中的ncov_string_list的nationwide数据,这是一个数组类型的数据,表示了最近几天的统计数据。

不言而喻,这几个变量就是页面的主要的几项指标的数据。然后根据这几个关键字和返回结构,最后确定了如下接口为我们需要的相关上方的汇总数据:

https://i.snssdk.com/forum/home/v1/info/?activeWidget=1&forum_id=1656784762444839。

4、这样Java爬虫需要的基本要素我们都有了,接下来可以简单的使用Jsoup和FastJSON简易的完成爬虫代码:

public class CollectData1 {
	//定义几个常量防止反爬虫
	public static String USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:49.0) Gecko/20100101 Firefox/49.0";
	public static String HOST = "i.snssdk.com";
	public static String REFERER = "https://i.snssdk.com/feoffline/hot_list/template/hot_list/forum_tab.html?activeWidget=1";
	
	public static void main(String[] args) throws IOException {
		//根URL
		String url = "https://i.snssdk.com/forum/home/v1/info/?activeWidget=1&forum_id=1656784762444839";
		String resultBody = Jsoup.connect(url).
				userAgent(USER_AGENT).header("Host", HOST).header("Referer", REFERER).execute().body();
		JSONObject jsonObject = JSON.parseObject(resultBody);
		String ncovStringList = jsonObject.getJSONObject("forum").getJSONObject("extra").getString("ncov_string_list");
		JSONObject ncovListObj = JSON.parseObject(ncovStringList);
		//取出每日的相关汇总数据,可以把这个数据存储到数据库中
		//[{confirmedNum: 9809, curesNum: 183, date: "2020-01-31", deathsNum: 213, suspectedNum: 15238}]
		JSONArray nationwides = ncovListObj.getJSONArray("nationwide");
		//取出当日数据
		JSONObject currentDateData = nationwides.getJSONObject(0);
		//取出昨日数据
		JSONObject lastDayData = nationwides.getJSONObject(1);
		System.out.println(currentDateData);
		System.out.println(lastDayData);
		Map rData = new HashMap();
		//获取确诊人数
		rData.put("confirmedCount",currentDateData.getIntValue("confirmedNum"));
		//获取疑似病例
		rData.put("suspectedNum",currentDateData.getIntValue("suspectedNum"));
		//获取治愈人数
		rData.put("curesNum",currentDateData.getIntValue("curesNum"));
		//获取死亡人数
		rData.put("deathsNum",currentDateData.getIntValue("deathsNum"));
		//获取确诊人数比上日
		rData.put("confirmedDiff",currentDateData.getIntValue("confirmedNum") - lastDayData.getIntValue("confirmedNum"));
		//获取疑似病例比上日
		rData.put("suspectedDiff",currentDateData.getIntValue("suspectedNum") - lastDayData.getIntValue("suspectedNum"));
		//获取治愈人数比上日
		rData.put("curedDiff",currentDateData.getIntValue("curesNum") - lastDayData.getIntValue("curesNum") );
		//获取死亡人数比上日
		rData.put("deadDiff",currentDateData.getIntValue("deathsNum") - lastDayData.getIntValue("deathsNum"));
		System.out.println(JSON.toJSONString(rData));
	}
	

}

以上只是一个简单的代码,使用Java获取到了相关的数据信息,从这个接口中,可以获取到头条页面上方的8项基本数据,和各个省市的明细数据;通过另外的一个接口,可以获取到每个省市的地图数据。

数据获取到了以后,每个人都可以根据自己的想法做一些基本的数据分析和展示效果等,也可以把每日的数据存储到数据库中。

你可能感兴趣的:(Java,Web,java)