分享一个我给 Github README.md 做的访客统计功能 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
jwenjian
V2EX    分享创造

分享一个我给 Github README.md 做的访客统计功能

  jwenjian
jwenjian 2020-06-16 07:58:12 +08:00 13136 次点击
这是一个创建于 1946 天前的主题,其中的信息可能已经有所发展或是发生改变。

这个是我很久之前准备开始用 Github issue 做博客时做的,从 hexo 迁移过去之后 发现用 github issue 写博客没有访客统计功能(虽然本来也没人看)。

但是由于不管是 github issues,还是 github 的 README,都只支持 markdown 语法,不能使用各种第三方统计了。

就自己做了一个访客统计的徽章( badge )服务。

原理很简单,徽章是一个 svg,你只需要在你的 issues 或者 readme 中添加一个 markdown 的图片:

![]( https://visitor-badge.glitch.me/badge?page_id=<your_page_id>) 

当有人打开你的 issue 或者 github 仓库时,浏览器会加载这个图片,服务器就会发出一个请求。

之后根据请求里的 page_id 来计数,并将最新的数量生成到一个 svg 图片中,将这个 svg 返回,浏览器就可以显示出来了。

注意这里的参数:page_id, 需要自己手动给一个唯一的字符串,没有特定规则,只要能唯一标识当前页面即可。

最开始想用 http request header 里面的 referrer 字段,但是后来发现 github 对图片进行了代理,服务器收到的图片请求中没有了原先的 referrer 字段。

另外实现过程中还有一点,就是缓存,github 的图片代理服务器会对你的图片进行缓存,所以我在做第一版的时候发现这个 svg 图片更新有问题,就开始研究 github 用的这个 camo 服务器,后来在返回 svg 的时候在 response 的 header 中做了点手脚:

  1. 添加一个 no-cache 的 header: 'Cache-Control': 'no-cache,max-age=0'
  2. 将 Expires header 的值设置为了当前时间减去 10 分钟

这样设置了之后,就可以绕过 camo 的缓存策略,每次都可以顺利的 +1, 实际效果:

刷新一下这个页面试试?


Github:visitor-badge

第 1 条附言    2020-06-16 09:03:48 +08:00

方便的朋友 也可以顺手给 product hunt 页面点个 vote.

Visitor count badge for your Github Repo - A github badge to count visitor to your repository | Product Hunt Embed

第 2 条附言    2020-06-16 09:14:05 +08:00

额,glitch.me 免费版已经报错说 too many requests 了 :)

不过来得早的同学已经看到效果了..

另外如果有人有富裕的服务器 想自己部署 代码也都有,欢迎。


PS. 如果有人愿意donate一下 我把我的 glitch.me 升级成pro,也可以很稳定... :)

第 3 条附言    2020-06-16 09:36:32 +08:00

再班门弄斧一下吧,这个原理被很多恶意的网站用来收集隐私信息,比如说有的网站给你发的邮件里,不管是营销邮件还是垃圾邮件或者其他的东西,在邮件正文中插入一个 1像素 的图片,图片的url地址都是精心构造好的,当你打开邮件时,发送者就可以知道:

谁,在什么时间,用什么设备,什么ip,什么网络打开了这个邮件。

有了ip就知道你是在什么地方(大致)打开的这个邮件。

从而可以对这个营销邮件的效果进行分析,比如发送了 10000 个邮件,有多少人打开之类的。

再往后挖,甚至还可以挖出你的兴趣,比如给你发不同的主题邮件,18+ 的,创业的,培训班的等等,一样发一个,看看你都打开了哪些,给你打标签...

所以现在一般邮件客户端都默认不加载图片,一是节省打开邮件的时间,加快打开速度,二也是为了保护你的隐私。

你可以检查一下你的邮件客户端,把默认加载图片给关掉。

89 条回复    2020-07-09 15:03:04 +08:00
ob
    1
ob  
   2020-06-16 08:02:54 +08:00 via Android
这个不错,过后试下。
uuspider
    2
uuspider  
   2020-06-16 08:04:05 +08:00 via Android
真是创意无限啊
chotow
    3
chotow  
   2020-06-16 08:04:27 +08:00
你这个统计怎么和 V2EX 的点击统计不一样
jwenjian
    4
