使用 Shell - 仍然解析 Twitter 流
上个月,您应该还记得我们在 Twitter 流解析程序中迈出了重要一步,即实际解析传入的消息并去除引号和其他 HTML 噪声。 我还重新发布了 send-tweet 脚本,我们将在本月使用它。
tweet-parser 面临的最大挑战是知道哪些消息已经回复过,哪些消息是上次程序运行后才有的新消息。 解决方案? 回头调整一下原始脚本。 事实证明,每条推文都有一个唯一的 ID 值,您可以在这里看到
<id>2541771</id>
您会记得在脚本的早期,我们有这个 grep 命令
grep -E '(<screen_name>|<text>)' | \
很简单。我们将调整它以包含|<id>并获取该值。当然,事情没那么简单。 事实证明,Twitter 的 XML 数据中出现了两个 <id> 字符串:一个是发送消息的帐户的 ID,另一个是消息本身的 ID - 两者都方便地标记为相同。 哎!
我可以抱怨并希望 Twitter 修复其 XML 以包含 USERID 或类似内容,但那有什么意义呢? 他们对重载的 <created_at> 标签也有同样的问题,所以我们必须硬着头皮接受我们现在从 XML feed 中抓取四个数据字段,但我们只关心其中的三个。
一旦我们知道我们将有四个输出行,周期性地,我们可以简单地决定哪些是真正重要的,并在 awk 语句中调整它们
$curl -u "davetaylor:$pw" $inurl | \ grep -E '(<screen_name>|<text>|<id>)' | \ sed 's/@DaveTaylor //;s/ <text>//;s/<\/text>//' | \ sed 's/ *<screen_name>//;s/<\/screen_name>//' | \ sed 's/ *<id>//;s/<\/id>//' | \ awk '{ if (NR % 4 == 0) { printf ("name=%s; ", $0) } else if (NR % 4 == 1) { printf("id=%s; ",$0) } else if (NR % 4 == 2) { print "msg=\"" $0 "\"" } }' > $temp
这是一个相当复杂的序列,所以让我们仔细看看 awk 条件语句。 我们有四个输入记录(行)要逐步处理。 NR 的值是到目前为止处理的记录数。 因此,如果 NR mod 4 等于 0,则它是四个记录(行)中的第一个。 第一个记录是名称值。
你有没有看到两行有 printf,第三行使用了一个更简单的 print 语句? 因为我们希望每个变量集都在单独的一行上,所以我们使用 print 语句,因为它会自动将换行符附加到输出。 当然,也可以通过将换行符作为格式字符串传递给 printf 来实现相同的效果。 示例输出如下
name=thattalldude; id=6507045947; msg="Rates?" name=KateC; id=6507034680; msg="hours" name=pbarbanes; id=6507033698; msg="thanks" name=jodie_nodes; id=6507022063; msg=" $$?" name=KateC; id=6507019757; msg="price" name=tarahn; id=6507008559; msg="impact" name=GaryH2UK; id=6507004771; msg="directions"
我们将再次逐行地将这些变量传递给 eval 语句,以设置三个变量:name、id 和 msg。 然后,这是一个简单的解析问题,将 msg 与我们已知的查询进行比较。 基本上,这就是我们上个月所做的,只是这次,每条推文都有一个唯一的 ID 值与之关联。
一个典型的测试现在可能看起来像这样
if [ "$msg" == "hours" ] ; then echo "@$name asked what our hours are in tweet $id" fi
漂亮! 它简单、直接,并且非常值得我们已经完成的预处理工作。
事实上,我对我的 Twitter 流运行它(在要求人们向我发送示例查询后),这就是我所看到的
@TheNose100 asked what our hours are in tweet 6507436100 @crepeauf asked what our hours are in tweet 6507187325 @jdscott asked what our hours are in tweet 6507087136 @KateC asked what our hours are in tweet 6507034680 @inspiremetoday asked what our hours are in tweet 6506966654
我敢打赌您可以看到从这里如何继续。 我们编写静态响应,根据需要计算值,并使用 send-tweet 回复用户
$tweet "@$name our hours are Mon-Fri 9-5, Sat 10-4."
为了好玩,我让人们发送查询“time”并获取 date 命令的当前输出,只是为了演示它是如何工作的。 这是代码块
if [ "$msg" == "time" ] ; then echo "@$id asked for the time" $tweet "@$name the local time on our server is $(date)" fi
太棒了。 得到了所有,除了我们从哪里开始。 您如何跟踪您已经回复过的推文?
答案并不难。 流从最新到最旧,消息 ID 值由服务器顺序分配,因此我们只需要缓存我们回答所有查询后看到的最新消息 ID 即可。 然后,在后续调用中,将每个查询 ID 与我们已回复的最新查询 ID 进行比较。 如果它们更大,我们需要回复它们。 如果不是,我们已经这样做了。 像这样
if [ "$id" == "$previouslatestid" -o $answered -eq 1 ] ; then echo "already answered query \"$msg\" from $name: skipped" answered=1 else ...
previouslatestid 是缓存的内容。 我们还将捕获当前查询浪潮的最新 ID,如下所示
if [ -z "$latestid" ] ; then latestid=$id # store most recent ID fi
当然,还有一些步骤。 我们需要在脚本开始时获取缓存的值
if [ -f "$lastidcache" ] ; then previouslatestid="$(cat "$lastidcache")" else previouslatestid="0" fi
并且,我们需要在最后保存它
echo $latestid > "$lastidcache"
就这样。 我的空间用完了,但完整的脚本可以在 ftp.linuxjournal.com/pub/lj/listings/issue191/10695.tgz 上找到。 下个月,我们将对其进行润色,看看我们能用 tweetbot 做什么有趣的事情!
Dave Taylor 黑客 shell 脚本已经很长时间了。 他是流行的 Wicked Cool Shell Scripts 的作者,可以在 Twitter 上找到 @DaveTaylor,也可以在 www.DaveTaylorOnline.com 上找到。