分类
网站

Python真香:尝试开发数据爬取与后端接口

高考结束,回到开往项目组。大学录取了计算机方向的专业,之前做项目的经历告诉我开发这件事情不能靠别人,自己不太好意思再给别人提需求了,也对同龄人已经熟练使用 Node.js 感到焦虑,所以这几个月自己尝试打开电脑为项目写点东西。

此前用 PHP 和原生 JavaScript 写过一点点东西,但都不算作一个项目——要么就是从网上搜随机数来实现随机动漫图片,要么就是搜索关于数组的处理方法用函数实现了一下并集、补集之类的东西。

这并不算是一个技术笔记,只是我的碎碎念。

编写 Python 数据爬取脚本

开往此前有一个“成员文章同步”的 ToDo,但是一直没有人实现。所以,我来折腾了(实则为捣乱)。

成员文章同步计划用 FreshRSS 实现,现在只需要用一个脚本爬取开往成员的订阅地址,生成一个 OPML 文件就好了。

开往成员的订阅地址从哪里整呢?组里原先有一些想法:弄个平台让站长自行提交;内置订阅地址的一些常见 uri 去测测哪个可以访问……最后,我想到了自己此前维护过的项目——中文博客列表导航。自己之前收集的那些订阅地址不就派上用场了?我可真是一个天才(猪)。

第一次,我的想法是这样的:

用 OneNote 画的超级丑的图

但是,当我真的去按照这个思路写代码的时候,电脑报错了。检查之后发现是中文博客列表导航有频率限制。我尝试 sleep 了一下,发现效果不好。这样会给中文博客列表导航发一千多次请求,对项目不友好。

所以,我对思路进行了改进(其实并不是):首先请求中文博客列表导航和开往的全量数据(相当于复刻了两个项目的数据库),再在中文博客列表导航的数据里查开往的成员网站,找到订阅地址信息。代码碎片如下:

travellingsData = requests.get('https://api.travellings.cn/all', headers = headers)
travellingsData = list(json.loads(travellingsData.text)["data"])

regex = r"^(?:https?:\/\/)?(?:[^@\/\n]+@)?(?:www\.)?([^\/:\?\n]+)"

zhblogsRequestUrl = 'https://www.zhblogs.net/api/blog/list?page=1&pageSize=7000'
zhblogsData = requests.get(zhblogsRequestUrl)
zhblogsData = json.loads(zhblogsData.text)["data"]["data"]

def searchZhblogs(targetDomain, zhblogsAllData):
    for j in zhblogsAllData:
        if targetDomain in j["url"]:
            return j
    return 0

这里有一个细节,中文博客列表导航并没有获取全量数据的接口,怎么办呢?我发现项目的博客列表请求接口时会带一个 Size 参数。我试着把这个 Size 调成一个很大很大的值,这样数据就可以覆盖项目收录的全部博客。我试了一下,果不其然,成功了。我真是一个小机灵鬼

接下来是如何生成 OPML。我找组里的 Kegongteng 要了一份文件,看了一下文件的结构,感觉还挺简单的,就是这个 xml 不知道要用什么东西搞定。字符串拼接?我之前想过这个东西,但是肉眼可见的麻烦。懒惰的我上网搜了一下 Python 生成 xml 文件的方法,发现了一个东西,让我眼前一亮。

import xml.etree.ElementTree as ET

# 创建根元素
root = ET.Element("RootElement")

# 创建子元素
child1 = ET.SubElement(root, "ChildElement")

# 添加属性
child1.attrib["attribute"] = "value"

# 创建子元素的文本内容
child1.text = "Hello, World!"

# 创建XML文件
tree = ET.ElementTree(root)
tree.write("example.xml")

当时看到这个东西就喜欢上了。这才是适合我这种小菜鸡使用的库。Python 真香!我不知道该怎么形容我喜欢它的原因,可能是“高度的语义化”?不懂。

有了这个库,我就可以不用尝试痛苦的字符串拼接了,直接写成以下代码:

root = Element('opml')
root.attrib["xmlns:frss"] = "https://freshrss.org/opml"
root.attrib["version"] = "2.0"

# head元素
head = SubElement(root, 'head')

# head里套title元素
title = SubElement(head, 'title')
title.text = "开往成员文章订阅"

# body元素
body = SubElement(root, 'body')

outline1 = SubElement(body, 'outline')
outline1.attrib["text"] = "技术博客"

