老师手上有一个项目,是某展馆的一个数据大屏。

这个项目之前是某大四学生开发的,现在他去实习了,系统还有一些东西要改,这个系统的开发和维护现在到我手上了 ¥ヾ(≧▽≦*)o¥

接手代码

这个数据大屏项目使用React写的,刚好之前把React学明白了,项目都能看明白。

整体看过去这个项目结构写的非常的好,代码非常整洁。

到此为止我以为开发它的人是个很厉害的人。

直到我看到某些地方的代码···

formatter: function (data) {
    if (data.name == "黑龙江省") {
        return (
            "                 &nbsp &nbsp   &nbsp &nbsp &nbsp" +
            "黑龙江省" +
            "<br>" +
            "&nbsp;&nbsp;" +
            data.data.value[0].name +
            "----->" +
            "丽水市" +
            "&nbsp;&nbsp;&nbsp;" +
            data.data.value[0].value +
            "人&nbsp;&nbsp;" +
            "<br>" +
            "&nbsp;&nbsp;" +
            data.data.value[1].name +
            "----->" +
            "&nbsp;&nbsp;" +
            "丽水市" +
            "&nbsp;&nbsp;&nbsp;" +
            data.data.value[1].value +
            "人&nbsp;&nbsp;"
        );
    }
    if (data.name == "河北省") {
        return (
            "&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp;&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp" +
            "河北省" +
            "<br>" +
            "&nbsp;&nbsp;" +
            data.data.value[0].name +
            "----->" +
            "丽水市" +
            "&nbsp;&nbsp;&nbsp;" +
            data.data.value[0].value +
            "人&nbsp;&nbsp;" +
            "<br>" +
            "&nbsp;&nbsp;" +
            data.data.value[1].name +
            "----->" +
            "&nbsp;&nbsp;" +
            "丽水市" +
            "&nbsp;&nbsp;&nbsp;" +
            data.data.value[1].value +
            "人&nbsp;&nbsp;"
        );
    }
    if (data.name == "北京市") {
        return (
            "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp;&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp" +
            "北京市" +
            "<br>" +
            "&nbsp;&nbsp;" +
            data.data.value[0].name +
            "----->" +
            "丽水市" +
            "&nbsp;&nbsp;&nbsp;" +
            data.data.value[0].value +
            "人&nbsp;&nbsp;" +
            "<br>" +
            "&nbsp;&nbsp;" +
            data.data.value[1].name +
            "----->" +
            "&nbsp;&nbsp;" +
            "丽水市" +
            "&nbsp;&nbsp;&nbsp;" +
            data.data.value[1].value +
            "人&nbsp;&nbsp;"
        );
    }
    // ································· //
    if (data.name == "辽宁省") {
        return (
            "&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp;&nbsp;&nbsp&nbsp;&nbsp&nbsp;&nbsp" +
            "辽宁省" +
            "<br>" +
            "&nbsp;&nbsp;" +
            data.data.value[0].name +
            "----->" +
            "丽水市" +
            "&nbsp;&nbsp;&nbsp;" +
            data.data.value[0].value +
            "人&nbsp;&nbsp;"
        );
    }
}

这代码写的和其他地方写的明显不是一个人写的。

问了一下老师,哦哦——套的模板···

上一个写这个代码的人是一个不会用循环的人o_o ....

完成需求

这个页面接手后是由很多问题的,为了我的身心健康,首先把前人写的东西重构了,接着是老师提需求···

  • 让这个数据大屏能够响应式布局,能够支持Pad端查看
  • 里面的一些新闻数据旧了,去爬新的
  • 用知识图谱展示数据
  • 点击新闻时要在页内浏览,不要打开新标签页
  • ······

其中爬新闻这一块最麻烦也最有意思

爬新闻

之前爬的那些信息是用Python爬的(他直接用了python的标志http库o_o ....),相当一部分新闻的链接都是临时的搜索跳转链接,这一部分全部都失效了。

需要爬取的新闻的关键词是固定的,而很多网站里面都有搜索功能,于是我使用Golang写了个简单程序去逐页搜索爬取,但是这个方法在请求多了之后会被风控,而且也并不是每个网站的搜索接口都那么好调用,这一个方法在爬了一些网站之后,老师觉得爬的太少,于是要换新的方法···

于是我想到,可以利用baidu啦、bing啦、google啦这样的搜索引擎,这样不用针对每一个网站写爬虫,只要搜索引擎收录的就可以啦。

但实际编写程序才发现他们反爬虫做的更离谱 ( ̄▽ ̄)"

撇了一眼浏览器上的油猴插件···我明白了!

// ==UserScript==
// @name        必应爬取
// @namespace   Violentmonkey Scripts
// @match       https://cn.bing.com/search*
// @grant       none
// @version     1.0
// @author      -
// @description 2024/3/18 20:53:51
// ==/UserScript==
window.onload = ()=>{
  function downloadFileData(data, fileName) {
      blob = new Blob(data);
      let blobUrl = window.URL.createObjectURL(blob);
      let link = document.createElement('a');
      link.download = fileName;
      link.style.display = 'none';
      link.href = blobUrl;
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
  }
  let rearr = []
  document.querySelectorAll(".b_algo").forEach(e=>{
    let d= {
      url:e.querySelector(".tilk")?.href,
      site:e.querySelector(".tptt")?.innerText,
      title:e.querySelector("h2")?.innerText,
    }
    rearr.push(d)

  })
  downloadFileData([JSON.stringify(rearr)],document.title + document.querySelector(".sb_pagS ").innerHTML)
  // 下一页
   document.querySelector(".sb_pagS ").parentElement.nextSibling.childNodes[0].click()
}

这段脚本会在必应搜索时将当前页面的搜索结果整理、发起下载请求然后跳转下一页···

像学习强国、潮新闻这些不允许搜索引擎收录,我给他们单独写了类似于上面的脚本。

这些网站在其他地方做了反爬虫,所以他们似乎对浏览器很信任,无论开多少个标签页同时爬似乎也不会有什么问题。

部署

需求完成的差不多了,趁着没人,老师带我去部署大屏,第一次去,出了以下问题:

  • 大屏里面的知识图谱似乎不支持Windows触摸屏
  • 为了开机自启用electron套了层壳,这层壳完全无法响应触摸事件
  • 全屏状态下需要一个关闭按钮

知识图谱使用echarts画的,echarts似乎默认Windows不会用触屏,所以不处理触摸事件,搜了一下,需要添加这样的代码:

// 强制触摸屏支持
import zRenderEnv from 'zrender/lib/core/env';
zRenderEnv.touchEventsSupported = true;
zRenderEnv.pointerEventsSupported = false;

这是一种办法,还有一种办法是改浏览器UA,让echarts以为是安卓端。

我呢,两个方法都采用了,页面内添加了代码,让echarts能够任何情况下支持Windows触摸屏,electron套壳改了浏览器UA,让echarts以外的东西也能正常使用。但似乎echarts以外就没有东西了

关闭按钮就在electron的preload脚本里面添加。

至于electron不响应触摸事件,搜了一下,似乎electron官方到现在还没解决,社区内有一些办法,这个问题我打算下次再去部署的时候修···

第二次去部署,一切都按预期进行,没有任何问题,唯独不响应触摸事件这个问题没复现出来···


我能想到的,最大的成功就是无愧于自己的心。