jwenjian  
OP
   2020-06-16 08:05:39 +08:00
@chotow v2 的更有意义吧,这个说白了就是统计 图片加载次数
jwenjian
    5
jwenjian  
OP
   2020-06-16 08:33:06 +08:00
@ob 掘金好像不行,他是直接转存的图片,发布之后就编程一个静态图片了 不会变
jwenjian
    6
jwenjian  
OP
   2020-06-16 08:33:24 +08:00
@uuspider 也是收到其他 github 徽章的启发
chizuo
    7
chizuo  
   2020-06-16 08:43:48 +08:00
不错不错,挺好的
zhw2590582
    8
zhw2590582  
   2020-06-16 09:02:43 +08:00
不错,但我只担心服务器稳不稳定,是不是一直维护
jwenjian
    9
jwenjian  
OP
   2020-06-16 09:05:02 +08:00
@zhw2590582glitch.me 上,只要一直有访问,没啥问题。可能偶尔出不来 :)

不过代码开源的 欢迎部署到更稳定的服务器上 提供稳定的服务
ChanKc
    10
ChanKc  
   2020-06-16 09:14:08 +08:00 via Android
GitHub 好像就有访客功能吧,当然不如自己做的全就是
Ritter
    11
Ritter  
   2020-06-16 09:15:17 +08:00
666
jwenjian
    12
jwenjian  
OP
   2020-06-16 09:15:58 +08:00
@ChanKc 这个之前还真没听说过,有链接么
securityCoding
    13
securityCoding  
   2020-06-16 09:18:43 +08:00
创意无限啊
ChanKc
    14
ChanKc  
   2020-06-16 09:25:03 +08:00 via Android   1
@jwenjian traffic 还是什么的,能看到每周克隆数折线图那个页面,手机上没找到
watzds
    15
watzds  
   2020-06-16 09:26:48 +08:00 via Android
以前 bbs 图片签名,能显示 ip,天气之类,是不是也是这个原理
jwenjian
    16
jwenjian  
OP
   2020-06-16 09:28:31 +08:00
@watzds 应该是一个原理
jwenjian
    17
jwenjian  
OP
   2020-06-16 09:37:18 +08:00
@ChanKc 嗯嗯 我好像也见到过,不过我这个纯粹是为了统计打开次数。
NotFoundEgg
    18
NotFoundEgg  
   2020-06-16 09:47:01 +08:00
让我想到了珊瑚虫 qq 印象中也是用发送 1 像素图片获取对方 ip 的
jwenjian
    19
jwenjian  
OP
   2020-06-16 09:50:52 +08:00
@NotFoundEgg 这个还真不清楚是不是这个原理 不过珊瑚虫。。。。哈哈好久之前的东西了 之前好多人都是安装魔改的 qq,各种功能。
metrue
    20
metrue  
   2020-06-16 09:59:35 +08:00
,小功能已经用在了 https://github.com/metrue/fx 上面.
raaaaaar
    21
raaaaaar  
   2020-06-16 10:00:10 +08:00 via Android   3
挺不错,能看见自己打开了多少次 T_T
jwenjian
    22
jwenjian  
OP
   2020-06-16 10:01:47 +08:00 via iPhone
感谢哪位大哥给的置顶…… 我都没注意
jwenjian
    23
jwenjian  
OP
   2020-06-16 10:08:58 +08:00 via iPhone
@raaaaaar 同惨……
Pyrex23
    24
Pyrex23  
   2020-06-16 10:23:16 +08:00 via iPhone
呃呃 是不是不行了?
This project has received too many request, please try again later
metrue
    25
metrue  
   2020-06-16 10:25:57 +08:00
已经挂了?....
WittBulter
    26
WittBulter  
   2020-06-16 10:29:37 +08:00
和我的 `views.show` 有点像: https://docs.views.show/
我一开始也支持 GitHub,后来我发现如果不对 Referrer 做识别,就无法避免暴力刷 views 的问题,虽然服务是在 Serverless 上无所谓压力,但是数据会很不准确。后面当我想实现只读、访客识别等功能的时候,就只好抛弃了 GtHub ...
没有找到特别好绕过 camo 的办法,所以我就转型只做个人博客或者网站的 views 统计了...
jwenjian
    27
jwenjian  
OP
   2020-06-16 10:33:54 +08:00
