此为历史版本和 IPFS 入口查阅区,回到作品页
iyouport
IPFS 指纹 这是什么

作品指纹

如何从推特挖掘情报(1):一个流行工具的具体介绍

iyouport
·
  • 多玩几次就能很熟练了

这里不是对于该工具的第一次介绍,因为它真的很流行;比如下面:

以及其他。

是的,它就是 Twint。

我们已经讲述了一整年,所以本文将假设您对开源情报调查已经有所了解(如果您还不了解,可以参见这篇文章《开源调查应该是一种心智:得到它你需要几个步骤》;以及整个“开源情报”类目)。

这就是基本需求,没有更多了。

Twint 项目可以在这里找到。

其实有很多有关 Twint 的文章在网上,但是这些文章只是解释了如何使用它来刮取一些推文。虽然没什么问题,但是,这只是其中一个步骤而已 —— 并非全部功能。

本文将以几个完整的调查周期来展示 Twint,以帮助您理解如何最大程度地使用它,因为每个功能都值得使用。

在开始之前

做开源情报调查几乎就像在玩乐高积木一样,每个人都可以从相同的拼接开始,其结果取决于您的积木。

并没有终结者一般的超级数据库或工具,这里只有您、您的头脑和您手边的基本工具。

事实上这正是使开源情报调查极具魅力的原因。

1、基本用法

覆盖一些示例,以帮您了解如何处理 Twint。

01 用户名+标签

通过此代码段,您将获得noneprivacy发送的包含#osint主题标签的每条推文。

import twint

c = twint.Config()
c.Username = "noneprivacy"
c.Search = "#osint"

twint.run.Search(c)

02 关注者/关注的人

下面的代码段将刮擦用户名为 Twitter 的每个关注者,要得到每个他关注的人,只需把最下面那行换成 twint.run.Following(c)。

import twint

c = twint.Config()
c.Username = "twitter"

twint.run.Followers(c)

请考虑到 Twitter 在阻止抓取工具方面做得很好,因此,您可能无法获得所有关注者/关注对象。在这种情况下,使用 Twitter API 来获取数据肯定没错。

请记住,在侦察阶段中,您很可能会使用其他工具(侦查工具太多了铺天盖地,这些年很多开发者都在投入对社交媒体情报的挖掘能力)。于是,如果某个工具无法返回预期的结果或无法正常工作,请使用其他适合您需求的工具 —— 工具多也是有好处滴。

2、实践

到目前为止,基本脚本已经足够,您可以在Wiki中找到其他示例。

假设这里想要获取一个名为 target 的用户的关注者,并且抓取限于拥有1000个关注者及以上的用户。

步骤是首先获得所有 followers, 然后从中提取具有1000个关注者及以上的用户。

那么就是这样的:

import twint

# get the followers first
c = twint.Config()
c.Username = "target"
c.Store_object = True
c.User_full = True

twint.run.Followers(c)

# save them in a list
target_followers = twint.output.user_object

# iterate over them and save in a new list
K_followers = []

for user in target_followers:
    if user.followers >= 1000:
        K_followers.append(user)

# now we can save them in an CSV file, for example
with open('K_followers.csv', 'w') as output:
    output.write('id,username,followers, following\n')
    for u in K_followers:
        output.write('{},{},{},{}\n'.format(u.id, u.username, u.followers, u.following))

这是一个非常简单的示例,它之所以如此“特别”,是因为它遵循了开源情报调查的三个基本步骤

  • 定义侦查目标,以及想要实现的目的;
  • 获取需要的信息;
  • 分析和过滤获得的数据。

在这一点上,应该深入研究这些关注者,例如获取其推文、并提取使用量最高的10个主题标签 —— 这些是重要的情报线索。

来看看怎么样。

3、提取前N个标签

现在继续前面的示例。在这种情况下,您已经有了一个用户列表,如果长度小于27,则可以使用一个查询。甚至可以生成各种流程来加快抓取过程。

import twint

custom_query = ""
hashtags = {}

with open('K_followers.csv', 'r') as input:
    # we can ignore the first row
    input.readline()
    line = input.readline()
    while line:
        user = line.split(',')[1]
        hashtags.update({user: {}})
        custom_query += "from:{} OR ".format(user)
        line = input.readline()
    custom_query = custom_query[:-4]

c = twint.Config()
c.Custom_query = custom_query
c.Store_object = True
c.Store_csv = True
c.Output = "tweets.csv"

# we want to hide the output, there will be a lot of tweets and the terminal might crash
c.Hide_output = True

twint.run.Search(c)

tweets = twint.output.tweets_object

# now we have all the tweets, let's elaborate the data

