将推文与情绪得分相结合可为你提供了一种量化方法来评估推文。若要拉取隐藏在“感受如何”这一问题背后的数据,你可以使用 Python 和 Twitter 的近期搜索端点来浏览过去 7 天的推文,并且可以使用 Microsoft Azure 的文本分析认知服务来检测语言并确定情绪得分。本教程将逐步为你演示如何创建代码来拉取过去 7 天的推文并提供一个得分,从而让你确切地了解自己上周过得怎样。你可以在名为 v2 的文件夹中引用完整版代码。 

 

设置

 

在开始之前,需确保具备以下各项:

 

 

你需要为该项目创建一个字典,这样便可以在终端键入以下内容,从而创建新目录并从当前目录更改为刚创建的新目录。你还将创建一个新的 Python 文件和一个 YAML 配置文件,用于存储令牌和机密。

      mkdir how-positive-was-your-week
cd how-positive-was-your-week
touch week.py
touch config.yaml

    


现在,你便可以使用所选文本编辑器设置配置文件 config.yaml。建议设置该文件,将使用 x 表示的内容替换为自己的不记名令牌和订阅密钥。

 

      search_tweets_api:
  bearer_token: xxxxxxxxxxxxxxxxxxxxxxx
azure:
  subscription_key: xxxxxxxxxxxxxxxxxxxxxxx
    

此外,还需要安装 RequestsPyYaMLPandas 库。Requests 将用于向 Twitter 和 Azure 端点发出 HTTP 请求,Pandas 用于为数据塑形。PyYaML 使你能够解析 .yaml 文件,你的密钥和令牌将存储在此文件中。Pandas 将用于处理数据并为其塑形。

 

打开文件 week.py 并导入所有要使用的库。除了 Requests 和 Pandas 之外,还需要导入 jsonast 的包,这些包是 Python 标准库的一部分,因此无需提前安装。此外,还要使用别名 pd 导入 Pandas,这样才不必在每次调用库时都键入完整的单词。

      import requests
import pandas as pd
import json
import ast
import yaml
    

在连接 Twitter API 之前,需要先设置 URL,确保其中含有正确的字段,以便你获取正确的数据。首先,你需要在该函数中创建一个名为 create_twitter_url 的函数,然后为用户名声明一个变量,你可以使用自己的用户名替换 jessicagarsonmax_results 的范围为 1-100。如果使用的用户名在特定一周内发布的推文数量会超过 100,则建议构建一些逻辑来处理分页,或者使用 search-tweets-python 之类的库。URL 的格式需进行设置,其中应包含结果数量上限以及表明你要查找特定用户名的推文的查询。你将在一个名为 url 的变量中返回经过格式设置的 URL,因为以后需要它才能发出 GET 请求。

      def create_twitter_url():
    handle = "jessicagarson"
    max_results = 100
    mrf = "max_results={}".format(max_results)
    q = "query=from:{}".format(handle)
    url = "https://api.twitter.com/2/tweets/search/recent?{}&{}".format(
        mrf, q
    )
    return url
    


你要创建的 URL 是:
https://api.twitter.com/2/tweets/search/recent?max_results=100&query=from:jessicagarson

 

如果要排除包含媒体文件的转推或推文,可以调整查询。通过向查询添加其他字段扩展即可调整 Twitter API 返回的数据。使用 PostmanInsomnia 等 REST 客户端有助于在开始编写代码之前查看返回的数据并进行调整。对于 v2 端点,同样有一个 Postman 集合

 

设置 main 函数

 

在文件底部,你可以开始设置将要用于调用所创建的所有函数的 main 函数。你可以添加刚创建的函数,并使用 if __name__ == "__main__" 语句调用该函数。

      def main():
    url = create_twitter_url()


if __name__ == "__main__":
    main()

    

验证并连接到 Twitter API

 

要访问在设置 config.yaml 时创建的配置文件,可以定义一个名为 process_yaml 的函数,该函数将读取 YAML 文件并保存其内容。

      def process_yaml():
    with open("config.yaml") as file:
        return yaml.safe_load(file)
    

