8
18
2022
15

我所讨厌的网页行为

有些网页的行为通常不被视为 bug,甚至是故意为之,但很令人讨厌。这里记录一些我所讨厌的网页「特性」。它们被归为两类,要么导致某些场景下用不了,或者用着很不方便,要么很打扰人。

可访问性问题

忽视系统、浏览器设置,在浏览器使用浅色主题的情况下默认使用深色主题,或者在浅色主题下代码部分使用深色主题。反过来问题不大,因为我有 DarkReader

主体文本不支持选择和复制。选择和复制之后,用户能做很多事情,比如查生字、翻译、搜索相关主题。

已访问链接与未访问链接显示没有差别。

消除可交互元素(链接、按钮)的 outline。这个 outline 以前是虚线框,现在火狐改成了蓝色框,用于标识当前键盘交互的对象。

搜索框不支持回车确认,必须换鼠标点击。

位于文本框后的按钮不支持使用 Tab 键切换过去,并且 Tab 键在此文本框中也没有任何显著的作用。必须换鼠标点击。

需要交互的元素不能被 vimium 插件识别为可点击。这大概是使用非交互元素来处理交互事件,甚至事件监听器都不在元素本身上。

使用 JavaScript 实现原本可以直接用链接实现的内容(链接目标是某个 JavaScript 函数调用)。这导致我无法使用中键来在新标签页中打开。

显著不同的内容没有独立的 URL。尤其见于一些单页应用(SPA)。要到达特定内容(比如加书签或者分享给别人),就只能记录先点哪里、再点哪里等。

预设用户的屏幕大小,导致浏览器窗口过小的时候部分关键内容(如登录按钮)看不到、无法操作。

交互元素没有无障碍标签。成堆的「未加标签 按钮」。

通过 User-Agent 判断浏览器,并拒绝为某些 User-Agent 服务(但实际上去除这个限制之后,功能是完全没有问题的)。

当没有带声音自动播放权限时,无声播放主体内容(而非等待用户操作使其获得权限)。说的就是 Bilibili。

为大屏幕用户(如桌面用户)展示为手机屏幕设计的页面。这些页面中字体特别巨大,并且不能被浏览器缩放影响。交互元素上鼠标指针不改变为手状,甚至只支持触摸操作而不支持鼠标点击。

悬浮于主内容之上的「在App中打开」。点名批评 imgur。它的按钮不光挡住图片,而且用户放大图片的时候它也被放大,挡住更多图片内容。

不能禁用的图片懒加载,或者视频内容被移出画面、切换到后台就停止加载。点名批评 Telegram、维基百科。我等你加载呢,你非要我盯着看你加载浪费时间?现在网好,你赶紧给我加载好,进电梯或者地铁或者山洞了,我再慢慢看你的内容啊。

视频内容被移出画面就停止播放。点名批评知乎。我让你播放你就给我播放。我不看视频,是因为视频画面没啥可看的,可是我听音频部分呀。

覆盖浏览器的 Ctrl-F 查找快捷键,并不提供方案来避免覆盖。我就搜索当前页面,不要你的站内搜索功能。

注册前请务必先阅读用户条款和规则,用户条款和规则页面需登录后才可访问。

简体中文内容指定繁体中文的字体,或者添加繁体中文的标签。或者反过来。

打扰用户

在内容页面,任何会动的非主体内容,包括但不限于广告、内容推荐。形式可以是动态 GIF、滚动动画、视频等。用于首页渲染效果的背景动画和视频不算,作为主体内容者也不算。

针对非音视频网站,自动或者非用户明确表达地(比如在用户点击不相关内容时)播放带音频的内容。

消耗 CPU 的背景特效。如 canvas-nest。会让 CPU 很吵,也会浪费能源、加剧气候变化。

Category: 用户体验 | Tags: 网页 accessibility
8
31
2017
17

新的火狐,新的旅程

Firedoge

今年底火狐将不再支持旧的基于 XUL 的扩展了。火狐53已经不支持 GTK 2 了。每人一只与众不同的火狐的时代行将结束,而生活仍要继续。

使用 ESR 版本只是短暂地续命罢了,stylo 也用不了。正巧ヨイツの賢狼ホロ[archlinuxcn] 仓库打包了可以与已有版本共存的 firefox-nightly 包,于是新的旅程开始了。