# first iterate over the tweets
for t in tweets:
    # then iterate over the hashtags of that single tweet
    for h in t.hashtags:
        # increment the count if the hashtag already exists, otherwise initialize it to 1
        try:
            hashtags[t.username][h] += 1
        except KeyError:
            hashtags[t.username].update({h: 1})

# now save the data
with open('hashtags.csv', 'w') as output:
    output.write('username,hashtag,count\n')
    for user in hashtags:
        for h in hashtags[user]:
            output.write('{},{},{}\n'.format(user, h, hashtags[user][h]))

现在已经获取了数据并对其进行了过滤,您必须对其进行分析,以获取有关调查目标的更多信息,从而对其进行分类。

为此,可以制作一个条形图,例如,查看每个单个标签在每个单个用户中所占的百分比。

另外,您可以看到被共享次数最多的标签,以查看您的调查目标是否属于某个“社区”。

请注意:这也是喜欢玩连锅端的追踪者常用的思考方式。

4、那些社区在谈论什么?

要识别社区,仅凭标签是不够的。

您需要获取用户之间的交互;例如,谁回答谁、谁提到谁,等等。

假设发现有一些用户似乎属于同一社区,因为他们几乎使用相同的 #标签。那么现在要实现的目标就是扩大这个圈子到其他用户。

import requests
import twint

custom_query = ""
mentioned = {}
replied = {}

mentions = ['mention1', 'mention2', 'mention3']
replies = ['reply1', 'reply2', 'reply3']

for m in mentions:
    mentioned.update({m: {}})
    custom_query += "@{} OR ".format(m)
custom_query = custom_query[:-3] # -3 because we want to leave a space

for r in replies:
    replied.update({r: {}})
    custom_query += "to:{} OR ".format(r)
custom_query = custom_query[:-4]

# Twint setup here
c = twint.Config()
c.Custom_query = custom_query
c.Store_object = True
c.Store_csv = True
c.Output = "tweets_mentions_replies.csv"

# we want to hide the output, there will be a lot of tweets and the terminal might crash
c.Hide_output = True

twint.run.Search(c)

tweets = twint.output.tweets_object

# now iterate over the tweets to do a bit of statistics
# we will determine the most mentioned users
# and the user that got the most replies
for t in tweets:
    # iterate over the mentioned users
    for m in t.mentions:
        try:
            mentioned[m]['count'] += 1
        except ValueError:
            mentioned.update({m: {'by': t.username, 'count': 1}})

    # we don't have the user which we reply in the tweet object, tweet
    # but from the tweet ID we can get redirected to the original URL
    # and from the URL, extract the username

    _reply_to = requests.get('https://twitter.com/statuses/{}'.format(t.conversation_id)).request.path_url.split('/')[1]
    try:
        replied[_reply_to]['count'] += 1
    except KeyError:
        replied.update({_reply_to: {'by': t.username, 'count': 1}})
    print('.', end='', flush=True)

# and now save to CSV for further analysis
actions = {'mentioned': mentioned, 'replied': replied}
for a in actions:
    action = actions[a]
    with open('{}.csv'.format(a), 'w') as output:
        output.write('author,{},count\n'.format(a))
        for user in action:
            output.write('{},{},{}\n'.format(action[user]['by'], user, action[user]['count']))

现在查看 mentioned.csv 和 replied.csv,将能够看到谁提及最多,谁得到了最多的提及,对于回复也是如此。

例如,如果有两个用户既是被提及最多的人、又是提及他人最多的人,就可以推断出它们是讨论的核心。

5、一致性

数据的一致性具备所有推文都包含特定的主题标签、和/或关键字的事实。

怎么才能知道数据集是一致的?因为它是 Twitter 本身为搜索查询返回的数据,所以一切都取决于您是否为调查目标确定了正确的查询范围。

因此,再次强调,确保要寻找的是您所需要的,反之亦然。

6、准确性

最常用的词正是我们所寻找的词,做到这一事实就是准确性。

是啊,但是?

这不是一环循环。您可以提取其他最常用的词并重新运行脚本。

“最”这个字或多或少是相对的,不要误解,例如,您不需要提取使用率最高前三个词。您必须选择“具有统计意义”的字词;意思是,如果使用的三个词的出现率约为2%,那就算了吧,因为出现率太小了。

但是在执行此操作之前,您必须过滤数据集,例如 不要计算文章、名词、代词、和“太笼统”的单词。这些通常称为“stop words”。

说起来好像有点复杂,但是,稍微玩一下您就能掌握,并且可以增加很多信心。