for j in travellingsTechBlogData:
    searchResult = searchZhblogs(re.match(regex, j["url"]).group(1), zhblogsData)
    if searchResult != 0 and searchResult["feed"] != None:
        outline = SubElement(outline1, 'outline')
        outline.attrib["text"] = j["name"]
        outline.attrib["type"] = "rss"
        outline.attrib["xmlUrl"] = searchResult["feed"][0]["url"]
        outline.attrib["htmlUrl"] = j["url"]
        outline.attrib["description"] = searchResult["sign"]

tree = ElementTree(root)

# write out xml data
tree.write('result-tech.xml', encoding = 'utf-8', xml_declaration = True)

最后,拖了一年多的 ToDo 就被我这么折腾完了。

整完成员文章订阅的东西之后,我还弄了一个标签同步的东西,这里不再赘述。

用 Python 写巡查工具后端

一句玩笑话

开往的巡查工具又是一个拖了很久的东西,之前大蛋糕写的前端代码还在。我来折腾(捣乱)一下。

最开始是跟组里的同学确定一下需求,是这样的:

用飞书画的模式图,比较漂亮

然后,因为我喜欢折腾,所以这个东西前端和后端分成两个人完成——前端由组里的 Lee 同学负责,后端就由我来糟蹋了。

首先是看看用 Python 的什么开发。Django?太重了,还会把前端的活给刨了。FastAPI?文档看不懂(太真实了)。为什么不用 Node.js 开发呢?因为我看不懂教程。所以,我用 Python Flask 来做后端,因为它够轻,够简单,够友好。

接着,我对要用到的接口进行了整理,大致如下:

这是我第一次做项目。虽然最后没有严格按照这样开发,但我仍然认为这样做是必要的,因为这样做我不再是无头苍蝇了。

然后,我用 PHPStudy 配了一下 MySQL 数据库环境,开始“查文档-写代码-调试”的循环。这个过程超级花时间,我还容易忘记时间。几次下午坐在电脑面前一坐就坐到夜晚。几次我爸我妈教我下楼吃饭,我都还在忙着改 SQL 查询语句,最后我爸把饭端到房间让我边写边吃。

开发过程琐碎。这里列出一些问题,以及我的解决方法(或者是组里的 Lee 和 Xuanzhi 同学告诉我的)

问题解决方法
路由挤在一个文件里面不利于维护使用 Flask 的 Blueprint
要防止 SQL 注入攻击使用参数化查询
CORS 跨域使用 flask_cors 拓展库
配置参数硬写在代码里不好使用 .env 以及 Python 相应的库

Xuanzhi 还提了一些关于接口设计的问题,比如不宜用 ifSuccess 作布尔值的名称,而应为 Success 或 isSuccess。我发现我把 is 记成 if 了。

各位大佬可以在 GitHub 上看到本小菜鸡的代码。如果有改进建议,还请批评指出。

分类
网站

加入开往团队所给我带来的

(以下内容都是我语音输入出来的,也就是说出来的,你可以想象一个人面对面的在跟你说话)

大家好,我叫林林。就今天加一个博主的微信,然后他开头就问好:“您是开往的林林吗?”那看来我已经臭名昭著了哈哈。呃,几个月之前就看到晓雨(还是叫他网名比较好,虽然比较习惯叫别人的真实名字)在他的博客里面发表了一篇文章《加入开往团队所给我带来的》。啊,看了那篇文章,我感触比较深。之前去邀请一位博主加入另外一个项目的维护组的时候,就发现他在那篇文章里面发现了个华点,就是那个忘记被他打码打掉的那个“你喜欢散兵吗?”。就看那篇文章,自己也在思考:我从开往获得了什么?我让开往获得了什么?

忙这种开源项目,不做编程的话,可能更多的只是忙一些繁琐的事情。就比如说,审核网站、处理issue、跟别人沟通之类。我自己目前还有一个中文博客列表导航,这个项目目前就几乎没有精力去管,项目本身也有人在管理。那个项目刚开始添加网站的方式非常的原始,就是在GitHub上面对一个JSON文件进行编辑,进行人工编辑。那个时候添加网站就是机械式的ctrl+C/V,就今天把友情链接搬过来的时候也用了这个方法,也才20个网站就受不了了。开网在没有用数据库之前也是用这种比较原始的方法添加网站的,就挺好奇刚开始那一会300个网站是怎么加进去的。那在开往做这些事情,其实并没有给我带来什么实质性的东西。甚至我弄博客还要倒贴钱去买域名、买服务器,还要花精力在搞网站,搞服务器,搞CDN,更新域名证书,提交网站备案之类的各种各样繁琐的事情上面。所以参与这个项目更多的给我带来的是成员之间的沟通和交流,以及项目被人夸赞所带来的自豪。