@metrue glitch 免费版 每分钟有最大次数限制好像... 你可以部署在 giki 的服务器上一份, :)
jwenjian
    28
jwenjian  
OP
   2020-06-16 10:35:56 +08:00
@WittBulter camo 绕不过去,本来用 referrer 是最合适的,不过因为有 camo 就只能这样了,不能说完美,只能说能用吧。
wysnylc
    29
wysnylc  
   2020-06-16 10:42:43 +08:00
这就是 N 年前论坛里签名图片显示 IP 位置 系统信息的东西,上面大吃一惊的是装的吗
slmaaw
    30
slmaaw  
   2020-06-16 10:51:25 +08:00 via Android
这应该也是 Google 的埋点原理吧 请求一个 1 像素的图片
jwenjian
    31
jwenjian  
OP
   2020-06-16 11:06:10 +08:00
iamkun
    32
iamkun  
   2020-06-16 11:10:28 +08:00
leetao94
    33
leetao94  
   2020-06-16 11:12:11 +08:00
有没有统计下载次数的功能呢?
xcodebuild
    34
xcodebuild  
   2020-06-16 11:12:28 +08:00
有个类似的服务 https://hits.dwyl.com/
jwenjian
    35
jwenjian  
OP
   2020-06-16 11:13:29 +08:00
@iamkun 嗯 你可以重点看下我提到的绕过 缓存服务器 camo 的部分,应该是没问题的。每一次生成的图片 github 都会缓存的,你再刷新一下,看看这两个 github 缓存的图片地址,应该是不一样的。
jwenjian
    36
jwenjian  
OP
   2020-06-16 11:14:47 +08:00
@xcodebuild 看起来比我薅 glitch 的羊毛靠谱 :)
iamkun
    37
iamkun  
   2020-06-16 11:15:29 +08:00
@jwenjian 哦刚才没看太仔细 这思路不错
jwenjian
    38
jwenjian  
OP
   2020-06-16 11:15:45 +08:00
@leetao94 这个就用各种统计平台的埋点功能就可以了
jwenjian
    39
jwenjian  
OP
   2020-06-16 11:19:45 +08:00
@xcodebuild 刚看了一下 hits 应该是用的同一种策略绕过 camo 的:

cache-control: no-cache, no-store, must-revalidate
cf-cache-status: BYPASS
cf-ray: 5a4161bc6ebbe80d-LAX
cf-request-id: 035cbb69be0000e80dc7069200000001
content-encoding: br
content-type: image/svg+xml
date: Tue, 16 Jun 2020 03:18:08 GMT
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
expires: 0
pragma: no-cache
server: cloudflare
status: 200
vary: Ac

或者说这应该是一个标准的 http 缓存策略的设置。
wuhaoworld
    40
wuhaoworld  
   2020-06-16 11:28:02 +08:00
这个方式已经不行了吧? 我看 Github 会把外链的图片抓取并保存到 githubusercontent.com 的域名下
ioioioioioioi
    41
ioioioioioioi  
   2020-06-16 11:32:32 +08:00
这个机器人怕也算统计吧
jwenjian
    42
jwenjian  
OP
   2020-06-16 11:33:52 +08:00
@wuhaoworld 可以再仔细点看看帖子
jwenjian
    43
jwenjian  
OP
   2020-06-16 11:34:55 +08:00
@ioioioioioioi 哈 算 不过如果真的有人刷这个数量 也没办法 其实没啥意义,刷个 10w 8w 的,又不能换钱
coldmonkeybit
    44
coldmonkeybit  
   2020-06-16 12:13:30 +08:00
涨知识,终于知道为什么我的邮箱会默认屏蔽图片了
cyrbuzz
    45
cyrbuzz  
   2020-06-16 12:53:35 +08:00
利用 img 图片进行的错误上报...前天刚看了实践就来了。
huiyadanli
    46
huiyadanli  
   2020-06-16 13:03:26 +08:00
想到了 http://hits.dwyl.io/
感觉没啥区别
jwenjian
    47
jwenjian  
OP
   2020-06-16 13:31:19 +08:00
@huiyadanli 这个之前有人提到了,功能上看应该是一样的功能。
jwenjian
    48
jwenjian  
OP
   2020-06-16 13:38:20 +08:00
