欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

简单JAVA币世界爬虫通知

程序员文章站 2022-03-24 20:11:39
...

最近玩数字货币,老想去刷新‘币世界’,受不了了,就准备自己写一个简单的爬虫。

 

构想是这样的:本地运行的简单爬虫程序去爬币世界的信息,然后通知给我,最好能显示内容。

 

OK,写个桌面应用?用Swing?用AWT?感觉麻烦,不想去复习JSE的东西。

 

突然想到web端好像也可以通知。(下图为效果图)

 


简单JAVA币世界爬虫通知
            
    
    博客分类: JAVA  

 

Ok,只需要写一个简单的web应用就行,开通H5的notification。

 

准备工作及必要技能

1.java web ---使用spring boot 开箱即用,非常简单。

2.简单的爬虫使用jsoup。

3.前端使用了angularJs。(socket and H5 notification)

 

Step 1

先去看看“币世界” http://www.bishijie.com/kuaixun/ (显然我只需要kuaixun部分)

 

想法: 我可以直接开始扒,但是显得非常的不美丽,每次扒取还要和上一次的数据对比。

 

想法: “币世界” 上面有一个东西是未读信息条目数,感觉这东西应该会对我的程序有所帮助。

 

开工:

1.打开浏览器中的币世界的network,可以发现这里有轮询的出现,看URL就知道,这是一个获取

未读消息数目的API。

 

www.bishijie.com/api/news/unreadNum?timestamp=1525350000 

 

经过简单的推理就知道后面得是当前的秒时间戳,OK,币世界自己也是通过时间戳为参数轮询的,我们来模拟URL结果。如下图

 


简单JAVA币世界爬虫通知
            
    
    博客分类: JAVA  
 OK,已经有思路了,我们按照他官网的思路来做,避免过多的拉内容,对他对我们都有好处。

 

2.贴上获取unread num的核心代码,非常简单。(完成代码在后面会附上的githup上)

 

 

package com.bishijie.alert.service.impl;

import com.bishijie.alert.asset.CommonUrl;
import com.bishijie.alert.bean.Timestamp;
import com.bishijie.alert.service.IUnderReadNum;
import com.bishijie.alert.util.HttpUtil;
import com.bishijie.alert.util.JSONUtil;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.HashMap;


@Service
public class UnderReadNumImpl implements IUnderReadNum {

    @Resource
    Timestamp timestamp;


    @Override
    public int getUnderReadNum(long timestamp) {
        String req = HttpUtil.get(MessageFormat.format(CommonUrl.underReadNum, timestamp + ""));
        return this.getNumFromMap(this.jsonToMap(req));
    }

    @Override
    public int getUnderReadNum() {
        String req = HttpUtil.get(MessageFormat.format(CommonUrl.underReadNum, this.timestamp.getTimestamp() + ""));
        return this.getNumFromMap(this.jsonToMap(req));
    }


    /////////////////////////////////////////////////////////// private ///////////////////////////////////////////////////////////