请使用 Twitter 高级搜索进行一些测试,以了解有关用于排除或包含特定单词的运算符的更多信息。您可以在这里回顾推特运算符的使用:《从推特中挖掘真相不需要太复杂的工具:一个常用工具的全面指南》。

您还需要更改代码。强烈建议您对Python脚本编写有一定的信心。

如何建立查询

在前面的示例中,我们始终假定查询正确,即 该查询返回了所需的数据。但是,如何构建查询呢?

有些时候指定几个标签和/或关键字可能就足够了。例如,如果要想挖掘有关开源情报的推文,则搜索“ #OSINT” 就足够了。对于其他字段(如信息安全、隐私 等等)也是如此。

如果您想要挖掘经常被一个或多个主题标签标识的社区网络(并假设对此一无所知),首先,可以使用OR运算符搜索这些标签,在最高百分比中提取用户名,然后搜索提及这些用户或回复这些用户的推文。

这样一来也许很快可以确定覆盖主要角色的用户。

深入分析和研究图表的“方向性”,可以区分四种主要角色:

  • 创造了新内容的人;
  • 谁提到了谁;
  • 谁在答复;
  • 谁在转发。

您可以在具有四个级别的树形图中绘制交互关系。首先放置创建内容的用户,然后转到最后放置转发者的位置。

还可以更深入一些,但是本文的目的不是解释社交媒体/网络分析。这里的主题是调查,于是下面还需要识别交互网络,所以分析就到此为止了。

对开源情报有用的查询

幸运的是,在这种情况下,由于大多数人通常会搜索详细的信息,以便:

  • 将该帐户与其他社交圈中的其他人联系起来;
  • 以及,发现联系方式和其他多汁的情报。

所以无需更多解释。

1、将Twitter帐户连接到其他社交网站

可以只搜索包含完整域的推文;但由于 Twitter 有字符限制,因此也需要搜索缩短的URL。然后分析数据。

以下是完整和缩短URL的有用列表:

Facebook:

  • facebook.com;
  • fb.me;
  • on.fb.me.

Youtube:

  • youtube.com;
  • youtu.be.

Instagram:

  • instagram.com;
  • instagr.am;
  • instagr.com.

Google:

  • google.com;
  • goo.gl.

Linkedin:

  • linkedin.com;
  • lnkd.in.

Instagram 的案例

import twint

# get the followers first
c = twint.Config()

c.Store_object = True
c.Username = "target"
c.Search = "\"instagram.com\"" # "instagram.com" = the tweet must contain this word
# we might add other keywords to scrape only one search
# c.Search = "\"instagram.com\" \"fb.me\"", the tweet must contain at least one of two

twint.run.Search(c)

# let's analyze the data
# I'll go straight to the content, and you'll see why
tweets = twint.output.tweets_object

links = []

for tweet in tweets:
    text = tweet.text.split(' ')
    for t in text:
        if t.startswith('instagram.com'):
            links.append(t)

ig_users = {}
for l in links:
    l = l.replace('instagram.com/', '') # clean up the data
    l = l.split('?')[0] # remove tracking codes, like ?igshid=1x89qxivizphf
    slashes = len(l.split('/'))
    user = l.split('/')[0]
    try:
        ig_users[user] += 1
    except KeyError:
        ig_users[user] = 1

# now let's get some rank and let's see the top 5 users
import operator

i = 0
sorted_users = dict(sorted(ig_users.items(), key=operator.itemgetter(1), reverse=True))

for s_user in sorted_users:
    if i == 4:
        break
    print('User: {} | Rank: {}'.format(s_user, sorted_users[s_user]))
    i += 1

现在,如果您看一下输出,您会发现p /的计数很高。事实证明 p / 不是一个用户,而是代表指向用户特定帖子的 link。

就此可以推断出,如果 Twitter 用户分享了包含 instagram.com/p/ 的链接,那么他/她正在共享的是一个帖子。否则他/她分享的是一个 Instagram 用户。

基本上,假设您要搜索分享了 Instagram 帖子的 Twitter 用户,则需要在查询上做一些优化,比如这样 c.Search = "\"instagram.com/p/\"".

随之而来的是,如果您要搜索分享了一个特定链接的帖子的用户,那么就是这样 c.Search = "\"instagram.com/p/postID\"".

同样,如果您要搜索分享了链接到特定 Instagram 帐户的用户,就是这样 c.Search = "\"instagram.com/accountName\"".

共享ID几乎是唯一的,因此,如果两个用户共享了具有相同ID的 Instagram 帖子的链接,则它们之间可能会发生强烈的交互。或者他们甚至可能是同一个人的两个分身。