在 main 函数中,可以将其保存到名为 data 的变量中。现在,main 函数应该有两个变量,一个用于 URL,另一个用于 data

      def main():
    url = create_twitter_url()
    data = process_yaml()

    

要从 config.yaml 文件访问不记名令牌,可以使用以下函数。

      def create_bearer_token(data):
    return data["search_tweets_api"]["bearer_token"]
    

正如之前的操作,你可以在 main 函数中添加一个名为 bearer_token 的变量。

      def main():
    url = create_twitter_url()
    data = process_yaml()
    bearer_token = create_bearer_token(data)
    

要连接到 Twitter API,请创建一个名为 twitter_auth_and_connect 的函数,在该函数中,你将设置标头格式来传入 bearer_token 和 url。此时,你可以使用请求包发出 GET 请求,以连接到 Twitter API。

      def twitter_auth_and_connect(bearer_token, url):
    headers = {"Authorization": "Bearer {}".format(bearer_token)}
    response = requests.request("GET", url, headers=headers)
    return response.json()
    

在此函数中,返回的对象是有效负载,如下所示:

      {'data': [{'id': '1272881032308629506', 'text': '@nomadaisy @kndl I just want to do deals with you'}, {'id': '1272880943687258112', 'text': '@nomadaisy @kndl I live too far away to hang responsibly with y’all 😬😭'}, {'id': '1272711045606408192', 'text': '@Babycastles https://t.co/Yfj8SJAnpG'}, {'id': '1272390182231330816', 'text': '@replylord Haha, I broke a glass in your honor today and all so I think I do read your Tweets'}, {'id': '1271810907274915840', 'text': '@replylord I like that I’m the only like here.'}, {'id': '1271435152183476225', 'text': '@Arfness @ChicagoPython @codewithbri @WeCodeDreams @agfors The video seems to be available https://t.co/GojUGdulkP'}, {'id': '1271111488024064001', 'text': 'RT @TwitterDev: Tune in tonight and watch as @jessicagarson takes us through running your favorite Python package in R. 🍿\n\nLearn how to use…'}, {'id': '1270794941892046848', 'text': 'RT @ChicagoPython: Chicago Python will be live-streaming tmrw night!\n\nOur talks:\n- How to run your favorite Python package in R by @jessica…'}, {'id': '1270485552488427521', 'text': "Speaking virtually at @ChicagoPython's __main__ meeting on Thursday night. I'll be showing how to run your favorite Python package in R. https://t.co/TnqgO80I3t"}], 'meta': {'newest_id': '1272881032308629506', 'oldest_id': '1270485552488427521', 'result_count': 9}}

    

现在,你可以更新 main 函数,使其类似于以下内容:

      def main():
    url = create_twitter_url()
    data = process_yaml()
    bearer_token = create_bearer_token(data)
    res_json = twitter_auth_and_connect(bearer_token, url)
    

生成语言

 

