概述
就像我在第一篇文章“无需 DLL 的 MT4/MT5 的原生推特(Twitter)客户端”中所承诺的那样;本文将尝试探索 Twitter API,从而能发送带有照片的推文。 为了令本文更容易理解,我仅关注上传图像。 到本文结尾,您应能得到一个可运行的推特客户端,且无需用到任何外部 DLL,这令您可发布最多四张照片的消息。 4 张照片的限制是由 Twitter API 设置,如参数 media_ids 中所述。
上传照片
有一种新方法,称为分块上传,在上传媒体时可用更好的方法来上传较大的文件,譬如视频或 GIF 动画。 出于我们的目的,我将关注简单方法,该方法仅限于仅上传图片。
请确保您已熟知推特的媒体类型和大小限制。
将照片上传到推特只是一个简单的基本 OAuth 授权 HTTP multipart/form-data POST,我将在下个段落中对其进行解释。 已上传的每张照片都将返回一个 media_id,该 ID 仅在一定时间内有效,从而可在要发布的推文里包含它。
为了发布多达四张照片,所有返回的 media_id 都被简单地连接在一起,形成以逗号分隔的列表。
发布带照片推文的步骤如下:
- 上传照片并收集返回的 media_id
- 重复上传更多照片,直达上限。 4 张照片。 始终收集其返回的 media_id。
- 准备您的推文消息
- 发送推文时,请指定 media_id,并在列表里以逗号分隔所有要包含的 media_id。
为了令代码简单易懂,省略了错误处理。
HTTP multipart/form-data
为了将照片上传到推特,可将这些照片作为原始二进制数据或 Base64 编码的字符串上传。 建议将照片作为原始二进制数据上传,因为 Base64 编码的字符串的大小约暴涨三倍。
HTTP multipart/form-data 方法在 RFC-2388 中加以良好定义,但阅读本篇不错指南也许更容易理解。 基本上,从提到的文章中引用:“这是一个 HTTP POST 请求,其发送的请求主体已特别格式化为一个 "parts" 序列,并用 MIME 边界分隔。”
POST /submit.cgi HTTP/1.1 Host: example.com User-Agent: curl/7.46.0 Accept: */* Content-Length: 313 Expect: 100-continue Content-Type: multipart/form-data; boundary=------------------------d74496d66958873e --------------------------d74496d66958873e Content-Disposition: form-data; name="person" anonymous --------------------------d74496d66958873e Content-Disposition: form-data; name="secret"; filename="file.txt" Content-Type: text/plain contents of the file --------------------------d74496d66958873e--
Twitter 类的实现如下:
void appendPhoto(string filename, string hash, uchar &data[], bool common_flag=false) { int flags=FILE_READ|FILE_BIN|FILE_SHARE_WRITE|FILE_SHARE_READ; if(common_flag) flags|=FILE_COMMON; //--- int handle=FileOpen(filename,flags); if(handle==INVALID_HANDLE) return; //--- int size=(int)FileSize(handle); uchar img[]; ArrayResize(img,size); FileReadArray(handle,img,0,size); FileClose(handle); int pos = ArraySize(data); int offset = pos + size; int hlen = StringLen(hash)+6; int newlen = offset + hlen; ArrayResize(data, newlen); ArrayCopy(data, img, pos); StringToCharArray("\r\n--"+hash+"\r\n", data, offset, hlen); }
上面的代码将图像文件的原始二进制数据添加到 HTTP multipart/form-data post 的 “parts” 里。 POST 的 “envelope” 的代码完成如下,并指定了 Twitter Upload-API 参数 “media”。
string uploadPhoto(string filename) { // POST multipart/form-data string url = "https://upload.twitter.com/1.1/media/upload.json"; //string url = "https://httpbin.org/anything"; string params[][2]; string query = oauthRequest(params, url, "POST"); string o = getOauth(params); string custom_headers = "Content-Type: multipart/form-data;" " boundary="; string boundary = getNonce(); StringAdd(custom_headers, boundary); // use nonce as boundary string StringAdd(custom_headers, "\r\n"); string headers = getHeaders(o, custom_headers, "upload.twitter.com"); //string query = getQuery(params, url); //Print(query); uchar data[]; string part = "\r\n--"; StringAdd(part, boundary); StringAdd(part, "\r\nContent-Disposition: form-data;" " name=\"media\"\r\n\r\n"); StringToCharArray(part, data, 0, StringLen(part)); appendPhoto(filename, boundary, data); string resp = SendRequest("POST", url, data, headers);; if(m_verbose) { SaveToFile(filename + "_post.txt", data); Print(resp); } return (getTokenValue(resp, "media_id")); }
为了检查和验证构建的 HTTP multipart/form-data,把 HTTP 请求另外保存在 MT 终端的数据文件夹中,以便进行进一步检查。
带照片的推文
出于简洁起见,我用了一个简单的函数 getTokenValue() 来提取 Twitter Upload-API 返回的 media_id。 您可能会考虑使用出色的 MQL5.com 上提供的 JSON 库。
以下代码展示了一种非常简单使用 Twitter 类的方法。 函数 Screenshots() 简单地捕获当前打开图表的屏幕截图,并构建一条简单的推文消息。 最多能选择四个图表。
每个屏幕截图均保存到文件,其文件名在字符串数组 fnames 里返回。
屏幕截图被逐一上传,收集返回的 media_id,合并的列表则以逗号分隔。
依据上述逗号分隔列表中指定的 media_ids 参数,我们发布带有这些屏幕截图的推文消息,并将这些屏幕截图附加到推文里。
就是如此容易。
CTwitter tw(consumer_key, consumer_secret, access_token, access_secret, verbose); // Gather information string fnames[4]; string msg; Screenshots(fnames, msg); // Upload screenshots int n = ArraySize(fnames); int i = n - 1; // create comma separated media_ids string medias = tw.uploadPhoto(fnames[i]); for(i= n - 2; i>=0; i--) { StringAdd(medias, ","); StringAdd(medias, tw.uploadPhoto(fnames[i])); } // Send Tweet with photos' ids string resp = tw.tweet(msg, medias); Print(resp);
Twitter 类
您可以在 Twitter.mqh 中找到 Twitter 类,其目标是独立于其他包含文件。 若要发送带有照片的推文,这一个文件就能满足您全部需求了。
首先,实例化一个 Twitter 对象,指定您的使用者和访问令牌,并带有一个可选的冗长标志,这有助于在开发过程中进行调试。
CTwitter tw(consumer_key, consumer_secret, access_token, access_secret, verbose);
然后,您可以尝试调用可用的公开函数:
- verifyCredentials()
返回您的访问令牌 Twitter ID
- uploadPhoto()
上传照片,并返回其 media_id
- tweet()
发送带有可选 media_ids 的推文
还有一些辅助函数:
- getTokenValue()
从 json 字符串返回令牌/参数的值。
注意: 这是一个非常简单的字符串解析,不要期望能与 json 完全兼容。
- unquote()
从字符串中删除引号。
在推特上发布您的图表
附件是一个有效的 MT5 脚本,该脚本可捕获多达四个图表的屏幕截图,并构建一条简单的推文消息,其中包含图表的品种和 OHLCV 值。
这是一个简单的示例,是您开始自行研发智能系统和/或脚本的起点。
注意:
您必须指定自己的使用者、访问令牌和密匙。
以下是脚本发送的推文示例。
图例 1. 自 MT5 发送的带照片推文
图例 2. 推特上的全尺寸 MT5 图表
当然,您也可以附加任何照片;)
图例 3. 幸运猫推文
结束语
此处为您提供了一个简单易用的 Twitter 类作为自包含文件,令您轻松发布图表和信号。 还示意了相关的技术细节,希望它们可以很容易就理解。
这个 Twitter 类还远未完工,还有许多其他 Twitter API 会添加到该类之中。 请随时在评论中发表您的改进意见,这都会令 MQL5 社区受益。
我希望您阅读本文时能感到愉悦,就像我写这篇文章时一样。
我也希望您可以用所提供的代码来得到乐趣和收益。
尽享快乐。