使用 Shell - 仍然解析 Twitter 流

作者:Dave Taylor

上个月,您应该还记得我们在 Twitter 流解析程序中迈出了重要一步,即实际解析传入的消息并去除引号和其他 HTML 噪声。 我还重新发布了 send-tweet 脚本,我们将在本月使用它。

tweet-parser 面临的最大挑战是知道哪些消息已经回复过,哪些消息是上次程序运行后才有的新消息。 解决方案? 回头调整一下原始脚本。 事实证明,每条推文都有一个唯一的 ID 值,您可以在这里看到

<id>2541771</id>

您会记得在脚本的早期,我们有这个 grep 命令

grep -E '(<screen_name>|<text>)' | \

很简单。我们将调整它以包含|<id>并获取该值。当然,事情没那么简单。 事实证明,Twitter 的 XML 数据中出现了两个 <id> 字符串:一个是发送消息的帐户的 ID,另一个是消息本身的 ID - 两者都方便地标记为相同。 哎!

时间戳和棘手的 XML

我可以抱怨并希望 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

漂亮! 它简单、直接,并且非常值得我们已经完成的预处理工作。

使用包含的 ID

事实上,我对我的 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 上找到。

加载 Disqus 评论