一开始,我尝试喂给它旧的 profile(复制了一份,然后用 firefox-nightly -no-remote -P 启动)。我原本有64个扩展,结果只有六个还兼容……

不如像之前升级火狐4那样,重练好了。重新取一块干净的画布,从头开始。

结果比预期中的好很多。

首先,新火狐很快。我不想办法关动画了。我不担心开新的窗口耗时了。多进程的架构也使得我不那么害怕单个标签页卡死导致什么也做不了了。不过不知道是进步明显,还是我那几十个XUL扩展太拖累了。

然后,同步很好用。虽然同步的内容有限,但是比手工搬移一些数据好多了,也可以把标签页发送到另外的设备阅读。同步的数据包括:书签,历史,表单自动填充,密码,从AMO安装的扩展(不过只会安装最新稳定版),部分首选项(只是一部分,所以还是有不少需要手动调整)。打开的标签页也可以从另外的设备看到。我同时也在 Android 上登录了同步,这样访问历史可以同步,方便在不同的场景下继续阅读。

不过也有点问题。首先是 tampermonkey 支持同步从URL安装的脚本,但是呢,一开始它没同步过来,我手动安装了。然后它又不知道什么时候同步了一份,于是重复了。删掉重复的,又过了一段时间,同步过来的那份也消失了……

还有一些设置上的调整。about:config 打开,搜索 x-western,改成 sans-serif 字体。剩下的中日韩字体设置,这次我直接在 fontconfig 那边配置了,就不用在火狐里点来点去的了。

安装中文语言包之后([archlinuxcn] 源里有),搜索 locale,把 en-US 改成 zh-CN。

搜索 urlbar,关闭自动填充、双击全选、隐藏 http:// 和 ftp://,地址栏建议数量增加为15,关闭搜索引擎的建议。

定制一下工具栏,使用紧凑布局,把不需要的扔掉,用得少的放进收纳盒里去。RSS 按钮丢最右上角好了。侧栏还是显示左边吧,那按钮也放左边来。

导入旧的书签。开了同步的话,注意一定不要从备份中恢复书签!因为恢复的时候会删掉已有的所有书签,包含移动端书签。导出成 HTML 再导入就会合并了。

打开 InoReader 设置界面,把 InoReader 添加为RSS阅读器。

最后就是各种扩展了。许多扩展没有迁移到 Web Extensions,但是一些还是有替代方案的。具体可以看这个表格。然后是配置这些扩展,包含各种扩展数据的导入。

还有很多扩展没有替代品,那也只能放弃了。有些扩展目前是不可能在 Web Extensions 上实现的。至于 UI,算了,接受现实吧。其实 nightly 的 GTK 3 界面做得比最开始的版本已经好了很多。

哦对了,我还换了个轻量级主题。之前使用的 White Lily,已经下架很久了。这次我换了这个,明快简洁,挺好看的。

具体扩展的介绍,我单独写了一篇

在导入网易云音乐的播放列表(我没有登录)的时候,我还发现一个事儿:火狐52的 devtools 有 bug,并不会显示 localStorage……

总体感受,忍痛割爱之后,又是一片新天地。nightly 确实很快。

Category: 火狐 | Tags: 火狐 网页 浏览器
3
26
2014
18

百度登陆方法及网盘 API 基本操作

本文只介绍流程,因此是以最方便试错的 shell 脚本为示例的。也就是一系列简单的 HTTP 请求,用什么语言都一样。

要实践本文中的例子,首先要确保系统上已经安装了如下软件:

  • curl: 命令行 HTTP 调试首选工具
  • jshon: 命令行 JSON 解析器。使用简单的栈式语法
  • json_pp: 这个命令行工具是 perl 自带的,把 JSON 数据格式化显示用的

首先把用户信息存到变量里去:

$ BDUSER=你的百度登陆名
$  PASS=你的百度登陆密码

访问一次百度,取得一个名为BAIDUID的 cookie。我们在此,以及以下所有 curl 命令中,都会使用-b-c选项告诉 curl 从当前目录下的「cookies」文件读取 cookie 数据,把接收到的 cookie 写到同一个文件里去。

