如何从推特挖掘情报(1):一个流行工具的具体介绍 - iYouPort
如何从推特挖掘情报(1):一个流行工具的具体介绍
- 多玩几次就能很熟练了
这里不是对于该工具的第一次介绍,因为它真的很流行;比如下面:
以及其他。
是的,它就是 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。
最后
就是这样!这是是挖掘推特情报的第一部分内容。后面将介绍其他角度的玩法。
如果您有更好的方法,欢迎留言探讨,也许我们可以更新它。玩得开心。⚪️
文章版权归原作者所有。