今天试着完善交错战线机器人,两个目标:
- 通过星火大模型 API ,补全空白标题
- 上传图片并使用
补全空白标题
使用讯飞星火提供的官方 API 例程即可。
1 2 3 4 5 6
| def generate_title(content=""): text.clear question = getText("user", content) SparkApi.answer = "" SparkApi.main(appid, api_key, api_secret, Spark_url, domain, question) return str(SparkApi.answer)
|
content 为 “向大模型提问的内容”,在这个情况下,则为 “请你为以下内容想一个标题”;这个函数会返回一段文本,即答案,即给出的标题。
上传文件/图片
我如果要通过 python 上传图片,一是需要注意在上传之前需要发送一个 OPTIONS 请求,二是上传后不会返回任何内容,包括图片 url。
查看了原js,使用的是 XHR(XMLHttpRequest)提交数据。
可以使用 Object.keys() 得到一个 Object 对象的键,例如,对于 变量 asd,可以使用 Object.keys(asd)
得到键,但注意不是通过 asd.keys()
。
在原本的js中,构造了一个 postfunc.thumbBinCache
方便生成图片代码,其中第七个键是完整大小的图片代码。
对于函数 postfunc.add1Attach = function (opt, time, attach,checkSum,url,isimg,thumb,utf8oname,tid,pid,aid)
,有以下注释:
我一直在纳闷 url 参数从何而来。
url 参数被保存在 y.data.url
,其中 y 是 window.script_muti_get_var_store
,即 nga 的网页版页面数据。可以向控制台输入 window.script_muti_get_var_store.data.url
查询 url。
(但是少了个 ./,需要自己加上去)
那么,问题来了,应该如何在没有编辑页面的 python 程序中获取到 url?
根据 api 文档(二哥写的),返回的数据一种形式就是开头有个 window.script_muti_get_var_store =
,得到的数据就这些个格式,但内容肯定是不同的。
但是发帖后获取的返回数据中,有已上传附件、已上传附件验证码(auth)。
地精文档
之前没注意到,光顾着自己尝试了。实际上二哥有详细描述应该如何上传附件。见 https://g.nga.cn/read.php?tid=6406100 的 6.1 和 6.2 节。
值得注意的是,文档是挺久之前写的,实际情况可能有变化。但也可能没变化,只是我搞错了,误以为没有返回数据。
文档中的描述是:
1 2 3 4
| 使用post(enctype=multipart/form-data)方法将如下数据上传至 6.1 中提到的数据中的附件上传地址,上传成功后服务器会返回数据。
将attachments连接至发帖表单的attachments参数末尾(如有多个附件用\t分隔) 将attachments_check连接至发帖表单的attachments_check参数末尾 (如有多个附件用\t分隔)
|
而发贴的时候,应当附带 attachments
附件、attachments_check
附件验证码。
我猜测 6.1 中的附件上传地址指的是一个 url,例如 http://img8.nga.cn/attach.php
之类的。
试了一下
fid=823,nga 的上线游戏讨论区。
我向 https://ngabbs.com/post.php?fid=823&__output=1
发送请求,返回的数据如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| { "data": { "action": "new", "__T": { "topic_misc_var": "" }, "fid": 823, "auth": "【字符串】", "if_moderator": 0, "cost_info": "匿名主题50银币 匿名回复1银币 贴条回复1银币 投票10银币 版主免费 付费会员免费(每月限量)", "tid": "", "__CU": { "uid": 65112288, "group_bit": 98528, "admincheck": 0, "rvrc": 10 }, "__GLOBAL": { "_ATTACH_BASE_VIEW": "img.nga.178.com/attachments" }, "__F": { "bit_data": 167772160, "fid": 823, "name": "上线游戏讨论区" }, "attach_url": "https://img8.nga.cn/attach.php" }, "encode": "gbk", "time": 1710754883, "debug": null }
|
得到的结果中, "attach_url": "https://img8.nga.cn/attach.php"
意思就是我要向这边上传文件,"auth": "【字符串】",
就是我需要附带的附件验证码,否则会被视为违规请求。需要的就是这个。
注意这是需要登录的(废话)。发送请求和其他基本一样,带上 Cookie 即可。
又试了一下
在网页段上传文件时,会发送这么一个 POST 请求:
1 2 3 4 5 6 7 8 9
| window.script_muti_get_var_store = { data: { attachments: 'aid~mvQ2t-64jz~ext~webp~url_utf8_org_name~RJ01078257%5fimg%5fmain%2ewebp~path~mon_202403/18~url_dscp~~size~28538~name~mvQ2t-64jzKsT1kSfk-bo.webp~tmp_file~./temp_attachments/mvQ2t-64jz.webp.tmp~tmp_shoot~./temp_attachments/mvQ2t-64jz.webp.tmp~tmp_shoot_size~28538~tmp_shoot_ext~webp~isimg~1~w~560~h~420~thumb~56', attachments_check: 'e7f78df7942303341cfc34c0947d092a', url: 'mon_202403/18/mvQ2t-64jzKsT1kSfk-bo.webp', isImg: '1', thumb: '56' } }
|
很显然,这是 javascript 生成的表单数据。也就是说,正常流程中发送数据,不会向服务器请求得到附件的 url,反之,是本地生成 url,再发送给服务器。
那么问题来了,本地是如何生成附件 url 的?
按照我的理解,应该是上传文件-图片服务器响应-返回数据中提取对应 url,但我并没有看到相应的响应。
总之就是又试了一次
使用 postman 制造一个请求,成功上传了,并且返回了有效数据:
1 2 3 4 5 6 7 8 9
| window.script_muti_get_var_store = { data: { attachments: 'aid~mvQ2t-3za5~ext~jpg~url_utf8_org_name~image.png~path~mon_202403/18~url_dscp~~size~124647~name~mvQ2t-3za5ZcT3cSlc-w0.jpg~tmp_file~./temp_attachments/mvQ2t-3za5.jpg.tmp~w~768~h~1152~tmp_shoot~./temp_attachments/mvQ2t-3za5.jpg.tmp~tmp_shoot_size~124647~tmp_shoot_ext~jpg~isimg~1~thumb~120', attachments_check: 'c745093860ce606f3fe12c0c3b66e638', url: 'mon_202403/18/mvQ2t-3za5ZcT3cSlc-w0.jpg', isImg: '1', thumb: '120' } }
|
是的,正是之前那些;我理解有误,但无误;这些数据不是本地提交的,是远端发来的。
破案了
在最终提交 post 的时候,需要在 attachments 添加对应的 attachments,而不是 attachments_check,或者 url
这是单张图片提交的情况:
1 2 3 4 5 6 7 8 9 10 11 12
| action: reply fid: 275 tid: 38719308 post_content: [img]./mon_202403/18/7nQ2t-de3sZlT3cSlc-w0.jpg[/img] attachments: aid~7nQ2t-de3s~ext~jpg~url_utf8_org_name~00737%2d2622116886%2dfeaturelessMix%5fv30202312%2epng~path~mon_202403/18~url_dscp~~size~218093~name~7nQ2t-de3sZlT3cSlc-w0.jpg~tmp_file~./temp_attachments/7nQ2t-de3s.jpg.tmp~w~768~h~1152~tmp_shoot~./temp_attachments/7nQ2t-de3s.jpg.tmp~tmp_shoot_size~124647~tmp_shoot_ext~jpg~isimg~1~thumb~120 attachments_check: fd9a4034fe53664a801d79a2dbd9f5c4 nojump: 1 lite: htmljs step: 2
|
这是同时提交两张图片的情况:
1 2 3 4 5 6 7 8 9 10 11
| action: reply fid: 275 tid: 38719308 post_content: [img]./mon_202403/18/7nQ2t-529pZlT3cSlc-w0.jpg[/img] [img]./mon_202403/18/7nQ2t-7v3oZlT3cSlc-w0.jpg[/img] attachments: aid~7nQ2t-529p~ext~jpg~url_utf8_org_name~00737%2d2622116886%2dfeaturelessMix%5fv30202312%2epng~path~mon_202403/18~url_dscp~~size~218093~name~7nQ2t-529pZlT3cSlc-w0.jpg~tmp_file~./temp_attachments/7nQ2t-529p.jpg.tmp~w~768~h~1152~tmp_shoot~./temp_attachments/7nQ2t-529p.jpg.tmp~tmp_shoot_size~124647~tmp_shoot_ext~jpg~isimg~1~thumb~120 aid~7nQ2t-7v3o~ext~jpg~url_utf8_org_name~00737%2d2622116886%2dfeaturelessMix%5fv30202312%2epng~path~mon_202403/18~url_dscp~~size~218093~name~7nQ2t-7v3oZlT3cSlc-w0.jpg~tmp_file~./temp_attachments/7nQ2t-7v3o.jpg.tmp~w~768~h~1152~tmp_shoot~./temp_attachments/7nQ2t-7v3o.jpg.tmp~tmp_shoot_size~124647~tmp_shoot_ext~jpg~isimg~1~thumb~120 attachments_check: 11e98d076d3a6793a4128a1ac62baa51 c593cf08e0b0e1765b727342fcf3f7de nojump: 1 lite: htmljs step: 2
|
可以看到 图片的 attachments 之间并没有使用分号啊逗号啊什么的隔开,只是换行和空格。
2024-03-19 更正:应该是使用 \t 进行分割,而不是使用回车或者空格,这在文档里面写出来了。
总结
完成了,不复杂的一套流程。
整体来说:
- 调用 data_dict_get() 函数,从 api 获取 bilibili 的动态信息,筛选没有转发过的。在 github action 可以表现为每五分钟检测上一个五分钟内的新动态(由于github action每个月份额有限,改成半小时)
- 从调到的字典数据中获取 data_list,即存放动态内容数据的列表
- 考虑到半小时内可能会有多条动态,而 nga 会有 10 秒发帖时间间隔,使用一个循环依次发送帖子(绝大多数情况下只有一个)
- 对于每一个的动态,根据时间戳判断是否是已经发送过;也可以将文件保存到本地,对比新旧文件的差别,判断哪些动态没有被发送过
- 调用 generate_post(data),其中 data 是单条动态的数据。
- 根据 api 回传的信息结构,分析出网页直观看到的内容、tag、图片、视频,并转化为 nga 对应的 bbscode。
- 标题使用讯飞星火的 api 进行生成(因为原动态总是不写标题)
- 图片使用 upload_img() 上传,这个函数接受的参数是一个列表,里面记录每张图的网址,因为一条动态可以有很多图片。使用 upload_one_img() 上传单个图片,使用 post_img() 上传图片,回传生成的图片 url、attachments、attachments_check
- 视频使用 flash=video 标签,不过不同客户端有的可能看不到。
- 一大问题是,有的动态是专栏文章的缩略,只会有一小段内容,然后是 “展开”,对应一个全新的页面。这种情况下的转发我还没弄明白应该怎么做。
- 结束之后,根据发送的帖子数量输出对应的内容。
二哥的代码、文档其实写得很清晰,井井有条。拜他所赐,我这个半吊子也能大致理解上传图片所需要的东西。遇见过的几个问题全是可以通过看文档快速解决的。