开源项目这种神奇的东西其实一个人就可以完成维护,像听说个站商店目前就是完全由一个人来负责开发,负责审核,负责日常的运维。开往以及中文博客列表导航都经历过这种阶段,但在这个阶段的时候常常会因为维护了这个人的时间精力以及一些状况,导致项目停滞。所以你看,目前两个项目都是有一个团体,当然开往维护组的一位技术说是团伙,来进行日常的开发、日常的维护的。

开往项目里面是有分工的。我之前初中的时候进过一个服务器的建设群,那个群刚刚创建,所以那个时候群里面非常的吵,各种各样的人都会提出他们自己的方案,那个时候喧闹了一个上午都拿不出一个大致的计划。在这个时候,就有人提出要先对建筑、指令、红石的人员进行分类,然后再分组选出组长,再有这些组长来下达命令,来进行讨论。这个方案一经提出就得到了建设群里面全体成员的同意,大家按照这个方案很快就建立起了秩序。在团体里面,除了那种两三个人的小团体,一般都要建立这种分工,因为分工可以提高效率,至少不会无缘无故的吵架,然后吵不出结果。

我在维护组里面大概担任了一个运营的职位,然后目前负责技术的同时也可能担任了一个产品的职位。我经常在维护组里面提需求,比如说要多设计一些跳转的页面,要弄一个**的计划等等。那这个时候产品就会内涵我:“当需求不是自己实现的时候,想象力就会飞出天际。”于是我每次提需求的时候就会说:“这功能很重要,再拖下去开往就不行了,你再把这个需求延期下去,我就要死了。”但事实上,技术,包括中文博客列表导航那边的技术,都挺会咕咕的。中文博客列表导航那里有个功能“统计图表”就拖了几个月。

那有的时候我们也会一起给我们维护组的设计晓雨提需求,提有关页面设计的需求。就最近新版的页面的讨论我因为在学校所以没有参与,但是回到家之后,看他们的聊天记录,感觉就是讨论还是挺频繁的。晓雨做出来一版,然后就被要求改一版。那当我们讨论有关新的跳转页面的需求的时候,大家都非常活跃,除了我们维护组的前端。这个场面用我们那位负责开发的人说的话说,就是“当后端在讨论要如何优化前端的时候,整个办公室都会洋溢着快乐的氛围”。

我们维护组里面也有互怼。之前因为我审核网站比较慢,然后就被那位负责开发的全都给审了。

“你把网站审了干嘛?”
“没有,我就审了超过30天的。”
“不是,超过30天的才能审啊。”
“就看他们呆的太久,就把他们审了。”

那位技术后来还说他一个人每周花个十分钟就可以干完。我就求他这种事情还是留给我来干,毕竟我不会编程,在项目里面也可能做不了什么事情。

最近他帮开往弄了一个能够检测网页有没有挂上开往链接的脚本,我就在后端的仓库里面提一个issue说有些网站被他误判了,那个issue被直接打回。

有些事情写成文字可能就变样了,还是得用脱口秀的方式讲出来。目前不得不承认的是,开往是一个开放、需要群策群力的项目。之后可能会在各种各样的平台发一些有关维护组内部的一些聊天,像今天这样整篇文章都在讲一个项目的个人还是不太受得了,希望之后可以将开往内部的一些讨论分享出来,让大家了解,这是一个有趣的维护组,有趣的小团伙。

分类
网站

Umami 统计服务即将暂停

最近,网站的Umami频繁出现报错,因为数据库原因我们没有办法进行版本更新。在接下来的两个月里,我们会尽量保证其稳定运行,但无法保证其发生让我们力不从心的情况。请各位使用本Umami服务的站长做好更换数据统计服务的准备。

分类
网站

博客聚合项目盘点

推荐阅读:谈谈几个博客聚合网站,以及个人推荐

随着个站商店也弄出了虫洞功能,目前已经有很多的博客聚合项目。本文尝试对他们进行收集。