从简单的信息(如域名)开始获取所需的更多信息,获取数据,进行过滤和分析。在对其进行分析时,第一个一般范围信息分为两类:用户和帖子。

知道了这一点现在就可以进行更多丰富的查询,从而请求更详细的数据。

此方法在 Facebook 上会非常有效。下面是一些示例。

YouTube 示例

Youtube 不像 Instagram,当用户将其 Twitter 帐户连接到 Youtube 时,就会泄漏更多信息。

您可以搜索有关点赞的视频、甚至对某个目标视频发表评论的用户的推文,或者仅仅是分享该视频的推文。

在进入脚本之前,需要先搜索您真正想要的内容。因此,在第一阶段,需要了解以下模式:

  • 点赞了视频的推文;
  • 分享了视频的推文;
  • 评论了视频的推文。

1、点赞的视频

用这个来查找: "youtu.be" "youtube.com" "Liked on YouTube".

你会第一眼看到 Liked on YouTube,这里有视频的标题。

此信息非常有用,因为如果由于某种原因删除了该视频,您仍然可以知道用户点赞了的视频,因此可以在其他平台中搜索该视频。

您也可以应用反向搜索,例如,如果要搜索点赞了特定视频且使用了缩短网址的用户,那么就这样 https://youtu.be/wcLiJHz3JRc” “Liked on YouTube。

2、分享的视频

如果仅搜索缩短网址,例如这样 “https://youtu.be/wcLiJHz3JRc”;你会看到一种特定的模式,其中包含一些随机文本,缩短的URL,然后是 “via @YouTube”。

由于文本几乎是随机的,因此我们将搜索静态部分。所以查询是 "youtu.be" "youtube.com" via @YouTube.

反向查询是 https://youtu.be/3z9sq9e5iu4 via @YouTube.

如果您不知道视频的网址,但是有几个关键字可以让您猜测视频的名称,那么,只需将它们放在查询中即可,但请注意,这与搜索 "keyword1 keyword2" 和keyword1 keyword2完全不同。

多玩一会就能对布尔搜索充满信心了。

3、评论过的视频

via @youtube "Check out this comment".

您能看到这个搜索与发布的评论有关,而不是视频。我希望将其重定向到视频,但我尝试的链接返回了404。运气不好。

Facebook 示例

无论如何,直接搜索和反向搜索均有效。

  • userID/posts/postID
  • username/posts/postID
  • story.php?story_fbid=postID&id=userID;
  • permalink.php?story_fbid=postID&id=userID;
  • events/eventID 。

也许还有其他一些,但即使是大多数情况下,仅凭这些也就足够了。

如果不知道 postID,那么可以拆分该网址,然后搜索,这样:"facebook.com/story.php" "&id=userID".

Google 和 Linkedin

Google 和 Linkedin 通常会在网址末尾附加一个类似哈希的内容,因此这里也没有模式。但是仍然可以对链接进行直接和反向搜索。

很多时候都可以使用为 Instagram 编写的相同代码,而无需进行任何更改。

发现联系方式

在这种情况下,您几乎可以使用所需的每种组合,以下有几种:

  • "@gmail.com",和/或其他电子邮件服务;
  • [at]gmail[dot]com,和/或其他电子邮件服务;
  • "contact us";
  • "hotline" "contact",人们有时会提起 Whatsapp 或其他IM服务的联系人;
  • 先前示例的其他各种组合。

Keybase 允许您验证自己拥有的 Twitter 帐户,通过 Keybase 给您发送的定制推文进行验证。也许它并不流行,但是它可能有用。

因为在 Keybase 上,您可以验证其他社交网络上其他帐户的所有权,并添加一个PGP密钥,其中可能包含电子邮件地址。

要提取电子邮件地址,您可以使用此代码段;link to the gist

import requests, base64, re, sys

r = requests.get("https://keybase.io/" + sys.argv[1] + "/key.asc")
body = r.text.split("\n\n")
key = body[1].split("-----")

for email in re.findall(r' <(.*?)>', str(base64.b64decode(key[0]))):
    print(email)

活动分析

确定一个用户(或更多用户)的每日和每周活动。

给定一个时区,您可以通过查看目标对象的活跃时间来估算目标所在的时区。

为了简化此操作,您可以使用 Excel 或 Kibana。在第一种情况下,您将需要从 Time 字段中“提取”小时,并从 date 字段中“提取”星期几。

建议您在必须处理大量推文时使用 Kibana。

最后

就是这样!这是是挖掘推特情报的第一部分内容。后面将介绍其他角度的玩法。

如果您有更好的方法,欢迎留言探讨,也许我们可以更新它。玩得开心。⚪️

CC BY-NC-ND 2.0 授权