    private HashMap jsonToMap(String req) {
        HashMap<String, Object> reqMap = new HashMap<>();
        try {
            reqMap =  JSONUtil.toObject(req, HashMap.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return reqMap;

    }

    private int getNumFromMap(HashMap reqMap){
        int tempNum = 0;
        if(reqMap.get("data")!=null){
            HashMap<String,Integer> dataMap= (HashMap<String, Integer>) reqMap.get("data");
            tempNum = dataMap.get("num");
        }
        return tempNum;
    }

}

 

 

3.OK 拿到了未读信息数目,不为0的时候,当然就要去真正的趴币世界了。(tab1 记得加时间戳,避免302)

 

下面贴上获取消息的核心代码片段。(完成代码在后面会附上的githup上)

 

 

package com.bishijie.alert.service.impl;

import com.bishijie.alert.asset.CommonUrl;
import com.bishijie.alert.bean.Timestamp;
import com.bishijie.alert.bean.UnderReadMessage;
import com.bishijie.alert.service.IUnderReadMessage;
import com.bishijie.alert.util.HttpUtil;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class UnderReadMessageImpl implements IUnderReadMessage{

    @Resource
    Timestamp timestamp;

    @Override
    public List<UnderReadMessage> getUnderReadMessage(int underReadNum) {
        this.timestamp.initTimestamp();//reset timestamp
        List<UnderReadMessage> mesList = new ArrayList<>();
        String req = HttpUtil.get(CommonUrl.coinWorld+"/?time="+new Date().getTime());
        Document doc = Jsoup.parse(req);
        Elements lis = doc.select("li.lh32");
        for(int i = 0;i<underReadNum;i++){
            mesList.add(new UnderReadMessage(
                    lis.get(i).select("h2").first().toString().replace("<h2>","").replace("</h2>","").replace("<h2 style=\"color:#ff0000;\">",""),
                    lis.get(i).select("div").first().toString().replace("<div>","").replace("</div>","")));
        }
        return mesList;
    }

    @Override
    public String getUnderReadMessagePage() {
        String req = HttpUtil.get(CommonUrl.coinWorld+"/?time="+new Date().getTime());
        return req;
    }


}

 

 

4.OK,数据都有了,我的构想是基于socket给前端推送然后前端通过H5通知给用户弹窗。完美!

具体逻辑是: 0.5秒的定时查询未读消息数目,如果不为0,这去爬网站信息,获取前未读消息数目的信息,通过socket给前端。(其中send无用,纯测试哈)

 

核心代码片段如下:

 

 

package com.bishijie.alert.web;


import com.bishijie.alert.bean.ServerMesList;
import com.bishijie.alert.bean.SocketMessage;
import com.bishijie.alert.service.IUnderReadMessage;
import com.bishijie.alert.service.IUnderReadNum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

@EnableScheduling
@Controller
public class SocketController {

    @Autowired
    private SimpMessagingTemplate messagingTemplate;

    @Resource
    IUnderReadNum iUnderReadNum;

    @Resource
    IUnderReadMessage iUnderReadMessage;

    @Resource
    ServerMesList mesList;


    @Deprecated
	@MessageMapping("/send")
	@SendTo("/topic/send")
	public SocketMessage send(SocketMessage message) throws Exception {
		System.out.println(message.date);
		DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		message.date = df.format(new Date());
		return message;
	}

    @Scheduled(fixedRate = 500)
    @Deprecated //no send socket to customer
    public void sendUnderReadNum() throws Exception {
        int num = iUnderReadNum.getUnderReadNum();
        if (num != 0) {
            mesList.setListMes(iUnderReadMessage.getUnderReadMessage(num));
            sendUnderReadMessage();
            messagingTemplate.convertAndSend("/coinWorld/underReadNum", num);
            System.out.println(new Date()+"####Send Msg####The Num is "+num);
        }
    }

    //core method
    private void sendUnderReadMessage() {
        messagingTemplate.convertAndSend("/coinWorld/underReadMessage", mesList);
    }





}

 

 

5.最后附上前端代码,非常简单。

 

 

<body ng-app="app" ng-controller="MainController">
<div ng-repeat="item in listMes">
    <h3>{{item.title}}</h3>
    <h4>{{item.body}}</h4>
    <br/>
</div>

</body>

<script src="https://cdn.bootcss.com/angular.js/1.5.6/angular.min.js"></script>
<script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script>
<script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
<script type="text/javascript">


    var stompClient = null;

    var app = angular.module('app', []);
    app.controller('MainController', function ($rootScope, $scope, $http) {
        // ********************************************* data *********************************************
        $scope.listMes = [];
        $scope.historyMes = [];
        // ********************************************* method *********************************************

        $scope.connect = function () {
            var socket = new SockJS('/my-websocket');
            stompClient = Stomp.over(socket);
            stompClient.connect({}, function (frame) {
                stompClient.subscribe('/coinWorld/underReadMessage', function (req) {
                    $scope.listMes = JSON.parse(req.body).listMes ;
                    console.log($scope.listMes);
                    for(var i=0;i<$scope.listMes.length;i++){
                        $scope.notificationSend($scope.listMes[i].title,
                            $scope.listMes[i].body,'/symbol.png',null);
                    }
                    $scope.$apply();
                });
            });
        };
        $scope.disconnect = function () {
            if (stompClient != null) {
                stompClient.disconnect();
            }
            $scope.data.connected = false;
        }
        $scope.send = function () {
            stompClient.send("/app/send", {}, JSON.stringify({
                'message': $scope.data.message
            }));
        }
        $scope.valid = function () {
            if (!window.Notification) {
                alert("Your browser not support Notification!")
            }
        }
        $scope.notification = function (title, msg, imagePath, onclick) {
            if (Notification.permission == "granted") {
                var notification = new Notification(title, {
                    body: msg,
                    icon: imagePath
                });
                notification.onclick = onclick;
                return notification;
            }
        }
        $scope.notificationSend = function (title, msg, imagePath, onclick) {
            var notification = $scope.notification(title, msg, imagePath, function () {
                notification.close();
                onclick();
            });
        }

        // ********************************************* init *********************************************
        $scope.connect();
        $scope.valid();

    });


</script>

 前端无任何显示,启动该应用后,只需打开网页输入localhost:12345 即可达到通知效果。

 

 

当有消息来得时候,就会弹窗了哦

 


简单JAVA币世界爬虫通知
            
    
    博客分类: JAVA  
 

 

轻松愉快。

 

附上githup地址:https://github.com/liaoke0123/digitalCashTool

 

可直接运行的哦。

 

愿比特币2年后20万美元。

 

 

 

 

 

 

 

  • 简单JAVA币世界爬虫通知
            
    
    博客分类: JAVA  
  • 大小: 28.2 KB
  • 简单JAVA币世界爬虫通知
            
    
    博客分类: JAVA  
  • 大小: 26.5 KB