[{"data":1,"prerenderedAt":1022},["ShallowReactive",2],{"content-\u002Fcontents\u002Fabout-twitter-api":3,"surroundPost-\u002Fcontents\u002Fabout-twitter-api":1013},{"id":4,"title":5,"body":6,"createdAt":1002,"description":5,"draft":1003,"extension":1004,"meta":1005,"navigation":264,"path":1006,"seo":1007,"stem":1008,"tags":1009,"thumbnail":1011,"updatedAt":1002,"__hash__":1012},"contents\u002Fcontents\u002Fabout-twitter-api.md","PythonとTwitter APIを利用したツイート収集方法",{"type":7,"value":8,"toc":993},"minimark",[9,13,16,29,32,37,50,53,56,65,74,78,81,89,94,97,100,103,106,120,123,134,138,141,161,164,175,184,191,195,198,201,204,212,215,218,801,804,807,810,813,824,842,849,852,855,893,900,903,906,915,918,944,947,950,953,956,959,962,965,968,977,980,989],[10,11,12],"p",{},"Python と Twitter API を使って Twitter の分析を行いたいと思ったので、Twitter API について色々調べて試してみました。",[10,14,15],{},"Twitter API とは、公式の言葉を引用すると以下のようなものです。",[17,18,19],"blockquote",{},[10,20,21,22],{},"Twitter にある情報をできるだけ広く共有するために、API （アプリケーション・プログラミング・インタフェイス）を通して Twitter データにプログラムレベルでアクセスし、企業、開発者、利用者に提供します。\n引用：",[23,24,28],"a",{"href":25,"rel":26},"https:\u002F\u002Fhelp.twitter.com\u002Fja\u002Frules-and-policies\u002Ftwitter-api",[27],"nofollow","Twitter の API について",[10,30,31],{},"今回はこの Twitter API の概要と Python を利用した Search Tweets API の使い方についてまとめました。",[33,34,36],"h2",{"id":35},"twitter-api-でできること","Twitter API でできること",[10,38,39,43,44,49],{},[40,41,42],"strong",{},"Twitter API では Twitter でできることはほぼ全てできます。","\n詳細は",[23,45,48],{"href":46,"rel":47},"https:\u002F\u002Fdeveloper.twitter.com\u002Fja\u002Fdocs",[27],"こちら","のドキュメントに記載されています。",[10,51,52],{},"API を使うことで、Twitter でできることをある程度自動化できることがアプリと比較したメリットです。",[10,54,55],{},"例えば、Twitter のサードパティーサービスのようにツイートの予約・自動投稿が可能になります。まぁ、だいたいやりたいと思ったことはコードと API を組み合わせれば実現できそうです。",[10,57,58,59,64],{},"ただし、開発者が守るべき",[23,60,63],{"href":61,"rel":62},"https:\u002F\u002Fhelp.twitter.com\u002Fja\u002Frules-and-policies\u002Ftwitter-automation",[27],"自動化ルール","があるので、自動化のプログラムを使用する前に確認しておきましょう。",[10,66,67,68,73],{},"今回使用するのは、ツイートの収集なので",[23,69,72],{"href":70,"rel":71},"https:\u002F\u002Fdeveloper.twitter.com\u002Fen\u002Fdocs\u002Ftweets\u002Fsearch\u002Foverview",[27],"Search Tweets API","を利用します。",[33,75,77],{"id":76},"twitter-api-の始め方","Twitter API の始め方",[10,79,80],{},"Twitter API を使用するには、Twitter のアカウントの他に Twitter API の登録申請が必要です。",[10,82,83,84,88],{},"詳しいやり方は",[23,85,48],{"href":86,"rel":87},"https:\u002F\u002Fqiita.com\u002Fkngsym2018\u002Fitems\u002F2524d21455aac111cdee",[27],"の記事が大変参考になります。",[10,90,91],{},[40,92,93],{},"ポイントは申請内容はすべて英語で書く必要があることです。",[10,95,96],{},"とはいえ、私たちには Google 翻訳があるのでそこまで苦労することはないです。日本語で内容を書いて、Google 翻訳の結果をコピペすれば大丈夫です。",[10,98,99],{},"書く内容については、正直に書けば問題ないと思います。",[10,101,102],{},"私の場合は以下のような内容で申請しました。",[10,104,105],{},"私が twitter データを利用する理由は以下の２つです。",[107,108,109,115],"ul",{},[110,111,112],"li",{},[40,113,114],{},"１つ目は自分のブログに関連するトピックの分析です。twitter の情報を分析し、ユーザーに需要のある記事を書きたいと思ってます。",[110,116,117],{},[40,118,119],{},"２つ目は機械学習のためのデータ収集です。私は、機械学習を勉強中で生データを使った分析を試してみたいと思ってます。",[10,121,122],{},"申請結果は申請してすぐにきました。他の記事では１日やそこら待つとありましたが、私の場合は出してすぐにメールがきました。普通に書いて出せば、その日のうちに利用を開始できると思います。",[10,124,125],{},[40,126,127,128,133],{},"利用できるようになったら必ず",[23,129,132],{"href":130,"rel":131},"https:\u002F\u002Fdeveloper.twitter.com\u002Fja\u002Fdeveloper-terms\u002Fagreement-and-policy",[27],"開発者契約およびポリシー","は確認しましょう。",[33,135,137],{"id":136},"search-tweets-api-の制限","Search tweets API の制限",[10,139,140],{},"API が使えるようになったら早速試したいところですが、API にはいろいろ条件があるのでまずはそれらを確認します。",[10,142,143,144,148,149,148,152,155,156,160],{},"Seatch Tweets API には",[145,146,147],"code",{},"Standard","、",[145,150,151],{},"Premium",[145,153,154],{},"Enterprise","の３タイプがあります。3 タイプの比較については",[23,157,48],{"href":158,"rel":159},"https:\u002F\u002Fkageura.hatenadiary.jp\u002Fentry\u002F2019\u002F02\u002F01\u002F500%E4%B8%87%E4%BB%B6%E3%82%92%E8%B6%85%E3%81%88%E3%82%8BTwitter_%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E5%8F%96%E5%BE%97%E3%83%BB%E5%88%86%E6%9E%90%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95_-Twitter_Premium_Se",[27],"の記事が参考になります。",[10,162,163],{},"今回利用する Standard Search API には以下のような制限があります。",[107,165,166,169,172],{},[110,167,168],{},"15 分間に 180 リクエストまで",[110,170,171],{},"１度に取得できるツイート件数は 100 件",[110,173,174],{},"遡れる期間は７日前まで",[10,176,177,178,183],{},"他の制限や Search API のパラメータなどについては",[23,179,182],{"href":180,"rel":181},"https:\u002F\u002Fdeveloper.twitter.com\u002Fen\u002Fdocs\u002Ftweets\u002Fsearch\u002Fapi-reference\u002Fget-search-tweets",[27],"こちら（公式）","に記載されてます。",[10,185,186,187,190],{},"コードを書くまえに",[145,188,189],{},"curl","を利用した example があるので、そちらを試すとイメージが掴めます。",[33,192,194],{"id":193},"python-でツイートを取得する方法","Python でツイートを取得する方法",[10,196,197],{},"いよいよ API を利用してツイートを取得していきます。",[10,199,200],{},"今回は Python を使って API を叩きます。Python には tweepy という Twitter API 用のライブラリがあるのでそちらを利用します。",[10,202,203],{},"ちなみに今回の検証環境は以下になります。",[107,205,206,209],{},[110,207,208],{},"MacOS Mojave バージョン 10.14.6",[110,210,211],{},"Python 3.7.4",[10,213,214],{},"コードは以下のようにしました。あまり綺麗な書き方じゃないかもしれません。。",[10,216,217],{},"必要ないかもしれませんが、リクエスト前に sleep を適当に設定しました。",[219,220,225],"pre",{"className":221,"code":222,"language":223,"meta":224,"style":224},"language-py shiki shiki-themes github-dark","import tweepy\nimport pandas as pd\nimport datetime\nfrom time import sleep\nimport argparse\n\nparser = argparse.ArgumentParser(description='Twitter APIでツイート取得')\nparser.add_argument('-q', help='検索クエリ')\nparser.add_argument('--cnt',default=100, help='取得件数。デフォルト１００件')\n\nargs = parser.parse_args()\n\n# API認証情報\nCONSUMER_API_KEY = \"\"\nCONSUMER_API_SECRET_KEY = \"\"\nACCESS_TOKEN = \"\"\nACCESS_TOKEN_SECRET = \"\"\n\n# tweepyでTwitter APIラッパーオブジェクト取得\ndef getAPI():\n    auth = tweepy.OAuthHandler(CONSUMER_API_KEY, CONSUMER_API_SECRET_KEY)\n    auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)\n\n    api = tweepy.API(auth)\n\n    return api\n\n# ツイートを取得\ndef getTweetData(api):\n\n    tweet_data = []\n\n    try:\n        response = api.search(q=args.q, count=1, result_type=\"result_type\", lang='ja',tweet_mode='extended')\n    except tweepy.error.TweepError as tweepy_error:\n        print(tweepy_error)\n\n    next_max_id = response[-1].id\n\n    i=0\n    sleep(1)\n\n    while True:\n        print('検索ページ：' + str(i))\n\n        try:\n            response = api.search(q=args.q, count=100, max_id=next_max_id-1, lang='ja',tweet_mode='extended')\n\n            if len(response) > 0:\n                next_max_id = response[-1].id\n            else:\n                print(\"これ以上取得できません。検索ツイートが７日以上前か、検索ボリュームが少なすぎます。\")\n                break\n\n            for tweet in response:\n                user_mentions = []\n\n                if tweet.entities[\"user_mentions\"]:\n                    for name in tweet.entities[\"user_mentions\"]:\n                        user_mentions.append(name[\"screen_name\"])\n\n                mention_names = ','.join(user_mentions)\n\n                tweet_data.append([tweet.created_at.strftime('%Y\u002F%m\u002F%d'), tweet.id, tweet.user.name, tweet.user.screen_name, tweet.full_text.replace('\\n',''), tweet.favorite_count,tweet.retweet_count,tweet.user.followers_count,tweet.user.friends_count,mention_names])\n\n        except tweepy.error.TweepError as tweepy_error:\n            print(tweepy_error)\n            break\n        except tweepy.error.RateLimitError as limit_error:\n            print(\"検索上限に達しました\")\n            break\n\n        i+=1\n        if(i == 180):\n            print(\"検索上限に達しました。上限は15分後にリセットされます\")\n            break\n        sleep(2)\n\n    print(\"Finish search!\")\n\n    return tweet_data\n\ndef makeFile(data):\n    now = datetime.datetime.now()\n    q = args.q.replace(' ', '_')\n\n    # 結果保存パス、ファイル名\n    file_name = 'path\u002F{0}_{1}.csv'.format(\"query\", now.strftime('%Y-%m-%d_%H-%M'))\n\n    columns = [\"投稿日\", \"ID\", \"User_name\", \"Screen_name\", \"text\", \"favorite\", \"retweet_count\", \"followers\", \"follows\", \"user_mentions\"]\n\n    df = pd.DataFrame(data) # 行の名前を設定\n    df.columns = columns\n\n    df.to_csv(file_name)\n\nif __name__ == \"__main__\":\n    api = getAPI()\n    search_data = getTweetData(api)\n    makeFile(search_data)\n","py","",[145,226,227,235,241,247,253,259,266,272,278,284,289,295,300,306,312,318,324,330,335,341,347,353,359,364,370,375,381,386,392,398,403,409,414,420,426,432,438,443,449,454,460,466,471,477,483,488,494,500,505,511,517,523,529,535,540,546,552,557,563,569,575,580,586,591,597,602,608,614,620,626,632,637,642,648,654,660,665,671,676,682,687,693,698,704,710,716,721,727,733,738,744,749,755,761,766,772,777,783,789,795],{"__ignoreMap":224},[228,229,232],"span",{"class":230,"line":231},"line",1,[228,233,234],{},"import tweepy\n",[228,236,238],{"class":230,"line":237},2,[228,239,240],{},"import pandas as pd\n",[228,242,244],{"class":230,"line":243},3,[228,245,246],{},"import datetime\n",[228,248,250],{"class":230,"line":249},4,[228,251,252],{},"from time import sleep\n",[228,254,256],{"class":230,"line":255},5,[228,257,258],{},"import argparse\n",[228,260,262],{"class":230,"line":261},6,[228,263,265],{"emptyLinePlaceholder":264},true,"\n",[228,267,269],{"class":230,"line":268},7,[228,270,271],{},"parser = argparse.ArgumentParser(description='Twitter APIでツイート取得')\n",[228,273,275],{"class":230,"line":274},8,[228,276,277],{},"parser.add_argument('-q', help='検索クエリ')\n",[228,279,281],{"class":230,"line":280},9,[228,282,283],{},"parser.add_argument('--cnt',default=100, help='取得件数。デフォルト１００件')\n",[228,285,287],{"class":230,"line":286},10,[228,288,265],{"emptyLinePlaceholder":264},[228,290,292],{"class":230,"line":291},11,[228,293,294],{},"args = parser.parse_args()\n",[228,296,298],{"class":230,"line":297},12,[228,299,265],{"emptyLinePlaceholder":264},[228,301,303],{"class":230,"line":302},13,[228,304,305],{},"# API認証情報\n",[228,307,309],{"class":230,"line":308},14,[228,310,311],{},"CONSUMER_API_KEY = \"\"\n",[228,313,315],{"class":230,"line":314},15,[228,316,317],{},"CONSUMER_API_SECRET_KEY = \"\"\n",[228,319,321],{"class":230,"line":320},16,[228,322,323],{},"ACCESS_TOKEN = \"\"\n",[228,325,327],{"class":230,"line":326},17,[228,328,329],{},"ACCESS_TOKEN_SECRET = \"\"\n",[228,331,333],{"class":230,"line":332},18,[228,334,265],{"emptyLinePlaceholder":264},[228,336,338],{"class":230,"line":337},19,[228,339,340],{},"# tweepyでTwitter APIラッパーオブジェクト取得\n",[228,342,344],{"class":230,"line":343},20,[228,345,346],{},"def getAPI():\n",[228,348,350],{"class":230,"line":349},21,[228,351,352],{},"    auth = tweepy.OAuthHandler(CONSUMER_API_KEY, CONSUMER_API_SECRET_KEY)\n",[228,354,356],{"class":230,"line":355},22,[228,357,358],{},"    auth.set_access_token(ACCESS_TOKEN, ACCESS_TOKEN_SECRET)\n",[228,360,362],{"class":230,"line":361},23,[228,363,265],{"emptyLinePlaceholder":264},[228,365,367],{"class":230,"line":366},24,[228,368,369],{},"    api = tweepy.API(auth)\n",[228,371,373],{"class":230,"line":372},25,[228,374,265],{"emptyLinePlaceholder":264},[228,376,378],{"class":230,"line":377},26,[228,379,380],{},"    return api\n",[228,382,384],{"class":230,"line":383},27,[228,385,265],{"emptyLinePlaceholder":264},[228,387,389],{"class":230,"line":388},28,[228,390,391],{},"# ツイートを取得\n",[228,393,395],{"class":230,"line":394},29,[228,396,397],{},"def getTweetData(api):\n",[228,399,401],{"class":230,"line":400},30,[228,402,265],{"emptyLinePlaceholder":264},[228,404,406],{"class":230,"line":405},31,[228,407,408],{},"    tweet_data = []\n",[228,410,412],{"class":230,"line":411},32,[228,413,265],{"emptyLinePlaceholder":264},[228,415,417],{"class":230,"line":416},33,[228,418,419],{},"    try:\n",[228,421,423],{"class":230,"line":422},34,[228,424,425],{},"        response = api.search(q=args.q, count=1, result_type=\"result_type\", lang='ja',tweet_mode='extended')\n",[228,427,429],{"class":230,"line":428},35,[228,430,431],{},"    except tweepy.error.TweepError as tweepy_error:\n",[228,433,435],{"class":230,"line":434},36,[228,436,437],{},"        print(tweepy_error)\n",[228,439,441],{"class":230,"line":440},37,[228,442,265],{"emptyLinePlaceholder":264},[228,444,446],{"class":230,"line":445},38,[228,447,448],{},"    next_max_id = response[-1].id\n",[228,450,452],{"class":230,"line":451},39,[228,453,265],{"emptyLinePlaceholder":264},[228,455,457],{"class":230,"line":456},40,[228,458,459],{},"    i=0\n",[228,461,463],{"class":230,"line":462},41,[228,464,465],{},"    sleep(1)\n",[228,467,469],{"class":230,"line":468},42,[228,470,265],{"emptyLinePlaceholder":264},[228,472,474],{"class":230,"line":473},43,[228,475,476],{},"    while True:\n",[228,478,480],{"class":230,"line":479},44,[228,481,482],{},"        print('検索ページ：' + str(i))\n",[228,484,486],{"class":230,"line":485},45,[228,487,265],{"emptyLinePlaceholder":264},[228,489,491],{"class":230,"line":490},46,[228,492,493],{},"        try:\n",[228,495,497],{"class":230,"line":496},47,[228,498,499],{},"            response = api.search(q=args.q, count=100, max_id=next_max_id-1, lang='ja',tweet_mode='extended')\n",[228,501,503],{"class":230,"line":502},48,[228,504,265],{"emptyLinePlaceholder":264},[228,506,508],{"class":230,"line":507},49,[228,509,510],{},"            if len(response) > 0:\n",[228,512,514],{"class":230,"line":513},50,[228,515,516],{},"                next_max_id = response[-1].id\n",[228,518,520],{"class":230,"line":519},51,[228,521,522],{},"            else:\n",[228,524,526],{"class":230,"line":525},52,[228,527,528],{},"                print(\"これ以上取得できません。検索ツイートが７日以上前か、検索ボリュームが少なすぎます。\")\n",[228,530,532],{"class":230,"line":531},53,[228,533,534],{},"                break\n",[228,536,538],{"class":230,"line":537},54,[228,539,265],{"emptyLinePlaceholder":264},[228,541,543],{"class":230,"line":542},55,[228,544,545],{},"            for tweet in response:\n",[228,547,549],{"class":230,"line":548},56,[228,550,551],{},"                user_mentions = []\n",[228,553,555],{"class":230,"line":554},57,[228,556,265],{"emptyLinePlaceholder":264},[228,558,560],{"class":230,"line":559},58,[228,561,562],{},"                if tweet.entities[\"user_mentions\"]:\n",[228,564,566],{"class":230,"line":565},59,[228,567,568],{},"                    for name in tweet.entities[\"user_mentions\"]:\n",[228,570,572],{"class":230,"line":571},60,[228,573,574],{},"                        user_mentions.append(name[\"screen_name\"])\n",[228,576,578],{"class":230,"line":577},61,[228,579,265],{"emptyLinePlaceholder":264},[228,581,583],{"class":230,"line":582},62,[228,584,585],{},"                mention_names = ','.join(user_mentions)\n",[228,587,589],{"class":230,"line":588},63,[228,590,265],{"emptyLinePlaceholder":264},[228,592,594],{"class":230,"line":593},64,[228,595,596],{},"                tweet_data.append([tweet.created_at.strftime('%Y\u002F%m\u002F%d'), tweet.id, tweet.user.name, tweet.user.screen_name, tweet.full_text.replace('\\n',''), tweet.favorite_count,tweet.retweet_count,tweet.user.followers_count,tweet.user.friends_count,mention_names])\n",[228,598,600],{"class":230,"line":599},65,[228,601,265],{"emptyLinePlaceholder":264},[228,603,605],{"class":230,"line":604},66,[228,606,607],{},"        except tweepy.error.TweepError as tweepy_error:\n",[228,609,611],{"class":230,"line":610},67,[228,612,613],{},"            print(tweepy_error)\n",[228,615,617],{"class":230,"line":616},68,[228,618,619],{},"            break\n",[228,621,623],{"class":230,"line":622},69,[228,624,625],{},"        except tweepy.error.RateLimitError as limit_error:\n",[228,627,629],{"class":230,"line":628},70,[228,630,631],{},"            print(\"検索上限に達しました\")\n",[228,633,635],{"class":230,"line":634},71,[228,636,619],{},[228,638,640],{"class":230,"line":639},72,[228,641,265],{"emptyLinePlaceholder":264},[228,643,645],{"class":230,"line":644},73,[228,646,647],{},"        i+=1\n",[228,649,651],{"class":230,"line":650},74,[228,652,653],{},"        if(i == 180):\n",[228,655,657],{"class":230,"line":656},75,[228,658,659],{},"            print(\"検索上限に達しました。上限は15分後にリセットされます\")\n",[228,661,663],{"class":230,"line":662},76,[228,664,619],{},[228,666,668],{"class":230,"line":667},77,[228,669,670],{},"        sleep(2)\n",[228,672,674],{"class":230,"line":673},78,[228,675,265],{"emptyLinePlaceholder":264},[228,677,679],{"class":230,"line":678},79,[228,680,681],{},"    print(\"Finish search!\")\n",[228,683,685],{"class":230,"line":684},80,[228,686,265],{"emptyLinePlaceholder":264},[228,688,690],{"class":230,"line":689},81,[228,691,692],{},"    return tweet_data\n",[228,694,696],{"class":230,"line":695},82,[228,697,265],{"emptyLinePlaceholder":264},[228,699,701],{"class":230,"line":700},83,[228,702,703],{},"def makeFile(data):\n",[228,705,707],{"class":230,"line":706},84,[228,708,709],{},"    now = datetime.datetime.now()\n",[228,711,713],{"class":230,"line":712},85,[228,714,715],{},"    q = args.q.replace(' ', '_')\n",[228,717,719],{"class":230,"line":718},86,[228,720,265],{"emptyLinePlaceholder":264},[228,722,724],{"class":230,"line":723},87,[228,725,726],{},"    # 結果保存パス、ファイル名\n",[228,728,730],{"class":230,"line":729},88,[228,731,732],{},"    file_name = 'path\u002F{0}_{1}.csv'.format(\"query\", now.strftime('%Y-%m-%d_%H-%M'))\n",[228,734,736],{"class":230,"line":735},89,[228,737,265],{"emptyLinePlaceholder":264},[228,739,741],{"class":230,"line":740},90,[228,742,743],{},"    columns = [\"投稿日\", \"ID\", \"User_name\", \"Screen_name\", \"text\", \"favorite\", \"retweet_count\", \"followers\", \"follows\", \"user_mentions\"]\n",[228,745,747],{"class":230,"line":746},91,[228,748,265],{"emptyLinePlaceholder":264},[228,750,752],{"class":230,"line":751},92,[228,753,754],{},"    df = pd.DataFrame(data) # 行の名前を設定\n",[228,756,758],{"class":230,"line":757},93,[228,759,760],{},"    df.columns = columns\n",[228,762,764],{"class":230,"line":763},94,[228,765,265],{"emptyLinePlaceholder":264},[228,767,769],{"class":230,"line":768},95,[228,770,771],{},"    df.to_csv(file_name)\n",[228,773,775],{"class":230,"line":774},96,[228,776,265],{"emptyLinePlaceholder":264},[228,778,780],{"class":230,"line":779},97,[228,781,782],{},"if __name__ == \"__main__\":\n",[228,784,786],{"class":230,"line":785},98,[228,787,788],{},"    api = getAPI()\n",[228,790,792],{"class":230,"line":791},99,[228,793,794],{},"    search_data = getTweetData(api)\n",[228,796,798],{"class":230,"line":797},100,[228,799,800],{},"    makeFile(search_data)\n",[10,802,803],{},"認証情報は API 利用申請を行い、API を使うアプリケーションの登録を行うと取得できます。",[10,805,806],{},"tweepy を使えば上記のように API のラッパーを簡単に扱えます。",[10,808,809],{},"検索クエリはコマンドラインから引数として渡します。検索結果は pandas を利用して csv にまとめます。今回は取得した情報全てではなく、いいね回数やフォロワー数などなんとなく役に立ちそうなものを抜粋しました。",[10,811,812],{},"このコードのポイントは以下の通りです。",[107,814,815,818,821],{},[110,816,817],{},"tweet_mode='extended'を指定",[110,819,820],{},"ツイートの id を保持し、２回目の以降の検索はその id 以降からツイートを取得",[110,822,823],{},"ツイートに含まれるメンションを保存",[10,825,826,827,830,831,833,834,837,838,841],{},"１つ目の",[145,828,829],{},"tweet_mode='extended'","は指定しないと、文字数が多いツイートの文章が省略されてしまいます。指定することでツイート全文を得られます。\n気をつけないといけないのは、",[145,832,829],{},"を指定しない場合では、ツイート文の取得キーが",[145,835,836],{},"tweet.full_text","ではなく",[145,839,840],{},"tweet.text","になります。",[10,843,844,845,848],{},"２つ目の",[145,846,847],{},"id","は、２度目に API を叩く時に１度目に取得したツイート以降の結果を取得するために利用します。Search Tweets API は１度に 100 件までなので、重複せずに結果を取得するために必要になります。",[10,850,851],{},"３つ目は、取得したツイート文に含まれるメンションを後で抜くために使います。正規表現で抜いてもいいのですが、API の結果を利用した方が確実なのでこちらを利用します。",[10,853,854],{},"実行するときは以下のようにターミナルに入力します。",[219,856,860],{"className":857,"code":858,"language":859,"meta":224,"style":224},"language-bash shiki shiki-themes github-dark","python \u003Cファイル名>.py -q \"\u003C検索文>\"\n","bash",[145,861,862],{"__ignoreMap":224},[228,863,864,868,872,876,880,883,886,890],{"class":230,"line":231},[228,865,867],{"class":866},"svObZ","python",[228,869,871],{"class":870},"snl16"," \u003C",[228,873,875],{"class":874},"sU2Wk","ファイル",[228,877,879],{"class":878},"s95oV","名",[228,881,882],{"class":870},">",[228,884,885],{"class":874},".py",[228,887,889],{"class":888},"sDLfK"," -q",[228,891,892],{"class":874}," \"\u003C検索文>\"\n",[10,894,895,896,899],{},"エラーなく終了すると、",[145,897,898],{},"makeFile","関数で指定したパスに結果が CSV で保存されます。",[33,901,902],{"id":902},"検索クエリのオプション",[10,904,905],{},"Search Tweets API では Twitter アプリの高度な検索と同じように検索に条件を設定できます。この設定を行うと、後でツイート文を分析するときにコード上で行う処理が減るので便利です。",[10,907,908,909,914],{},"公式では",[23,910,913],{"href":911,"rel":912},"https:\u002F\u002Fdeveloper.twitter.com\u002Fen\u002Fdocs\u002Ftweets\u002Fsearch\u002Fguides\u002Fstandard-operators",[27],"Standard search operators","と呼ばれています。",[10,916,917],{},"よく使うのをいくつ紹介します。先頭にハイフンがついてるオプションは否定を意味します。",[107,919,920,926,932,938],{},[110,921,922,925],{},[145,923,924],{},"lang:ja","日本語のみ取得",[110,927,928,931],{},[145,929,930],{},"-filter:links","URL を含むツイートを除外",[110,933,934,937],{},[145,935,936],{},"-filter:retweets","アカウント名のツイートを除外",[110,939,940,943],{},[145,941,942],{},"hoge -huga","hoge を含むが huga は含まないツイート",[10,945,946],{},"これらのオプションをコード実行時の検索クエリに含めると指定した条件に合致したツイートのみが取得できます。",[33,948,949],{"id":949},"まとめ",[10,951,952],{},"今回は Twitter API の Search Tweets API について紹介しました。",[10,954,955],{},"ツイートはデータ分析をする上で非常に役立ちます。とくに自然言語処理を勉強する上で、大量の生データを扱えるのはありがたいです。",[10,957,958],{},"ツイートは本当にいろいろなパターンがあるので、自然言語処理の前処理の勉強にはもってこいです。",[10,960,961],{},"次回は今回のコードを利用したツイート収集自動化について書こうと思います。",[33,963,964],{"id":964},"参考書籍",[10,966,967],{},"API については以下の書籍が参考になりました。",[107,969,970],{},[110,971,972],{},[23,973,976],{"href":974,"rel":975},"https:\u002F\u002Famzn.to\u002F3adI1PI",[27],"Real World HTTP ―歴史とコードに学ぶインターネットとウェブ技術",[10,978,979],{},"Python を使った API 操作は以下の書籍を参考にしました。スクレイピングや機械学習についても書かれており重宝してます。私が持っているものの増補改訂版が出てたのでそちらを紹介します。",[107,981,982],{},[110,983,984],{},[23,985,988],{"href":986,"rel":987},"https:\u002F\u002Famzn.to\u002F2QCYghh",[27],"増補改訂 Python によるスクレイピング&機械学習 開発テクニック",[990,991,992],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}",{"title":224,"searchDepth":237,"depth":237,"links":994},[995,996,997,998,999,1000,1001],{"id":35,"depth":237,"text":36},{"id":76,"depth":237,"text":77},{"id":136,"depth":237,"text":137},{"id":193,"depth":237,"text":194},{"id":902,"depth":237,"text":902},{"id":949,"depth":237,"text":949},{"id":964,"depth":237,"text":964},"2020-05-09",false,"md",{},"\u002Fcontents\u002Fabout-twitter-api",{"title":5,"description":5},"contents\u002Fabout-twitter-api",[1010],"Python","\u002Fimg\u002Ftwitter-card.png","Ktdi6-EQViyUQJw0ZzQJKm5MCNFhoLByjB10rmZXW2c",[1014,1018],{"title":1015,"path":1016,"stem":1017,"children":-1},"Shepherd | Paper Summary","\u002Fcontents\u002F20260512-paper-watch","contents\u002F20260512-paper-watch",{"title":1019,"path":1020,"stem":1021,"children":-1},"Agent libOS: A Library-OS-Inspired Runtime for Long-Running, Capability-Controlled LLM Agents","\u002Fcontents\u002Fagent-libos","contents\u002Fagent-libos",1784936718563]