对了 这个项目的 [首页]( https://visitor-badge.glitch.me) 的 favicon 也是一个 svg 哦,里面放了一个 emoji 表情 ,你可以用这个方式来把你喜欢的 emoji 表情作为网页的 favicon,具体可以看 [这里]( https://www.yuque.com/jwenjian/blog/mpnmmb)
metrue
    49
metrue  
   2020-06-16 14:17:18 +08:00
提一个需求,可以加一个 'since <date>' 的功能。
zhwithsweet
    50
zhwithsweet  
   2020-06-16 14:51:57 +08:00
http://blog.zouhaha.site/ 已经放在自己的 blog 上
wellsc
    51
wellsc  
   2020-06-16 14:59:33 +08:00
Insights 的 traffic 挺好用的,能精确到某个 issue 的 unique visitors,还有图表
meisen
    52
meisen  
   2020-06-16 15:14:45 +08:00
楼主很强大,能否帮忙看下 t/682055 是否可以解决?
jwenjian
    53
jwenjian  
OP
   2020-06-16 15:25:00 +08:00 via iPhone
@wellsc 不瞒你说 我从来没点开过 insight 的那个 tab 页
Tink
    54
Tink  
PRO
   2020-06-16 15:49:57 +08:00
很 6
Tink
    55
Tink  
PRO
   2020-06-16 15:50:24 +08:00
yanshenxian
    56
yanshenxian  
   2020-06-16 16:06:53 +08:00
这个挺好的
jwenjian
    57
jwenjian  
OP
   2020-06-16 16:47:52 +08:00 via iPhone
@yanshenxian 嗯嗯 主要是分享一下这个思路
1daydayde
    58
1daydayde  
   2020-06-16 17:05:58 +08:00
不错,已 star
liuyibao
    59
liuyibao  
   2020-06-16 17:36:00 +08:00
no1xsyzy
    60
no1xsyzy  
   2020-06-16 18:19:07 +08:00
补充:Gmail 对图片进行缓存,不会暴露真实 IP 。
hercat
    61
hercat  
   2020-06-16 18:27:42 +08:00
想法不错
jwenjian
    62
jwenjian  
OP
   2020-06-16 19:37:57 +08:00
jwenjian
    63
jwenjian  
OP
   2020-06-16 19:39:46 +08:00
@cyrbuzz 也是一种跨域新思路
windardyang
    64
windardyang  
   2020-06-16 21:34:28 +08:00
cool, like it.
windardyang
    65
windardyang  
   2020-06-16 21:34:38 +08:00
stared
sedgwickz
    66
sedgwickz  
   2020-06-16 22:00:05 +08:00
建议给 ip 加个 cache,否则容易被刷,刚试了下,一会刷了好几千。

测试地址: https://visitor-badge.glitch.me/badge?page_id=visitor-badge.v2ex.sharing1

测试代码:


import requests
import time
import threading

def sendReq():
try:
r = requests.get('https://visitor-badge.glitch.me/badge?page_id=visitor-badge.v2ex.sharing1')
except:
pass

def run():
try:
while 1:
threading.Thread(target=sendReq).start()
time.sleep(0.01)
except:
pass

run()
jinliming2
    67
jinliming2  
   2020-06-16 23:53:58 +08:00 via iPhone
很多邮箱默认不加载图片之类的第三方资源的,要手动允许加载,而手动允许加载也有很多邮箱是由邮箱提供者的服务器代为请求然后处理一下,返回给你的不是原始文件,防止图片里有恶意代码……
JCZ2MkKb5S8ZX9pq
    68
JCZ2MkKb5S8ZX9pq  
   2020-06-17 00:24:06 +08:00
思路不错,不晓得那些带统计的短链接网站能不能做到类似的事情。
就不展示,仅统计。
aleung
    69
aleung  
   2020-06-17 01:00:26 +08:00 via Android   1
20 年前的网站就是这样做的,而且计数器就是当年网站里唯一的动态内容。失传的技艺重新发掘出来了,哈哈
jwenjian
    70
jwenjian  
OP
   2020-06-17 02:07:45 +08:00 via iPhone
@sedgwickz 无所谓了,刷这个不顶吃不顶喝的……
jwenjian
    71
jwenjian  
OP
   2020-06-17 02:08:40 +08:00 via iPhone
@jinliming2 嗯……之前也有人提到 Gmail 缓存图片 这更进一步保护邮箱安全了
jwenjian
    72
jwenjian  
OP
   2020-06-17 02:10:02 +08:00 via iPhone
@JCZ2MkKb5S8ZX9pq 那个不需要这么做 因为你只要访问了短链接,它在给你跳转之前就可以把这些工作做了,统计的出发点是你会直接访问短链接
jwenjian
    73
jwenjian  
OP
   2020-06-17 02:10:26 +08:00 via iPhone
@aleung 嗯……老技术 新场景……
jwenjian
    74
jwenjian  
OP
   2020-06-17 02:14:49 +08:00 via iPhone
@coldmonkeybit 还有人提到你的邮件服务器会替你代理发送图片请求,隐藏你的真实 IP
OldPanda
    75
OldPanda  
   2020-06-17 05:37:52 +08:00
创意不错,不知道有没有考虑过用 aws lambda + api gateway 来搭后台,每个月前一百万次请求免费,几乎等于不要钱
jwenjian
    76
jwenjian  
OP
   2020-06-17 07:45:58 +08:00 via iPhone
@OldPanda 谢谢你。aws 这一套我捣鼓过 后来好像要验证我的信用卡 我没有……
myqoo
    77
myqoo  
   2020-06-17 09:08:35 +08:00
这就和当年网站计数器一样,写个脚本可以刷它爆表~
dreamage
    78
dreamage  
   2020-06-17 09:20:25 +08:00
思路清奇
VShawn
    79
VShawn  
   2020-06-17 10:57:51 +08:00
@jwenjian #76 我刚才在 Github 上试了一下以前用的统计工具,也是用图片进行统计,楼主可以参考一下。

https://github.com/VShawn/Shawn_pose_estimation_by_opencv/blob/master/README.md
jwenjian
    80
jwenjian  
OP
   2020-06-17 11:19:52 +08:00 via iPhone
@VShawn 嗯嗯 这个我之前也见过 原理是一样的 只是它多做了很多工作 比如拿到你的 IP 之后 把 IP 转成地理位置 再画在一个地图上 最终生成一个图片,我做的这个比较简单 只是统计次数。
jwenjian
    81
jwenjian  
OP
   2020-06-17 13:39:52 +08:00
@myqoo ...
yazoox
    82
yazoox  
   2020-06-18 12:35:36 +08:00
很有意思的功能
lzj307077687
    83
lzj307077687  
   2020-06-18 18:41:16 +08:00
![]( http://badge.roblog.top/?key=v2ex_reply)
哈哈 我也写了个
jwenjian
    84
jwenjian  
OP
   2020-06-18 20:04:51 +08:00
jwenjian
    85
jwenjian  
OP
   2020-06-18 20:06:05 +08:00
@yazoox 嘿嘿 虽然原理简单 技术也不难,不过有了新的应用场景还是挺好玩儿的
lzj307077687
    86
lzj307077687  
   2020-06-19 09:24:31 +08:00
@jwenjian #84 前几天看了一眼这贴,然后昨天在学 py 的时候突然想起来感觉可以写一下!
虽然功能比较简单,不过也学到了东西,svg 文件,重温了下 http header 什么的...
刚回来看发现原来有 github,而且也是拿 py 写的,巧了~
jwenjian
    87
jwenjian  
OP
   2020-06-19 09:26:08 +08:00
@lzj307077687 哈哈,github 的链接字太小,确实不容易发现。
jwenjian
    88
jwenjian  
OP
   2020-07-09 12:54:03 +08:00 via iPhone
最近这两天被发现的一个彩蛋 GitHub 创建一个用户名同名的仓库 这个仓库的 README 就可以显示在你的 GitHub profile 页面,你可以在这个 README 里添加这个 badge 就可以知道你的 GitHub 页面被打开多少次啦~

示例参见我的 github
Leprax
    89
Leprax  
   2020-07-09 15:03:04 +08:00
@jwenjian #88 刚刚知道了这个彩蛋,又特地来爬了这个帖子
关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2963 人在线   最高记录 6679       Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 36ms UTC 14:10 PVG 22:10 LAX 07:10 JFK 10:10
Do have faith in what you're doing.
ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86