$ curl -b cookies -c cookies http://www.baidu.com/ -sS -o /dev/null

获取 token:

$ TOKEN=$(curl -b cookies -c cookies -sS "https://passport.baidu.com/v2/api/?getapi&tpl=mn&apiver=v3&class=login&tt=$(date +%s860)&logintype=dialogLogin" | tr "'" '"' | jshon -e data -e token -u)
$ curl -b cookies -c cookies "https://passport.baidu.com/v2/api/?logincheck&token=$TOKEN&tpl=mn&apiver=v3&tt=$(date +%s)&username=$BDUSER&isphone=false"
{"errInfo":{ "no": "0" }, "data": { "codeString" : "", "vcodetype" : "" }}

使用用户信息登陆:

$ curl -b cookies -c cookies --compressed -sS 'https://passport.baidu.com/v2/api/?login' -H 'Content-Type: application/x-www-form-urlencoded' --data "staticpage=http%3A%2F%2Fpan.baidu.com%2Fres%2Fstatic%2Fthirdparty%2Fpass_v3_jump.html&charset=utf-8&token=$TOKEN&tpl=mn&apiver=v3&tt=$(date +%s083)&codestring=&safeflg=0&u=http%3A%2F%2Fpan.baidu.com%2F&isPhone=false&quick_user=0&logintype=basicLogin&username=$BDUSER&password=$PASS&verifycode=&mem_pass=on&ppui_logintime=57495&callback=parent.bd__pcbs__ax1ysj" | grep -F 'err_no=400032' > /dev/null

如果这条命令返回(即$?的值)为 0 则成功,否则失败。这是因为百度的登陆之后的页面会进行跳转,如果登陆成功那么跳转 URL 里包含err_no=400032,否则err_no是别的什么值。这个判断条件可能会变化,比如去年年底是err_no=40032时表示成功。

登陆成功之后就可以调用网盘 API 了。这部分比登陆的请求要好看许多。

先来获取一下网盘容量,也好确认我们确实登陆成功了:

$ curl -b cookies -c cookies 'http://pan.baidu.com/api/quota'
{"errno":0,"total":510341939200,"used":0}

这些请求直接在网页版里开着 Firebug 看就可以了。比如:

列根目录下的文件信息:

$ curl -b cookies -c cookies 'http://pan.baidu.com/api/list' | json_pp
$ curl -b cookies -c cookies 'http://pan.baidu.com/api/list?dir=/test' | json_pp

建立目录:

$ curl -b cookies -c cookies 'http://pan.baidu.com/api/create' -F path=/测试curl -F isdir=1 -F size= -F block_list='[]' -F method=post

参考资料

Category: 网络 | Tags: 百度 curl 网页
10
12
2013
24

GM 脚本:在 Disqus 中提示需要登录

Disqus 越来越受欢迎,然而,非 Disqus 用户评论越来越艰难

一开始,和 WordPress 一样,名字、电邮、网站。想要新评论通知?好呀,使用 Facebook、Twitter 或者 Google+ 登录下就好。

后来,「Twitter 用户,创建个 Disqus 帐号吧!」不想要 Disqus 帐号,那就不要登陆了,也甭想推广自己的博客,填上电邮地址显示个头像吧。当然,为了迫使你们登陆,名字和电邮信息也不像一般博客是记住的。下次继续填,继续勾选「以访客身份发布」。

现在,花了不少时间和心思写完很不错的评论,双击填名字的文本框填名字时,却经常发现刚展开的部分里那个「以访客身份发布」复选框没有了。「对不起,必须登录才能在此博客留言哦亲。」Holy shhhhhhhhhhhhhit!

此 GreaseMonkey 脚本为防止最后一种情况的发生,在你动手写下评论的时候明确告诉你不登录你的评论是发不出去的

不过,由于我现在取不到自己的 Disqus 帐号密码,所以不确定登录 Disqus 帐号之后这个脚本能否正确检测到。欢迎反馈!

点击安装

脚本全文如下:

// ==UserScript==
// @name        Disqus login required reminder
// @namespace   http://lilydjwg.is-programmer.com/
// @description Remind you if you can't post your comments because you aren't logged in
// @include     http://disqus.com/embed/comments/*
// @include     https://disqus.com/embed/comments/*
// @version     1
// ==/UserScript==