寻我是一个收录了博客并对博客的订阅地址进行爬取的项目,在这个项目上面,你可以看到有哪些博客新发布了哪些文章。

中文独立博客列表是一个建立在GitHub上的项目,它收集了中文独立博客和播客,并将其在一个网站上面对订阅地址进行爬取。在博客主之间,还是比较有名的。

博客志从2002年来每年都会收集一些优秀的博客,追求宁缺毋滥的原则。

博客联盟是博客主们的联盟。(最近好像论坛出了问题,404了)在一两年前,有一个得到他支持的学生博客联盟,现在不知道到哪里去了。

BlogFinder也是一个以抓取订阅地址功能为主的博客聚合项目,维护者仅为一个人。项目里面有类似读书旅游之类的阅读精选,可以查看相关话题的相关博文。

十年之约刚开始是一群博主建立的要让博客持续更新十年的一个条约,同意并承诺可以遵守这个条约的博主便可以加入这个博主联盟。目前,十年之约弄出了类似于开往的虫洞功能(但与开往不同的是,十年之约成员没有被要求添加虫洞的链接,正如虫洞的未知性一样,这个链接可以是像开往一样双向的,也有可能是单向的)十年之约还弄出了论坛。

个站商店听说维护者也是一个人,代码、审核以及日常的运维工作全部由一个人来实在太不容易。这个项目既收集网站,又爬取订阅地址,还有论坛功能。目前,个站商店又新推出了虫洞功能,与十年之约的虫洞类似,这种链接可以是双向的,也可以是单向的。

GoTo这个项目起初想模仿开往,但最近正在开发类似中文博客搜索引擎的东西。他们项目组里面的大部分人是中学生,多多少少有些不方便。目前,他们与开往有差异的东西就是,他们不仅仅跳转到网站的首页,还可以通过爬虫的爬取跳转到网站的内页。另外,他们目前有着开往没有的管理后台和应用程序接口。

博客搜索网是一个比较接近于中文博客搜索引擎的东西,它可以通过订阅地址来爬取博客的博文,目前负责维护的也是一个人。

中文博客列表导航是一个项目,我就不方便再多介绍。里面有博客的架构统计图表和域名统计图表。收录门槛很低,可以勉强用来发现一些冷门的博客。

开往原本是因为某一个博客程序没有友链功能而开发出来的项目,它要求开往成员必须添加开往的链接。根据开往成员的反馈,开往已经成为一些网站的主要流量来源。

萌国ICP备案是一个名为萌国的国度的ICP备案。(至于那个国家在哪里,我们不知道)一些萌萌的博客可以申请萌国ICP备案,备案的博客一般都有二次元的色彩。

BlogWe是一个博客列表项目,收集博客网站,不过最近审核情况好像不太好,已经堆了800多个待审核的博客。

小熊导航是一个博客导航项目,收集博客网站,新建于2022年12月,是一个很年轻的项目。

对于这些博客聚合项目,越来越多肯定有利于将博客连接到一起,那如果将这些项目放到一起观察,会发现“有大部分的博客聚合项目的功能是相同的”,一些博客聚合项目还在开发别的功能。我们就以博客跳转项目为例,更多的博客跳转项目可以给博主更多的选择,这固然没错。但这是否会像 GoTo 刚开始一样沦落于开往的竞争?我们在以博客列表项目为例,有很多的博客列表项目刚开始都将大量的时间投入到收集博客和添加博客中,我们能否避免在重复添加博客上浪费的时间和精力,从而花更多的时间去完善每个项目应该做出差异化的东西?

我个人能力比较有限,如果还有没有收集到的博客聚合项目,请评论,谢谢。

分类
网站

中国境内个人博客网站相关政策收集

我主要通过公安机关互联网站安全管理服务平台来查找政策文件,并按照“评论留言”“文章版权与合规”和“网络安全与信息保护”三方面进行分类,明确博客网站站长在各方面应尽到的主体责任,本文也尽力给出有关问题的解决方案。

评论留言

博客网站是具有舆论属性或社会动员能力的网站平台,其中,评论留言功能属于跟帖评论服务,理应遵守《互联网跟帖评论服务管理规定》(2022年12月15日起施行)。根据该规定,博客站长(即跟帖评论服务提供者)应尽到以下责任:

  • 对评论留言先发后审
  • 对跟帖评论服务使用者(评论留言作者)进行基于移动电话号码、身份证件号码或者统一社会信用代码等方式的真实身份信息认证