虽然可以使用近期搜索有效负载来获取有效负载中的语言(这里提供了使用此方法的代码版本),但 Azure 还提供了一个可以预计语言的端点。在使用数据之前,需确保数据具有正确形态,才能连接到检测语言端点。因此,你将设置数据格式,使其与 Azure 快速入门指南中概述的格式匹配。为此,请将包含推文和 ID 的被调用数据内部的对象分离为名为 data_only 的变量。你需要设置一些字符串格式,将推文数据转换为正确的格式,还需要设置将其他将字符串转换为字典所需的格式。使用 jsonast 库可以辅助此转换。

      def lang_data_shape(res_json):
    data_only = res_json["data"]
    doc_start = '"documents": {}'.format(data_only)
    str_json = "{" + doc_start + "}"
    dump_doc = json.dumps(str_json)
    doc = json.loads(dump_doc)
    return ast.literal_eval(doc
    

若要连接到 Azure,你将需要设置数据格式,具体方法是按照处理 Twitter API URL 的方式调整 URL。你可以设置 URL,以便从语言和情绪端点中检索数据。你的凭据将从 config.yaml 进行解析,然后传入,供 Azure 端点进行验证。

      def connect_to_azure(data):
    azure_url = "https://week.cognitiveservices.azure.com/"
    language_api_url = "{}text/analytics/v2.1/languages".format(azure_url)
    sentiment_url = "{}text/analytics/v2.1/sentiment".format(azure_url)
    subscription_key = data["azure"]["subscription_key"]
    return language_api_url, sentiment_url, subscription_key
    

此外,你还将创建一个函数,用于创建标头,标头再以发出请求所需的格式传入订阅密钥,从而连接到 Azure。

      def azure_header(subscription_key):
    return {"Ocp-Apim-Subscription-Key": subscription_key}
    

现在,你便可以向 Azure API 发出 POST 请求,为推文生成语言。

      def generate_languages(headers, language_api_url, documents):
    response = requests.post(language_api_url, headers=headers, json=documents)
    return response.json()

    

你应该会收到返回的 JSON 响应,该响应与下面的响应类似。

 

      {'documents': [{'id': '1272881032308629506', 'detectedLanguages': [{'name': 'English', 'iso6391Name': 'en', 'score': 1.0}]}, {'id': '1272880943687258112', 'detectedLanguages': [{'name': 'English', 'iso6391Name': 'en', 'score': 1.0}]}, {'id': '1272711045606408192', 'detectedLanguages': [{'name': 'English', 'iso6391Name': 'en', 'score': 1.0}]}, {'id': '1272390182231330816', 'detectedLanguages': [{'name': 'English', 'iso6391Name': 'en', 'score': 1.0}]}, {'id': '1271810907274915840', 'detectedLanguages': [{'name': 'English', 'iso6391Name': 'en', 'score': 1.0}]}, {'id': '1271435152183476225', 'detectedLanguages': [{'name': 'English', 'iso6391Name': 'en', 'score': 1.0}]}, {'id': '1271111488024064001', 'detectedLanguages': [{'name': 'English', 'iso6391Name': 'en', 'score': 1.0}]}, {'id': '1270794941892046848', 'detectedLanguages': [{'name': 'English', 'iso6391Name': 'en', 'score': 1.0}]}, {'id': '1270485552488427521', 'detectedLanguages': [{'name': 'English', 'iso6391Name': 'en', 'score': 1.0}]}], 'errors': []}

    

我们还建议更新 main 函数,使其包含所创建的新函数。该函数现应类似于如下所示内容。

      def main():
    url = create_twitter_url()
    data = process_yaml()
    bearer_token = create_bearer_token(data)
    res_json = twitter_auth_and_connect(bearer_token, url)
    documents = lang_data_shape(res_json)
    language_api_url, sentiment_url, subscription_key = connect_to_azure(data)
    headers = azure_header(subscription_key)
    with_languages = generate_languages(headers, language_api_url, documents)

    

获得情绪得分

 

你需要将推文数据与包含所生成语言的数据合并到一起,然后才能使用 Azure 的端点生成情绪得分。可以使用 Pandas 来为这一数据转换过程提供协助。可以将采用检测到的语言的 Json 对象转换为数据帧。由于只需要语言的缩写,因此可以执行列表解析来获取包含语言缩写的 iso6391Nameiso6391Name 包含在字典内,而字典在列表内,列表又在含有语言数据的数据帧内。你还可以将推文数据转换为一个数据帧,再将推文语言的缩写附加到该数据帧。然后,将以 JSON 格式发送这些推文数据。

      def combine_lang_data(documents, with_languages):
    langs = pd.DataFrame(with_languages["documents"])
    lang_iso = [x.get("iso6391Name")
                for d in langs.detectedLanguages if d for x in d]
    data_only = documents["documents"]
    tweet_data = pd.DataFrame(data_only)
    tweet_data.insert(2, "language", lang_iso, True)
    json_lines = tweet_data.to_json(orient="records")
    return json_lines
    

与此类似,你将数据转换为字典格式,并在有效负载前面加上单词 documents: 作为关键字,以获取情绪得分。

      def add_document_format(json_lines):
    docu_format = '"' + "documents" + '"'
    json_docu_format = "{}:{}".format(docu_format, json_lines)
    docu_align = "{" + json_docu_format + "}"
    jd_align = json.dumps(docu_align)
    jl_align = json.loads(jd_align)
    return ast.literal_eval(jl_align)
    

现在,数据应采用正确的格式调用 Azure 的情绪端点。你可以向 connect_to_azure 函数中定义的情绪端点发出 POST 请求。

      def sentiment_scores(headers, sentiment_url, document_format):
    response = requests.post(
        sentiment_url, headers=headers, json=document_format)
    return response.json()
    

返回的 JSON 响应应类似于下面的有效负载。

      {'documents': [{'id': '1272881032308629506', 'score': 0.18426942825317383}, {'id': '1272880943687258112', 'score': 0.0031259357929229736}, {'id': '1272711045606408192', 'score': 0.7015109062194824}, {'id': '1272390182231330816', 'score': 0.8754926323890686}, {'id': '1271810907274915840', 'score': 0.19140595197677612}, {'id': '1271435152183476225', 'score': 0.7853382229804993}, {'id': '1271111488024064001', 'score': 0.7884223461151123}, {'id': '1270794941892046848', 'score': 0.8826596736907959}, {'id': '1270485552488427521', 'score': 0.8784275054931641}], 'errors': []}

    

现在,main 函数应类似如下。

 

      def main():
    url = create_twitter_url()
    data = process_yaml()
    bearer_token = create_bearer_token(data)
    res_json = twitter_auth_and_connect(bearer_token, url)
    documents = lang_data_shape(res_json)
    language_api_url, sentiment_url, subscription_key = connect_to_azure(data)
    headers = azure_header(subscription_key)
    with_languages = generate_languages(headers, language_api_url, documents)
    json_lines = combine_lang_data(documents, with_languages)
    document_format = add_document_format(json_lines)
    sentiments = sentiment_scores(headers, sentiment_url, document_format)
    

获取情绪平均分

 

为了获得情绪平均分,可以将来自 Azure 情绪端点的 JSON 响应转换为数据帧,然后计算标题为“score”这一列的平均值。

      def mean_score(sentiments):
    sentiment_df = pd.DataFrame(sentiments["documents"])
    return sentiment_df["score"].mean()
    

获得平均分后,可以创建一个逻辑语句,便于你确切地知道一周的积极程度。

      def week_logic(week_score):
    if week_score > 0.75 or week_score == 0.75:
        print("You had a positive week")
    elif week_score > 0.45 or week_score == 0.45:
        print("You had a neutral week")
    else:
        print("You had a negative week, I hope it gets better")

    

文件主语句的最终版本应如下所示:

 

      def main():
    url = create_twitter_url()
    data = process_yaml()
    bearer_token = create_bearer_token(data)
    res_json = twitter_auth_and_connect(bearer_token, url)
    documents = lang_data_shape(res_json)
    language_api_url, sentiment_url, subscription_key = connect_to_azure(data)
    headers = azure_header(subscription_key)
    with_languages = generate_languages(headers, language_api_url, documents)
    json_lines = combine_lang_data(documents, with_languages)
    document_format = add_document_format(json_lines)
    sentiments = sentiment_scores(headers, sentiment_url, document_format)
    week_score = mean_score(sentiments)
    print(week_score)
    week_logic(week_score)
    

现在,你应该可以在终端键入以下内容来运行代码:

 

      python3 week.py

    

根据情绪得分,你应该会在终端输出中看到如下内容:

 

      0.6470708809792995
You had a neutral week
    

后续步骤

 

你可以轻松扩展此代码示例,以便了解最积极或最消极的推文,或者通过可视化效果跟踪每周的变化。

 

如果在此过程中遇到任何问题,请在论坛上告诉我们;如果本教程激发了你的创作灵感,请通过 @TwitterDev 与我们分享。我使用了 Twitter API 以外的多个库和工具来制作本教程,但你可能有不同的需求和要求,所以应评估这些工具是否适合你。Twitter 并未运营或管理上文提及的第三方服务,关于任何工具和其他功能的用法,这些服务可能具有单独的条款。