# 编程有意思

**URL:** https://meta.appinn.net/t/topic/30149
**Category:** 稻米鼠的频道
**Created:** [2022 年2 月 20 日 07:01 UTC](https://meta.appinn.net/t/topic/30149 "2022-02-20T07:01:47Z")
**Posts on this page:** 20
**Page:** 1

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 20 日 07:01 UTC](https://meta.appinn.net/t/topic/30149/1 "2022-02-20T07:01:47Z")

</div>

有些东西实现起来真的很简单，却可以带来蛮大的体验提升。

编程有什么用？能让自己感到开心吧。如果过去的我遇到现在的我，那么会是怎样崇拜的目光呢……虽然现在的自己依然不过是一只三脚猫（鼠）。

慢慢的记录一些有趣的东西，如果明白原理，都是很简单，很基础的，而且要写的代码也很少。

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 20 日 07:27 UTC](https://meta.appinn.net/t/topic/30149/2 "2022-02-20T07:27:21Z")

</div>

## 通知聚合服务

我把各个平台的通知汇聚在一起，显示在 Kindle 上，然后摆在桌面。

但这个东西不适合分享出来，这有很多原因，这里不解释了。但是自己书写一个也挺简单的，只不过两个知识点：

- 前端 JS 不方便跨域获取数据，所以我们需要一个服务器来请求数据
- 服务器就是构造一个 get 方法（多数时候都是 get）而已

用 Node.js 引入 http（内置模块，无需额外安装），

```javascript
const http = require('http');

http.createServer(function (request, response) {
    response.writeHead(200, {'Content-Type': 'text/plain'});
    response.write('要输出的内容')
    response.end();
}).listen(8080);

console.log('Server running at http://127.0.0.1:8080/');

```

构造请求也用 http 这个模块，不过有些请求需要带上 cookie。也可以使用 superagent，格式上可能简单点。

```javascript
const req = http.request({
  method: 'GET',
  host: 'https://website.com',
  port: 80,
  path: '/api',
  headers: {
    Cookie: ['a=111', 'b=222']
  }
}, res => {
  res.on('data', data => console.log(data.toString()) );
});
req.on('error', function (e) { 
  console.log('problem with request: ' + e.message); 
});
req.end();

```

然后，然后就把两者缝合一下就行了，展示页面随便写写就好，反正服务器是自己的，展示页面疯狂轮询自己的后端没所谓啦，如果设备支持 websocket 的话可以不轮询（Kindle 似乎不支持）。

服务器这边请求别人的数据就克制点，五分钟十分钟的查询一次就好。

---

<div class="post-metadata">

### 作者： ![Xclo](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/xclo/32/15090_2.png) [@Xclo](https://meta.appinn.net/u/Xclo)
#### 发布日期： [2022 年2 月 20 日 07:33 UTC](https://meta.appinn.net/t/topic/30149/3 "2022-02-20T07:33:55Z")

</div>

### 如何学习编程

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 20 日 07:36 UTC](https://meta.appinn.net/t/topic/30149/4 "2022-02-20T07:36:36Z")

</div>

## 私人微博

有时候自己絮絮叨叨的，尤其是写代码的时候，就是忍不住吐槽，冒出什么感想又想找地方说说。但是这些内容发在什么平台也不太合适，但是记录一下以后可能还有点什么用。或者说想到什么事情就想赶紧记录一下之类的场景吧。

就开个服务器，接受请求，把接收的数据写入文本就好了。上面让间的 http 服务里，request 里面有请求信息，拿到 query 里面的参数，然后对文档进行追加就行了。我是一个月一个文档，然后每条前面标记一下时间。

然后可以写一个小书签来提交数据，或者我用 utools 的 网页快开插件 做了个自定义。

当然这只是最基本的实现，不过确实可以满足我的需求。比如多行文本，空格啥的就没特别支持。

我做了个展示界面，每次请求都会显示出所有的已有内容，也就读取文件做个简单的查找替换后显示出来。

然后页面顶端加了个表单，get 请求嘛，学前端的但凡学个十来节课都会写。现在我碎嘴子的可开心了。

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 20 日 07:44 UTC](https://meta.appinn.net/t/topic/30149/5 "2022-02-20T07:44:43Z")

</div>

## 展开全文

学一下 CSS 选择器，然后：

```javascript
document.body.querySelector(选择器).click()

```

找到那个展开按钮，然后点击一下。然后的问题就是搜集所有展开按钮的选择器了。

* * *

但上面的方法有个缺陷，如果在点击事件上绑定了其他操作，也会被一同触发，虽然这种情况不多见。

那就把所有限制了高度的元素取消高度限制，反正就是把所有折叠样式逆向操作一下，主要还是折腾选择器和设置样式。

当然还有更复杂的情况，但这些已经可以覆盖百分之八九十了，自用问题不大。发布出来的话……就会有一些主要访问剩余百分之一二十网站的用户说根本不管用，2333

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 20 日 07:45 UTC](https://meta.appinn.net/t/topic/30149/6 "2022-02-20T07:45:21Z")

</div>

> [@Xclo](#):
>
> 如何学习编程

这不就是在讲么……（其实翻翻论坛，我写了好多乱七八糟的

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 20 日 07:48 UTC](https://meta.appinn.net/t/topic/30149/7 "2022-02-20T07:48:12Z")

</div>

## 复制不能复制的内容

网页中右键——检查，在代码里选中代码块元素，但凡认真看两眼都能选对，一般那个元素叫 code（谜底写在谜面上

切换到控制台（Console），输入 `$0.innerText`，回车，好了，内容被输出，复制吧。

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 20 日 07:52 UTC](https://meta.appinn.net/t/topic/30149/8 "2022-02-20T07:52:44Z")

</div>

## I’m Rich

网页都是可以修改的，但是修改以后只是本地可见，刷新就没了，也不会影响到其他人。

**上面这句大差不差，但你不真的理解最好别玩，真的有风险！！！**

检查元素看代码里面，双击一下就可以修改代码里的文字，什么粉丝数，账户余额随便改（改了也没啥用，就是截图炫耀下。

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 20 日 08:05 UTC](https://meta.appinn.net/t/topic/30149/9 "2022-02-20T08:05:47Z")

</div>

## 所有链接地址

别问我有啥用

```auto
var arr = []
document.body.querySelectorAll('a').forEach(el=>arr.push(el.href))
console.log(arr.join('\n'))

```

真的是所有链接，需要更精准的选择得学学选择器，虽然也不难，但显然这里就不会去展开了。

获取页面中其他东西的方法也类似，比如所有帖子的标题，所有图片地址……剩下自己发挥想象力。

第二行的方法可以嵌套，就是一层套一层的套娃，就可以玩出更精准的数据获取，比如获取并整理页面中 n 个表格的内容。

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 20 日 08:10 UTC](https://meta.appinn.net/t/topic/30149/10 "2022-02-20T08:10:42Z")

</div>

## 有事儿您叫我

接 [编程有意思 - #2，来自 dms](https://meta.appinn.net/t/topic/30149/2) 这里。获取数据以后根据情况再构造一个 get 请求，利用 [Server酱](https://sct.ftqq.com/) 或者 [pushplus](https://www.pushplus.plus/) 这类服务，就可以轻松的顺便给自己发条微信，提醒自己有数据更新。

就这么一两个方法反复倒腾就挺好玩的了。

---

<div class="post-metadata">

### 作者： ![jerrylus](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/jerrylus/32/14901_2.png) [@jerrylus](https://meta.appinn.net/u/jerrylus)
#### 发布日期： [2022 年2 月 20 日 09:19 UTC](https://meta.appinn.net/t/topic/30149/11 "2022-02-20T09:19:45Z")

</div>

不太确定是否相关，不过有的时候知道一些编程相关的小知识，还是很有用的。最近遇到了一个需求，需要把一些数据从一个闭源工具里导出来，然而这个工具本身只提供了自家的云同步，并没有任何导出到本地的功能。想着毕竟不是一个特别复杂的工具，数据存储大概率用的是 SQLite，于是试着在安装目录和用户目录下找了找 `.db` 文件，果不其然找到了。再用 [DB Browser for SQLite](https://sqlitebrowser.org/) 打开，很方便地就把数据迁移出来了。

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 20 日 09:37 UTC](https://meta.appinn.net/t/topic/30149/12 "2022-02-20T09:37:03Z")

</div>

> [@jerrylus](#):
>
> 不过有的时候知道一些编程相关的小知识，还是很有用的

我一直的观点是：不一定要一个多大的目标，学一句用一句，都是有价值的。而且就算啥都没学会，对思维方式带来的影响也是很有意义的。

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 20 日 10:45 UTC](https://meta.appinn.net/t/topic/30149/13 "2022-02-20T10:45:25Z")

</div>

## 所有链接在新窗口打开

就是找出所有链接，改一下 `target` 属性。

```auto
document.body.querySelectorAll('a').forEach(el=>el.setAttribute('target', '_blank'))

```

挺长的，不追求自己会写，但是按单词读也能理解大概意思：

- `document` 文档，就是当前这个网页
- `body` 网页的身体
- `querySelectorAll` 查询所有选择器（选择器在小括号里）
- `forEach` 对他们每一个做后面小括号里的操作
- `el` 被用来代表其中的每一个元素
- `el.setAttribute` 对元素设置属性

就这。

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 21 日 00:59 UTC](https://meta.appinn.net/t/topic/30149/15 "2022-02-21T00:59:03Z")

</div>

## 奥运金牌榜

接 [编程有意思 - #2，来自 dms](https://meta.appinn.net/t/topic/30149/2) 这里。

先找一个奖牌榜的网站，查看网络数据，随便翻翻大概就能找到个 json，里面是所有国家奖牌数据，然后就是 get 这个 json。

JSON 是种文件格式，反正读取这个文件内容，用 `JSON.parse(文件内容)` 处理一下就得到了一个对象或者数组，有了数据自己想办法展示出来就行了。

不过，冬奥会闭幕了，但是这个方法可以应用在很多场景上，比如疫情数据啥的

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 21 日 01:38 UTC](https://meta.appinn.net/t/topic/30149/16 "2022-02-21T01:38:10Z")

</div>

## 回帖草稿

不是说这个论坛的，这个要更复杂。咱们说小众主站的，评论了没发，关了标签再打开，写的内容还在，这样万一遇到个崩溃啊，手残啊，不至于自己崩溃了。

先说原理，先是选准表单，然后对表单里的元素按 `name`（没有 `name` 就按 `id`，更出乎意料的情况不讨论）挨个取值，存一个对象，然后把这个对象转换为字符串，存到浏览器的存储里，每次打开页面就看一下有没有已经存好的数据，有就再读取回来。

```auto
// 数据存这里
const data = {}
// 假设就一个表单
const form = document.body.querySelector('form')
// 找出里面所有的输入元素
form.querySelectorAll('input, textarea').forEach(el=>{
  // 有 name 属性才操作
  if(el.name){
    // 添加一个监听器，虽然道理上是发生改变
    // 但是 onchange 反应迟钝，所以用按键事件
    // 道理上再加一些判断性能更好，这里简化
    el.addEventListener('keypress', ()=>{
      // 把值赋给 data 里面对应的属性，就放在对应的位置嘛
      data[el.name] = el.value
      // 把 data 写入存储
      window.localStorage.setItem('formData', JSON.stringify(data))
    })
  }
})

```

实际就几行代码啦，还差一个读取恢复功能：

```auto
// 读取存储的数据
const storeData = window.localStorage.getItem('formData')
// 有存储的数据就用存储的数据，否则新建一个对象
const data = storeData ? JSON.parse(storeData) : {}
// 找出里面所有的输入元素
form.querySelectorAll('input, textarea').forEach(el=>{
  // 有 name 属性才操作
  if(el.name){
    // 恢复存储的内容，这里不是特别严谨，但基本可用
    el.value = data[el.name]
  }
})

```

好长的内容啊，可那是因为我写了好些注释吧，实际上也没几行。上下两段的循环逻辑完全一致。知识点只有三个：

- 读写 `localStorage`
- JSON 的两个方法
- 事件监听器

* * *

包装成油猴子应用在所有页面，就不怕填完的内容丢失了。（实际情况比理想中的复杂，上面只是最简单的实现，所以放在所有场景中应用不够严谨，可能遇到各种意外……但，这里不展开了

---

<div class="post-metadata">

### 作者： ![Xclo](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/xclo/32/15090_2.png) [@Xclo](https://meta.appinn.net/u/Xclo)
#### 发布日期： [2022 年2 月 21 日 06:24 UTC](https://meta.appinn.net/t/topic/30149/17 "2022-02-21T06:24:56Z")

</div>

最重要的是基础，我曾尝试过自学python3，遇到一些问题无法解决不得不放弃

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 21 日 06:26 UTC](https://meta.appinn.net/t/topic/30149/18 "2022-02-21T06:26:20Z")

</div>

> [@Xclo](#):
>
> 遇到一些问题无法解决

所以有人做适当的引导还是比较好的，能指明方向不走弯路也算一种捷径了。

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 22 日 00:39 UTC](https://meta.appinn.net/t/topic/30149/19 "2022-02-22T00:39:03Z")

</div>

## 获取瀑布流王网页全部内容

问题来自： [求：保存【响应式网页】到本地文件的工具](https://meta.appinn.net/t/topic/30191) 和 [小众论坛上用浏览器自带搜索只能搜到一部分内容 - #16，来自 Betty](https://meta.appinn.net/t/topic/30152/16)

先说明，是否有必要保存整个网页这件事情有待商榷，我个人以为这个需求应该是在（资料收集）方法上就出了问题。这个工作已经接近爬虫范畴了，责问网页就有点缘木求鱼吧。但这不妨碍我们技术层面讨论。

获取一个回帖的内容很简单，这里稍微放一张图片

 ![image](https://meta-edge.appinn.com/uploads/default/original/3X/8/d/8d44c6b8454e6b5cae79fc4cf8f0a30b308ace05.png)

每个 `.topic-post` 就是一个回帖，但这个元素没啥特征，`article` 这个元素比较好，包含所有回帖内容，并且它的 id 标记了“楼层”。于是就准备一个对象储存内容，然后遍历一下这个元素：

```javascript
const data = {}
document.body.querySelectorAll('.topic-post > article').forEach(el=>{
  data[el.id] = el.innerHTML
})

```

好了，但是数量不够，因为网页没加载出来所有帖子，所以我们要让页面往下滚动，然后再获取。先说往下滚动：

```javascript
while(true){
  const Y = window.scrollY
  window.scrollTo(0,Y+1000)
  // 工作代码放这里
  if(Y === window.scrollY) break
}

```

获取当前滚动的位置，向下滚动 1000 像素，如果位置没变化，那就不滚了，否则无休止的进行下去。兄弟们，虽然这是代码，但它不吃人，你平心静气的思考一下会发现很简单的事情啦。

上下组合一下基本就可以用了，不过严谨点最好判断一下是不是已经保存过某个帖子了，如果是，那就别覆盖了，当然，可能也要判断一下保存的版本文字长度是不是太短之类，我就不详细演示了，简单示例如下：

```javascript
const data = {}
while(true){
  const Y = window.scrollY
  window.scrollTo(0,Y+1000)
  document.body.querySelectorAll('.topic-post > article').forEach(el=>{
    if(data[el.id]) return
    data[el.id] = el.innerHTML
  })
  if(Y === window.scrollY) break
}

```

* * *

核心方法很简单，不过实际使用中要考虑的问题比较多，不展开，就简单说一下：

- 滚动后应该给网页留出加载时间，做一个延时
- 数据量的问题，各种意义上的可能爆内存，遍历太快还可能爆 cpu

至于合并数据，拼接字符串嘛，爆内存就是另外的问题了

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 22 日 08:18 UTC](https://meta.appinn.net/t/topic/30149/20 "2022-02-22T08:18:39Z")

</div>

## 链接访问统计

从这开始聊 [[自荐]Easy Links，追踪和分析你的 web链接](https://meta.appinn.net/t/topic/30204)

做个简易版很容易的，已知跳转到某个网址的代码是：

```javascript
window.location.href = '新地址'

```

做个网页，加上上面的 JS 就可以实现跳转了，这样跳转速度很快的，基本可以认为无感。当然，没有任何统计功能。

我不会写统计功能，太麻烦了，找个第三方统计代码放进去好了，你喜欢什么用什么，我不管。

然后是一个时序问题，进页面就开始跳转的话，可能统计代码还没干活，所以把统计代码放在前面，先执行它。还不放心的话加一点延时跳转就行了。这些操作都十分基础。

* * *

可是，这样只能跳转到固定链接，那我们每次有一个新连接就需要弄一个新的页面，这很烦，所以我们可以利用网址中的 get 参数来传入目标网址，类似这样：

```auto
https://shortlink.com/redirect.html?target=https://meta.appinn.net/t/topic/30149/

```

但这样不行，因为后面网址中的一些符号会捣乱，所以我们得先对后面的网址进行编码，你可以在控制台运行：

```javascript
encodeURIComponent('https://meta.appinn.net/t/topic/30149/')

```

获得这样的结果：

```auto
https%3A%2F%2Fmeta.appinn.net%2Ft%2Ftopic%2F30149%2F

```

然后组合出来的网址我不写了，现在我们网页里要获取这个 target 的值，你去搜索获取 get 值的方法，很多会定义出一个函数，用正则什么的搜索，但是，有一些的正则写的又不够严谨。

其实，如果不考虑兼容低版本浏览器，那么有现成的方法可用，也是非常的简单：

```javascript
window.location.href = (new URLSearchParams(window.location.search)).get('target')

```

得，弄半天就写了一句代码，整的跟没干活似的……

* * *

你看这么简单，你学会了吧， ~~是不是觉得那个帖子里推荐的东东也不过尔尔~~ ……自己动手试试吧，你就知道了。

- 方便的添加链接（当然我们可以再写个界面
- 方便的管理已有链接（当然我们可以再弄个记事本
- 方便阅读的统计数据（我们用的第三方，这个……除非再写个油猴子

如果上面这些你也不太在乎，那么我们的网页放在哪里呢？弄一个国内可以方便访问的网站也比较麻烦吧，何况，好多时候网址是通过 QQ 和微信发送的，自己的小网站很可能在里面被标一个大大的不安全……

所以，所以我们这里只是很单纯的聊聊技术而已。

---

<div class="post-metadata">

### 作者： ![dms](https://meta-edge.appinn.com/user_avatar/meta.appinn.net/dms/32/3545_2.png) [@dms](https://meta.appinn.net/u/dms)
#### 发布日期： [2022 年2 月 24 日 06:39 UTC](https://meta.appinn.net/t/topic/30149/21 "2022-02-24T06:39:22Z")

</div>

## 手机控制电脑

这是对这个回帖（ [为Unified Remote添加任意自定义功能，把手机变成电脑的「真」万能遥控器（兼论如何实现一键盘是英文输入法，一键盘中文输入法） - #3，来自 dms](https://meta.appinn.net/t/topic/30315/3) ）的进一步说明。

这里只是核心原理，因为需要调用外部程序，如果没有编程基础，那么可以实现的效果比较有限。

依然是起一个服务器用来接受请求，但是考虑到我们可能实现比较多的功能，那么有几种方案可以选择：

- 引入 Express，然后利用它的路由功能，这很方便；
- 对请求地址用正则进行判断，算是自己完成路由功能了；
- 就用 get 参数，这会非常简单

我们就假设选择最后一种，还是 [编程有意思 - #2，来自 dms](https://meta.appinn.net/t/topic/30149/2) 这里这样弄，然后把收到的请求输出一下，大概是 `request.query` 这个对象里有请求中的所有 get 参数。

这就方便了，比如获得 get 参数是 `?app=notepad` 就是想打开记事本，怎么打开呢？

```javascript
  exec('notepad', (err, stdout, stderr) => {
    if(err) {
      console.log(err);
      return;
    }
  })

```

行数有一点多，不过其实后面的是错误处理啥的，可以不用管，反正前面 `'notepad'` 里面就是 cmd 命令，就这样。那如果会写 AHK，就可以调用 AHK 去实现各种操作了。

不过除此之外，在接受请求的时候还得做一件事情，就是返回用来展示的页面，比如上面很多按钮的网页，这个自己发挥，不展开了。

如果会 JS，可以把页面里的各种操作弄得流畅一点。不会就每个按钮用一个最基本的表单提交就行。

* * *

一直想弄个类似的东西玩，一方面我手头的旧设备不是很适合，另一方面我想要的功能更复杂一点，比如实时显示当前电脑电量音量啥的。

然后这个方法除了简单还有一个好处：网页可以全屏显示（设备浏览器不太差劲的话），屏幕利用率美滋滋，设备扛得住，自己又会写的话还能加各种特效。

[下一页](https://meta.appinn.net/t/topic/30149.md?page=2)