网传,公安交互式备案要求(目前没有找到相关公开的政策文件):

  • 收集评论者的IP地址、端口号、精确到秒的评论时间,并保存不少于6个月的时间

评论留言的内容版权问题可能会使博客站长卷入版权纠纷,例如因用户评论侵权:卢松松收到法院传票索赔6000元

WordPress有一个名为公安备案(作者:杨景文)的插件,安装并启用后即可收集并存储评论者的IP、评论时间、端口号。在“设置——讨论”中可以设置“评论必须经人工批准”。有条件的站长可以使用腾讯或者百度的文本内容审核接口。

文章版权与合规

《关于规范网络转载版权秩序的通知》(国版办发【2015】3号)中需要注意的内容如下:

  • 一、互联网媒体转载他人作品,应当遵守著作权法律法规的相关规定,必须经过著作权人许可并支付报酬,并应当指明作者姓名、作品名称及作品来源。法律、法规另有规定的除外。
  • 三、互联网媒体转载他人作品,不得对作品内容进行实质性修改;对标题和内容做文字性修改和删节的,不得歪曲篡改标题和作品的原意。
  • 四、《著作权法》第五条所称时事新闻,是指通过报纸、期刊、广播电台、电视台等媒体报道的单纯事实消息,该单纯事实消息不受著作权法保护。凡包含了著作权人独创性劳动的消息、通讯、特写、报道等作品均不属于单纯事实消息,互联网媒体进行转载时,必须经过著作权人许可并支付报酬。

目前,CC0之类的协议在国内是否被承认仍有争议,请各位在引用、转载的时候严格遵守《中华人民共和国著作权法》。

根据《中华人民共和国著作权法》(2020年11月11日第三次修正),以下情况可以不经著作权人许可,不向其支付报酬,但应当指明作者姓名或者名称、作品名称,并且不得影响该作品的正常使用,也不得不合理地损害著作权人的合法权益(节选):

  • 为个人学习、研究或者欣赏,使用他人已经发表的作品
  • 为介绍、评论某一作品或者说明某一问题,在作品中适当引用他人已经发表的作品

根据《网络信息内容生态治理规定》(2020年3月1日起施行),网络信息内容生产者不得制作、复制、发布含有下列内容的违法信息(节选):

  • 反对宪法所确定的基本原则的
  • 危害国家安全,泄露国家秘密,颠覆国家政权,破坏国家统一的
  • 损害国家荣誉和利益的
  • 歪曲、丑化、亵渎、否定英雄烈士事迹和精神,以侮辱、诽谤或者其他方式侵害英雄烈士的姓名、肖像、名誉、荣誉的
  • 煽动民族仇恨、民族歧视,破坏民族团结的
  • 破坏国家宗教政策,宣扬邪教和封建迷信的
  • 散布谣言,扰乱经济秩序和社会秩序的
  • 散布淫秽、色情、赌博、暴力、凶杀、恐怖或者教唆犯罪的
  • 侮辱或者诽谤他人,侵害他人名誉、隐私和其他合法权益的

该规定对于鼓励创作的内容、抵制创作的内容有着详细的说明,请各位博主阅读该规定,对自己的文章内容进行整改。

网络安全与信息保护

在信息保护方面,《全国人民代表大会常务委员会关于加强网络信息保护的决定》(2012年12月28日通过并施行)有以下规定:

  • 网络服务提供者和其他企业事业单位收集、使用公民个人电子信息,应当公开其收集、使用规则。(发布隐私政策)
  • 网络服务提供者和其他企业事业单位应当采取技术措施和其他必要措施,确保信息安全,防止在业务活动中收集的公民个人电子信息泄露、毁损、丢失。

《中华人民共和国个人信息保护法》(2021年11月1日起施行)第二章第一节第十七条也有类似告知个人信息相关事项的要求。请各位博客站长发布隐私政策,告知博客网站处理个人信息的相关事项,当中应该包括:

  • 个人信息处理者的名称或者姓名和联系方式
  • 个人信息的处理目的、处理方式,处理的个人信息种类、保存期限
  • 个人行使本法规定权利的方式和程序

《中华人民共和国网络安全法》(2017年6月1日起施行)规定“网络产品、服务的提供者应当为其产品、服务持续提供安全维护”。请各位博客站长检查是否给网站装上防火墙。