var check = function(){
  var el = document.querySelector('input[name="author-guest"]');
  if(!el){
    setTimeout(check, 100, false);
    return;
  }
  if(el.style.display == 'none'){
    console.log("login required");
    var msg = document.getElementsByClassName('placeholder')[0];
    msg.textContent = '需要登录 / Login Required!';
    msg.parentNode.addEventListener('blur', function(){
      var msg = document.getElementsByClassName('placeholder')[0];
      msg.textContent = '需要登录 / Login Required!';
    });
  }
};

setTimeout(check, 100, false);

点击安装


附:我始终认为,不管登陆评论能给用户和自己带来多大的好处,只要文章允许评论,来访者应当能够以最小成本发表评论并且署名。也就是,不需要注册,不需要登录,你就可以评论。最好支持 Gravatar 头像,最好支持链接到自己的网站,最好支持被回复时 Email 提醒。实际上本博客非登录用户需要填写验证码我已经很不爽了,只是 Chito 这个博客程序提供的另一种反垃圾策略——使用 Akismet——我这边已经坏掉了。

所以我越来越敬佩 WordPress。

Category: 火狐 | Tags: 博客 火狐 网页 GreaseMonkey
7
26
2013
6

飞速中文网小说下载脚本

  • JavaScript 加密什么的最讨厌了 :-(
    • eval 一个不依赖外部变量的函数立即调用很天真,看我 nodejs 来干掉你!
    • HTTP 请求的验证首先尝试 Referer,「小甜饼」没有想像中的那么重要。
    • curl 和各命令行工具处理起文本很顺手呢
    • 但是 Python 也没多几行呢
  • Requests 效率比 lxml 自己那个好太多
  • progressbar 太先进了,我还是自个儿写吧……
  • argparse 写 Python 命令行程序必备啊~
  • string.Template也很好用哦
  • 以下是主代码啦,除了标准库以及 lxml 和 requests,没有的模块都在无所不能的 winterpy 仓库里。其实主代码也在的。
#!/usr/bin/env python3
# vim:fileencoding=utf-8

import sys
from functools import partial
from string import Template
import argparse
import base64
from urllib.parse import unquote

from lxml.html import fromstring
import requests

from htmlutils import extractText
from termutils import foreach

session = requests.Session()

def main(index, filename='$name-$author.txt', start=0):
  r = session.get(index)
  r.encoding = 'gb18030'
  doc = fromstring(r.text, base_url=index)
  doc.make_links_absolute()
  name = doc.xpath('//div[@class="info"]/p[1]/a/text()')[0]
  author = doc.xpath('//div[@class="info"]/p[1]/span/text()')[0].split()[-1]

  nametmpl = Template(filename)
  fname = nametmpl.substitute(name=name, author=author)
  with open(fname, 'w') as f:
    sys.stderr.write('下载到文件 %s。\n' % fname)
    links = doc.xpath('//div[@class="chapterlist"]/ul/li/a')
    try:
      foreach(links, partial(gather_content, f.write), start=start)
    except KeyboardInterrupt:
      sys.stderr.write('\n')
      sys.exit(130)

  sys.stderr.write('\n')
  return True

def gather_content(write, i, l):
  # curl -XPOST -F bookid=2747 -F chapterid=2098547 'http://www.feisuzw.com/skin/hongxiu/include/fe1sushow.php'
  #      --referer http://www.feisuzw.com/Html/2747/2098547.html
  # tail +4
  # base64 -d
  # sed 's/&#&/u/g'
  # ascii2uni -qaF
  # ascii2uni -qaJ
  # <p> paragraphs
  url = l.get('href')
  _, _, _, _, bookid, chapterid = url.split('/')
  chapterid = chapterid.split('.', 1)[0]
  r = session.post('http://www.feisuzw.com/skin/hongxiu/include/fe1sushow.php', data={
    'bookid': bookid, 'chapterid': chapterid,
  }, headers={'Referer': url})

  text = r.content[3:] # strip BOM
  text = base64.decodebytes(text).replace(b'&#&', br'\u')
  text = text.decode('unicode_escape')
  text = unquote(text)
  text = text.replace('<p>', '').replace('</p>', '\n\n')

  title = l.text
  write(title)
  write('\n\n')
  write(text)
  write('\n')
  return title

if __name__ == '__main__':
  parser = argparse.ArgumentParser(description='下载飞速中文网小说')
  parser.add_argument('url',
                      help='小说首页链接')
  parser.add_argument('name', default='$name-$author.txt', nargs='?',
                      help='保存文件名模板(支持 $name 和 $author')
  parser.add_argument('-s', '--start', default=1, type=int, metavar='N',
                      help='下载起始页位置(以 1 开始)')
  args = parser.parse_args()
  main(args.url, args.name, args.start-1)
Category: python | Tags: python 网页 爬虫
4
4
2010
0

用 jQuery 写了个给页面链接加上提示的小书签

已经不记得是怎样发现Learning jQuery这个博客了。首先看到的是关于在网页中加载 jQuery的几篇博文,非常不错,而且改进后的版本挺人性化的。所给链接上有小书签的链接,这里这不再给出了(不懂e文的童鞋请在页面上搜索“jQuerify”)。

觉得这个博客非常不错,当然不能看完一走了之了。于是订阅之,然后就发现了这个简单的jQuery插件——eztip,这里有作者写的demo,效果图如下:

点击这里,然后把鼠标移到本页的链接上,你也可以看到类似的提示哦!

这是所用到的代码,很简单呵:

$(document).ready(function() {
  $('.tips').eztip('a', {contentAttrs: ['title','href'], opacity: .75});
});

样式还得自己定义一下:

.simple-tip { position: absolute; background-color: #cec; border: 1px solid #393; padding: 6px;}

这个插件有点小问题:当链接位于页面右边缘或者下边缘时,提示仍然会出现在右下方(或者你定义的其它位置),造成出现滚动条并且看不到提示的情况。

不过,既然能在任意页面通过小书签加载 jQuery,何不通过小书签把这个提示也加上呢?于是,仿照 jQuerify 小书签,我自己也写了一个给链接加上提示的小书签。调试它花了我一个小时左右呢,这还是有Vimjsbeautify这个清理 Javascript 的 Vim 插件的帮助的情况下。注意,使用前要先确定页面已加载 jQuery,如果网页没有使用 jQuery 的话就用上面介绍的小书签啦。下面给出这个小书签的代码:

javascript: (function() {
  var el = document.createElement('div'),
  b = document.getElementsByTagName('body')[0];
  msg = '';
  el.style.position = 'fixed';
  el.style.height = '32px';
  el.style.width = '220px';
  el.style.marginLeft = '-110px';
  el.style.top = '0';
  el.style.left = '50%';
  el.style.padding = '5px 10px 5px 10px';
  el.style.zIndex = 1001;
  el.style.fontSize = '12px';
  el.style.color = '#222';
  el.style.backgroundColor = '#f99';
  if (typeof jQuery == 'undefined') {
    msg = 'This page is not using jQuery, sorry!';
    return showMsg();
  }
  function getScript(url, success) {
    var script = document.createElement('script');
    script.src = url;
    var head = document.getElementsByTagName('head')[0],
    done = false;
    script.onload = script.onreadystatechange = function() {
      if (!done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')) {
        done = true;
        success();
      }
    };
    head.appendChild(script);
  }
  getScript('http://plugins.learningjquery.com/eztip/jquery.eztip.js', function() {
    jQuery('body').eztip('a', {
      contentAttrs: ['href', 'title'],
      opacity: .9
    });
    jQuery('.simple-tip').css({
      position: 'absolute',
      zIndex: 9999,
      backgroundColor: '#cec',
      color: '#131',
      border: '1px solid #393',
      padding: '6px'
    });
    msg = 'link tip ready!';
    return showMsg();
  });
  function showMsg() {
    el.innerHTML = msg;
    b.appendChild(el);
    window.setTimeout(function() {
      if (typeof jQuery == 'undefined') {
        b.removeChild(el);
      } else {
        jQuery(el).fadeOut('slow', function() {
          jQuery(this).remove();
        });
        if (otherlib) {
          $jq = jQuery.noConflict();
        }
      }
    },
    2500);
  }
})();

| Theme: Aeros 2.0 by TheBuckmaker.com