├── requirements.txt ├── .DS_Store ├── Twitter_Frontend_API ├── __init__.py ├── __pycache__ │ ├── main.cpython-38.pyc │ └── main1.cpython-38.pyc ├── test.py └── main.py ├── CHANGELOG.md ├── setup.py ├── LICENSE ├── examples └── ALL EXAMPLE.py └── README.md /requirements.txt: -------------------------------------------------------------------------------- 1 | requests 2 | lxml 3 | fake_useragent 4 | bs4 5 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lqm1/Twitter_Frontend_API/HEAD/.DS_Store -------------------------------------------------------------------------------- /Twitter_Frontend_API/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from .main import Client 3 | from .main import API 4 | 5 | __version__ = "1.1.1" -------------------------------------------------------------------------------- /Twitter_Frontend_API/__pycache__/main.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lqm1/Twitter_Frontend_API/HEAD/Twitter_Frontend_API/__pycache__/main.cpython-38.pyc -------------------------------------------------------------------------------- /Twitter_Frontend_API/__pycache__/main1.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lqm1/Twitter_Frontend_API/HEAD/Twitter_Frontend_API/__pycache__/main1.cpython-38.pyc -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## 1.1.0 2 | 3 | Now you can perform more extensive account operations and retrieve information than the last update. 4 | 5 | - You can now change your password and check the shadowban status. 6 | 7 | ## 1.0.4 8 | 9 | You can now work with accounts. 10 | 11 | - You can now manipulate accounts using Twitter's front-end API. 12 | You can manipulate areas that cannot be handled by normal APIs such as settings. 13 | 14 | 15 | ## 0.1.3 16 | 17 | First release 18 | 19 | - We've implemented most of the common APIs available from the Twitter website. -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | with open('requirements.txt') as requirements: 3 | required = requirements.read().splitlines() 4 | 5 | setup( 6 | name='Twitter_Frontend_API', 7 | version='1.1.1', 8 | description='Get information from Twitter and work with your account using the front-end API built into the Twitter website.', 9 | url='https://github.com/KohnoseLami/Twitter_Frontend_API', 10 | author='神瀬来未', 11 | author_email='info@vxxx.cf', 12 | license='MIT', 13 | keywords='twitter scraper frontend api', 14 | packages=[ 15 | "Twitter_Frontend_API", 16 | ], 17 | install_requires=required, 18 | classifiers=[ 19 | 'License :: OSI Approved :: MIT License', 20 | 'Programming Language :: Python :: 3.9', 21 | ], 22 | ) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 KohnoseLami 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Twitter_Frontend_API/test.py: -------------------------------------------------------------------------------- 1 | from main import Client 2 | 3 | # res = Client().rate_limit_status() 4 | # res = Client().collections_entries("custom-539487832448843776") 5 | # res = Client().favorites_list("_SNQ") 6 | # res = Client().followers_ids("_SNQ") 7 | # res = Client().followers_list("_SNQ") 8 | # res = Client().friends_ids("_SNQ") 9 | # res = Client().friends_list("_SNQ") 10 | # res = Client().friendships_show("_SNQ", "Shadow_Ban_Bot") 11 | # res = Client().geo_id("06ef846bfc783874") 12 | # res = Client().geo_reverse_geocode("35.79449997305192", "139.79078800000002") 13 | # res = Client().geo_search("Tokyo") 14 | # res = Client().lists_list("_SNQ") 15 | # res = Client().lists_members("1517792406514839552") 16 | # res = Client().lists_memberships("_SNQ") 17 | # res = Client().lists_ownerships("_SNQ") 18 | # res = Client().lists_show("1517792406514839552") 19 | # res = Client().lists_statuses("1517792406514839552") 20 | # res = Client().lists_subscribers("1517792406514839552") 21 | # res = Client().lists_subscriptions("_SNQ") 22 | # res = Client().search_tweets("ツイート") 23 | # res = Client().statuses_lookup(["1488101267243429889", "1516619027288043521"]) 24 | # res = Client().statuses_retweeters_ids("1488101267243429889") 25 | # res = Client().statuses_retweets("1488101267243429889") 26 | # res = Client().statuses_show("1488101267243429889") 27 | # res = Client().statuses_user_timeline("_SNQ") 28 | # res = Client().trends_available() 29 | # res = Client().trends_closest("35.79449997305192", "139.79078800000002") 30 | # res = Client().trends_place("1110809") 31 | # res = Client().users_lookup(["_SNQ", "Shadow_Ban_Bot"]) 32 | # res = Client().users_search("_SNQ") 33 | # res = Client().user_show("_SNQ") 34 | 35 | res = Client().user_show("_SNQ") 36 | 37 | print(res) -------------------------------------------------------------------------------- /examples/ALL EXAMPLE.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from Twitter_Frontend_API import Client 3 | 4 | #ログイン無しでの情報取得 5 | client = Client() 6 | print(client.generate_ct0()) 7 | print(client.generate_authenticity()) 8 | print(client.generate_token()) 9 | print(client.user_info(screen_name="Twitter")) #print(api.user_info(user_id="783214")) 10 | print(client.user_tweets(screen_name="Twitter")) #print(api.user_tweets(user_id="783214")) 11 | print(client.trend()) 12 | print(client.searchbox("Text")) 13 | print(client.topic_search("Text")) 14 | print(client.latest_search("Text")) 15 | print(client.image_search("Text")) 16 | print(client.video_search("Text")) 17 | print(client.user_search("Text")) 18 | print(client.screenname_available("Screenname")) 19 | print(client.get_status("1335886771968741377")) 20 | print(client.shadowban_check(screen_name="Twitter")) #print(api.shadowban_check(user_id="783214")) 21 | 22 | 23 | from Twitter_Frontend_API import API 24 | 25 | #ログインと認証情報の定義 26 | #認証情報は辞書形式での定義 27 | auth = {'auth_token': '----------------------------------------', 'ct0': '--------------------------------'} 28 | auth = API.Login("Twitter", "Password") 29 | print(auth) 30 | 31 | #ログインあり 32 | api = API(auth) 33 | print(api.generate_ct0()) 34 | print(api.generate_authenticity()) 35 | print(api.generate_token()) 36 | print(api.user_info(screen_name="Twitter")) #print(api.user_info(user_id="783214")) 37 | print(api.user_tweets(screen_name="Twitter")) #print(api.user_tweets(user_id="783214")) 38 | print(api.trend()) 39 | print(api.searchbox("Text")) 40 | print(api.topic_search("Text")) 41 | print(api.latest_search("Text")) 42 | print(api.image_search("Text")) 43 | print(api.video_search("Text")) 44 | print(api.user_search("Text")) 45 | print(api.screenname_available("Screenname")) 46 | print(api.get_status("1335886771968741377")) 47 | print(api.update_status("Text")) 48 | print(api.update_status("Text", conversation_control=2, in_reply_to_status_id="1335886771968741377", card_uri="card://1338528317587124224")) 49 | print(api.destroy_status("1335886771968741377")) 50 | print(api.create_favorite("1335886771968741377")) 51 | print(api.destroy_favorite("1335886771968741377")) 52 | print(api.retweet("1335886771968741377")) 53 | print(api.unretweet("1335886771968741377")) 54 | print(api.create_friendship(screen_name="Twitter")) #print(api.create_friendship(user_id="783214")) 55 | print(api.destroy_friendship(screen_name="Twitter")) #print(api.destroy_friendship(user_id="783214")) 56 | print(api.notifications()) 57 | print(api.pin_tweet("1335886771968741377")) 58 | print(api.change_id("Screen_name")) 59 | print(api.topic_follow("847896929698668544")) 60 | print(api.topic_unfollow("847896929698668544")) 61 | print(api.followed_topics("1323603354165993472")) 62 | print(api.not_interested_topics()) 63 | print(api.recommendations()) 64 | print(api.lists_all("1323603354165993472")) 65 | print(api.create_list("ListName", private="False", description="")) 66 | print(api.destroy_list("1337433856673075206")) 67 | print(api.update_list("1326095394959360001", name="NameList", private="True", description="Text")) 68 | print(api.add_list_member("1326095394959360001", "1323603354165993472")) 69 | print(api.remove_list_member("1326095394959360001", "1323603354165993472")) 70 | print(api.list_members("1326095394959360001")) 71 | print(api.create_card(4, "5", one="Hello", two="World", three="!", four="byPython") 72 | print(api.Twitter_Web_Client("Text", place_id="fc6282dff859b848", authenticity_token=None)) 73 | print(api.add_bookmark("1335886771968741377")) 74 | print(api.mute_conversation("1335886771968741377")) 75 | print(api.unmute_conversation("1335886771968741377")) 76 | print(api.verify_password("password")) 77 | print(api.account_data(verify=None, password="password")) 78 | print(api.private("true")) 79 | print(api.gender("male")) 80 | print(api.protect_password_reset("password", protect="true")) 81 | print(api.session_revoke("KRJlliMG5b61wbuY4f70nk6TylRkYPJaMmCLT5eiQe8=")) 82 | print(api.sessions_revoke_all()) 83 | print(api.allow_media_tagging("all")) 84 | print(api.nsfw("true")) 85 | print(api.geo_enabled("true")) 86 | print(api.geo_delete()) 87 | print(api.display_sensitive_media("true")) 88 | print(api.twitter_interests()) 89 | print(api.set_explore("true")) 90 | print(api.shadowban_check(screen_name="Twitter")) #print(api.shadowban_check(user_id="783214")) 91 | print(api.change_password("old_password", "new_password")) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 2023-02-03 Addendum 2 | This module is currently not maintained and the person who requested the pull has now quit parsing Twitter. 3 | I do Twitter self-bots for work, and I won't write about any further improvements or private APIs for mobile (maybe). 4 | 5 | If I were to leave some useful information here, the Twitter API v 1.1 endpoints would still all work as usual using the "auth_token" in the account credentials cookie and the TweetDeck Authorization token. 6 | (Bearer AAAAAAAAAAAAAAAAAAAAAF7aAAAAAAAASCiRjWvh7R5wxaKkFp7MM%2BhYBqM%3DbQ0JPmjU9F6ZoMhDfI4uTNAaQuTDm2uO9x3WFVr2xBZ2nhjdP0) 7 | 8 | The previous login program included in this module can be used to get the "auth_token," but now logins using task.json are used. 9 | (Tip: The login API is the same for mobile and site (Why? LOL)) 10 | (API Keys: https://gist.github.com/shobotch/5160017) 11 | 12 | It also now says it's mainly GraphQL, not v 1.1, but the mobile version still uses the v2 API, the GraphQL API, the v 1.1 API and, to top it off, v 1. 13 | For a while you will be able to run v 1.1 just by changing the Authorization key. 14 | 15 | Also, there is now automated detection, so if you do a self-bot recklessly, your account will be immediately suspended. 16 | (Hint: Twitter barely detects in user agents, anywhere else) 17 | 18 | Automating with easy knowledge and gathered information is a high risk. 19 | Also, suspending is done per IP. Remember that if you automate and your account is suspended, the account of the family member you live with carries the risk of account suspension as well. 20 | 21 | Automating Twitter is currently easier than social networks like Instagram and Facebook, but with hidden risks. 22 | 23 | Telegram: KohnoseLami 24 | 25 | # Twitter Frontend API 26 | Get information using a front-end API that does not require a Twitter site login. 27 | 28 | ![Python 3.9](https://img.shields.io/badge/-Python%203.9-3776AB.svg?logo=python&style=plastic) 29 | [![Release](https://img.shields.io/badge/-Release%201.1.1-00979D.svg?logo=release&style=plastic)](https://github.com/KohnoseLami/Twitter_Frontend_API/releases) 30 | 31 | ## Overview 32 | 33 | Twitter runs, they force you to get a developer account to get information from Twitter. This is terrible. Your Twitter account could be suspended at any moment, or your application might not be approved at all. This is a module designed to work around them. 34 | You can analyze the communication of Twitter's official site, generate a guest token, and get information from it. 35 | It is not yet resistant to the retrieval of a large amount of information such as another page such as a search with detailed specification. You can retrieve only the information that appears the first time in the browser. Since the parameter analysis has not yet been completed, it is still in the process of development. 36 | 37 | The document is not ready yet. 38 | 39 | ## Features 40 | 41 | - You can obtain information such as:. 42 | * Generating Guest Tokens for Retrieving Information from Twitter 43 | * Obtain user details using a screen name or user ID 44 | * Retrieving a user's tweet using a screen name or user ID 45 | * Get Trend 46 | * Get results from search box (Search Candidates) 47 | * Get Search Results for Featured Tweets 48 | * Get Search Results for Latest Tweets 49 | * Get Image Tweet Search Results 50 | * Get Search Results for Video Tweets 51 | * Get user search results 52 | * Check if the screen name is available 53 | 54 | ## Install 55 | 56 | Install with pip: 57 | 58 | ``pip install Twitter_Frontend_API`` 59 | 60 | To update: 61 | 62 | ``pip install Twitter_Frontend_API --upgrade`` 63 | 64 | Tested on Python 3.9.0 65 | 66 | ## Usage 67 | 68 | ```python 69 | 70 | from Twitter_Frontend_API import Client 71 | 72 | api = Client() 73 | 74 | # SetUp 75 | print(api.generate_ct0()) 76 | print(api.generate_authenticity()) 77 | print(api.generate_token()) 78 | 79 | # Twitter API v1.1 80 | print(api.rate_limit_status()) 81 | print(api.collections_entries("custom-539487832448843776")) 82 | print(api.favorites_list("_SNQ")) 83 | print(api.followers_ids("_SNQ")) 84 | print(api.followers_list("_SNQ")) 85 | print(api.friends_ids("_SNQ")) 86 | print(api.friends_list("_SNQ")) 87 | print(api.friendships_show("_SNQ", "Shadow_Ban_Bot")) 88 | print(api.geo_id("06ef846bfc783874")) 89 | print(api.geo_reverse_geocode("35.79449997305192", "139.79078800000002")) 90 | print(api.geo_search("Tokyo")) 91 | print(api.lists_list("_SNQ")) 92 | print(api.lists_members("1517792406514839552")) 93 | print(api.lists_memberships("_SNQ")) 94 | print(api.lists_ownerships("_SNQ")) 95 | print(api.lists_show("1517792406514839552")) 96 | print(api.lists_statuses("1517792406514839552")) 97 | print(api.lists_subscribers("1517792406514839552")) 98 | print(api.lists_subscriptions("_SNQ")) 99 | print(api.search_tweets("ツイート")) 100 | print(api.statuses_lookup(["1488101267243429889", "1516619027288043521"])) 101 | print(api.statuses_retweeters_ids("1488101267243429889")) 102 | print(api.statuses_retweets("1488101267243429889")) 103 | print(api.statuses_show("1488101267243429889")) 104 | print(api.statuses_user_timeline("_SNQ")) 105 | print(api.trends_available()) 106 | print(api.trends_closest("35.79449997305192", "139.79078800000002")) 107 | print(api.trends_place("1110809")) 108 | print(api.users_lookup(["_SNQ", "Shadow_Ban_Bot"])) 109 | print(api.users_search("_SNQ")) 110 | print(api.user_show("_SNQ")) 111 | 112 | # Twitter API v2 OR Twitter API Private 113 | print(api.user_tweets(screen_name="Twitter")) #print(api.user_tweets(user_id="783214")) 114 | print(api.trend()) 115 | print(api.searchbox("Text")) 116 | print(api.topic_search("Text")) 117 | print(api.latest_search("Text")) 118 | print(api.image_search("Text")) 119 | print(api.video_search("Text")) 120 | print(api.user_search("Text")) 121 | print(api.screenname_available("Screenname")) 122 | print(api.get_status("1335886771968741377")) 123 | print(api.shadowban_check(screen_name="Twitter")) #print(api.shadowban_check(user_id="783214")) 124 | ``` 125 | 126 | ```python 127 | from Twitter_Frontend_API import API 128 | 129 | auth = {'auth_token': '----------------------------------------', 'ct0': '--------------------------------'} 130 | auth = API.Login("Twitter", "Password") 131 | print(auth) 132 | 133 | api = API(auth) 134 | 135 | print(api.generate_ct0()) 136 | print(api.generate_authenticity()) 137 | print(api.generate_token()) 138 | print(api.user_info(screen_name="Twitter")) #print(api.user_info(user_id="783214")) 139 | print(api.user_tweets(screen_name="Twitter")) #print(api.user_tweets(user_id="783214")) 140 | print(api.trend()) 141 | print(api.searchbox("Text")) 142 | print(api.topic_search("Text")) 143 | print(api.latest_search("Text")) 144 | print(api.image_search("Text")) 145 | print(api.video_search("Text")) 146 | print(api.user_search("Text")) 147 | print(api.screenname_available("Screenname")) 148 | print(api.get_status("1335886771968741377")) 149 | print(api.update_status("Text")) 150 | print(api.update_status("Text", conversation_control=2, in_reply_to_status_id="1335886771968741377", card_uri="card://1338528317587124224")) 151 | print(api.destroy_status("1335886771968741377")) 152 | print(api.get_dm()) 153 | print(send_dm('Text', screen_name="hogehoge")) #print(api.send_dm('Text', user_id="123456")) 154 | print(delete_dm(conversation_id_1=, conversation_id_2=)) #https://twitter.com/messages/- 155 | print(api.create_favorite("1335886771968741377")) 156 | print(api.destroy_favorite("1335886771968741377")) 157 | print(api.retweet("1335886771968741377")) 158 | print(api.unretweet("1335886771968741377")) 159 | print(api.create_friendship(screen_name="Twitter")) #print(api.create_friendship(user_id="783214")) 160 | print(api.destroy_friendship(screen_name="Twitter")) #print(api.destroy_friendship(user_id="783214")) 161 | print(api.notifications()) 162 | print(api.pin_tweet("1335886771968741377")) 163 | print(api.change_id("Screen_name")) 164 | print(api.topic_follow("847896929698668544")) 165 | print(api.topic_unfollow("847896929698668544")) 166 | print(api.followed_topics("1323603354165993472")) 167 | print(api.not_interested_topics()) 168 | print(api.recommendations()) 169 | print(api.lists_all("1323603354165993472")) 170 | print(api.create_list("ListName", private="False", description="")) 171 | print(api.destroy_list("1337433856673075206")) 172 | print(api.update_list("1326095394959360001", name="NameList", private="True", description="Text")) 173 | print(api.add_list_member("1326095394959360001", "1323603354165993472")) 174 | print(api.remove_list_member("1326095394959360001", "1323603354165993472")) 175 | print(api.list_members("1326095394959360001")) 176 | print(api.create_card(4, "5", one="Hello", two="World", three="!", four="byPython") 177 | print(api.Twitter_Web_Client("Text", place_id="fc6282dff859b848", authenticity_token=None)) 178 | print(api.add_bookmark("1335886771968741377")) 179 | print(api.mute_conversation("1335886771968741377")) 180 | print(api.unmute_conversation("1335886771968741377")) 181 | print(api.verify_password("password")) 182 | print(api.account_data(verify=None, password="password")) 183 | print(api.private("true")) 184 | print(api.gender("male")) 185 | print(api.protect_password_reset("password", protect="true")) 186 | print(api.session_revoke("KRJlliMG5b61wbuY4f70nk6TylRkYPJaMmCLT5eiQe8=")) 187 | print(api.sessions_revoke_all()) 188 | print(api.allow_media_tagging("all")) 189 | print(api.nsfw("true")) 190 | print(api.geo_enabled("true")) 191 | print(api.geo_delete()) 192 | print(api.display_sensitive_media("true")) 193 | print(api.twitter_interests()) 194 | print(api.set_explore("true")) 195 | print(api.shadowban_check(screen_name="Twitter")) #print(api.shadowban_check(user_id="783214")) 196 | print(api.change_password("old_password", "new_password")) 197 | ``` 198 | 199 | ## Donate 200 | 201 | Bitcoin Address 202 | 16TCmq3QrAmuJied6KwNGuiqxuGpZDVVMp 203 | 204 | ## Legal 205 | This is not official on Twitter. Use at your own risk. 206 | -------------------------------------------------------------------------------- /Twitter_Frontend_API/main.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | import requests 3 | import json 4 | from fake_useragent import UserAgent 5 | from bs4 import BeautifulSoup 6 | 7 | ua = UserAgent() 8 | 9 | ###例外クラス### 10 | class TwitterError(Exception): 11 | pass 12 | 13 | 14 | ###ログイン無し情報取得### 15 | 16 | class Client: 17 | headers = { 18 | 'authorization': 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA', 19 | 'User-Agent': ua.ie 20 | } 21 | guest_token = requests.post('https://api.twitter.com/1.1/guest/activate.json', headers=headers).json()["guest_token"] 22 | 23 | headers = { 24 | 'authorization': 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA', 25 | 'x-guest-token': guest_token, 26 | 'User-Agent': ua.ie 27 | } 28 | 29 | def generate_ct0(self): 30 | response = requests.get('https://twitter.com/i/release_notes') 31 | ct0 = response.cookies.get_dict()["ct0"] 32 | 33 | return ct0 34 | 35 | def generate_authenticity(self): 36 | response = requests.get('https://twitter.com/account/begin_password_reset') 37 | soup = BeautifulSoup(response.text, "lxml") 38 | authenticity_token = soup.find(attrs={'name':'authenticity_token'}).get('value') 39 | 40 | return authenticity_token 41 | 42 | def generate_token(self): 43 | headers = { 44 | 'authorization': 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA', 45 | 'User-Agent': ua.ie 46 | } 47 | response = requests.post('https://api.twitter.com/1.1/guest/activate.json', headers=headers).json() 48 | 49 | return response 50 | 51 | ### Twitter API v1.1 ### 52 | 53 | def rate_limit_status(self, resources=None): 54 | url = 'https://api.twitter.com/1.1/application/rate_limit_status.json' 55 | if resources != None: 56 | url = url + '?resources=' + resources 57 | response = requests.get(url, headers=self.headers).json() 58 | return response 59 | 60 | def collections_entries(self, id, count=None, max_position=None, min_position=None, tweet_mode=None): 61 | url = 'https://api.twitter.com/1.1/collections/entries.json?id=' + id 62 | if count != None: 63 | url = url + '&count=' + count 64 | if max_position != None: 65 | url = url + '&max_position=' + max_position 66 | if min_position != None: 67 | url = url + '&min_position=' + min_position 68 | if tweet_mode != None: 69 | url = url + '&tweet_mode=' + tweet_mode 70 | response = requests.get(url, headers=self.headers).json() 71 | return response 72 | 73 | def favorites_list(self, screen_name, count=None, since_id=None, max_id=None, include_entities=None, tweet_mode=None): 74 | url = 'https://api.twitter.com/1.1/favorites/list.json?screen_name=' + screen_name 75 | if count != None: 76 | url = url + '&count=' + count 77 | if since_id != None: 78 | url = url + '&since_id=' + since_id 79 | if max_id != None: 80 | url = url + '&max_id=' + since_id 81 | if include_entities != None: 82 | url = url + '&include_entities=' + include_entities 83 | if tweet_mode != None: 84 | url = url + '&tweet_mode=' + tweet_mode 85 | response = requests.get(url, headers=self.headers).json() 86 | return response 87 | 88 | def followers_ids(self, screen_name, cursor=None, stringify_ids=None, count=None): 89 | url = 'https://api.twitter.com/1.1/followers/ids.json?screen_name=' + screen_name 90 | if cursor != None: 91 | url = url + '&cursor=' + cursor 92 | if stringify_ids != None: 93 | url = url + '&stringify_ids=' + stringify_ids 94 | if count != None: 95 | url = url + '&count=' + count 96 | response = requests.get(url, headers=self.headers).json() 97 | return response 98 | 99 | def followers_list(self, screen_name, cursor=None, count=None, skip_status=None, include_user_entities=None, tweet_mode=None): 100 | url = 'https://api.twitter.com/1.1/followers/list.json?screen_name=' + screen_name 101 | if cursor != None: 102 | url = url + '&cursor=' + cursor 103 | if count != None: 104 | url = url + '&count=' + count 105 | if skip_status != None: 106 | url = url + '&skip_status=' + skip_status 107 | if include_user_entities != None: 108 | url = url + '&include_user_entities=' + include_user_entities 109 | if tweet_mode != None: 110 | url = url + '&tweet_mode=' + tweet_mode 111 | response = requests.get(url, headers=self.headers).json() 112 | return response 113 | 114 | def friends_ids(self, screen_name, cursor=None, stringify_ids=None, count=None): 115 | url = 'https://api.twitter.com/1.1/friends/ids.json?screen_name=' + screen_name 116 | if cursor != None: 117 | url = url + '&cursor=' + cursor 118 | if stringify_ids != None: 119 | url = url + '&stringify_ids=' + stringify_ids 120 | if count != None: 121 | url = url + '&count=' + count 122 | response = requests.get(url, headers=self.headers).json() 123 | return response 124 | 125 | def friends_list(self, screen_name, cursor=None, count=None, skip_status=None, include_user_entities=None, tweet_mode=None): 126 | url = 'https://api.twitter.com/1.1/friends/list.json?screen_name=' + screen_name 127 | if cursor != None: 128 | url = url + '&cursor=' + cursor 129 | if count != None: 130 | url = url + '&count=' + count 131 | if skip_status != None: 132 | url = url + '&skip_status=' + skip_status 133 | if include_user_entities != None: 134 | url = url + '&include_user_entities=' + include_user_entities 135 | if tweet_mode != None: 136 | url = url + '&tweet_mode=' + tweet_mode 137 | response = requests.get(url, headers=self.headers).json() 138 | return response 139 | 140 | def friendships_show(self, source_screen_name, target_screen_name): 141 | url = 'https://api.twitter.com/1.1/friendships/show.json?source_screen_name=' + source_screen_name + '&target_screen_name=' + target_screen_name 142 | response = requests.get(url, headers=self.headers).json() 143 | return response 144 | 145 | def geo_id(self, place_id): 146 | url = 'https://api.twitter.com/1.1/geo/id/' + place_id + '.json' 147 | response = requests.get(url, headers=self.headers).json() 148 | return response 149 | 150 | def geo_reverse_geocode(self, lat, long, accuracy=None, granularity=None, max_results=None): 151 | url = 'https://api.twitter.com/1.1/geo/reverse_geocode.json?lat=' + lat + '&long=' + long 152 | if accuracy != None: 153 | url = url + '&accuracy=' + accuracy 154 | if granularity != None: 155 | url = url + '&granularity=' + granularity 156 | if max_results != None: 157 | url = url + '&max_results=' + max_results 158 | response = requests.get(url, headers=self.headers).json() 159 | return response 160 | 161 | def geo_search(self, query, granularity=None, accuracy=None, max_results=None, contained_within=None, attribute_street_address=None): 162 | url = 'https://api.twitter.com/1.1/geo/search.json?query=' + query 163 | if granularity != None: 164 | url = url + '&granularity=' + granularity 165 | if accuracy != None: 166 | url = url + '&accuracy=' + accuracy 167 | if max_results != None: 168 | url = url + '&max_results=' + max_results 169 | if contained_within != None: 170 | url = url + '&contained_within=' + contained_within 171 | if attribute_street_address != None: 172 | url = url + '&attribute_street_address=' + attribute_street_address 173 | response = requests.get(url, headers=self.headers).json() 174 | return response 175 | 176 | def lists_list(self, screen_name, reverse=None): 177 | url = 'https://api.twitter.com/1.1/lists/list.json?screen_name=' + screen_name 178 | if reverse != None: 179 | url = url + '&reverse=' + reverse 180 | response = requests.get(url, headers=self.headers).json() 181 | return response 182 | 183 | def lists_members(self, list_id, count=None, cursor=None, include_entities=None, skip_status=None, tweet_mode=None): 184 | url = 'https://api.twitter.com/1.1/lists/members.json?list_id=' + list_id 185 | if count != None: 186 | url = url + '&count=' + count 187 | if cursor != None: 188 | url = url + '&cursor=' + cursor 189 | if include_entities != None: 190 | url = url + '&include_entities=' + include_entities 191 | if skip_status != None: 192 | url = url + '&skip_status=' + skip_status 193 | if tweet_mode != None: 194 | url = url + '&tweet_mode=' + tweet_mode 195 | response = requests.get(url, headers=self.headers).json() 196 | return response 197 | 198 | def lists_memberships(self, screen_name, count=None, cursor=None): 199 | url = 'https://api.twitter.com/1.1/lists/memberships.json?screen_name=' + screen_name 200 | if count != None: 201 | url = url + '&count=' + count 202 | if cursor != None: 203 | url = url + '&cursor=' + cursor 204 | response = requests.get(url, headers=self.headers).json() 205 | return response 206 | 207 | def lists_ownerships(self, screen_name, count=None, cursor=None): 208 | url = 'https://api.twitter.com/1.1/lists/ownerships.json?screen_name=' + screen_name 209 | if count != None: 210 | url = url + '&count=' + count 211 | if cursor != None: 212 | url = url + '&cursor=' + cursor 213 | response = requests.get(url, headers=self.headers).json() 214 | return response 215 | 216 | def lists_show(self, list_id): 217 | url = 'https://api.twitter.com/1.1/lists/show.json?list_id=' + list_id 218 | response = requests.get(url, headers=self.headers).json() 219 | return response 220 | 221 | def lists_statuses(self, list_id, since_id=None, max_id=None, count=None, include_entities=None, include_rts=None, tweet_mode=None): 222 | url = 'https://api.twitter.com/1.1/lists/statuses.json?list_id=' + list_id 223 | if since_id != None: 224 | url = url + '&since_id=' + since_id 225 | if max_id != None: 226 | url = url + '&max_id=' + max_id 227 | if count != None: 228 | url = url + '&count=' + count 229 | if include_entities != None: 230 | url = url + '&include_entities=' + include_entities 231 | if include_rts != None: 232 | url = url + '&include_rts=' + include_rts 233 | if tweet_mode != None: 234 | url = url + '&tweet_mode=' + tweet_mode 235 | response = requests.get(url, headers=self.headers).json() 236 | return response 237 | 238 | def lists_subscribers(self, list_id, count=None, cursor=None, include_entities=None, skip_status=None): 239 | url = 'https://api.twitter.com/1.1/lists/subscribers.json?list_id=' + list_id 240 | if count != None: 241 | url = url + '&count=' + count 242 | if cursor != None: 243 | url = url + '&cursor=' + cursor 244 | if include_entities != None: 245 | url = url + '&include_entities=' + include_entities 246 | if include_entities != None: 247 | url = url + '&include_entities=' + include_entities 248 | if skip_status != None: 249 | url = url + '&skip_status=' + skip_status 250 | response = requests.get(url, headers=self.headers).json() 251 | return response 252 | 253 | def lists_subscriptions(self, screen_name, count=None, cursor=None): 254 | url = 'https://api.twitter.com/1.1/lists/subscriptions.json?screen_name=' + screen_name 255 | if count != None: 256 | url = url + '&count=' + count 257 | if cursor != None: 258 | url = url + '&cursor=' + cursor 259 | response = requests.get(url, headers=self.headers).json() 260 | return response 261 | 262 | def search_tweets(self, q, geocode=None, lang=None, locale=None, result_type=None, count=None, until=None, since_id=None, max_id=None, include_entities=None, tweet_mode=None): 263 | url = 'https://api.twitter.com/1.1/search/tweets.json?q=' + q 264 | if geocode != None: 265 | url = url + '&geocode=' + geocode 266 | if lang != None: 267 | url = url + '&lang=' + lang 268 | if locale != None: 269 | url = url + '&locale=' + locale 270 | if result_type != None: 271 | url = url + '&result_type=' + result_type 272 | if count != None: 273 | url = url + '&count=' + count 274 | if until != None: 275 | url = url + '&until=' + until 276 | if since_id != None: 277 | url = url + '&since_id=' + since_id 278 | if max_id != None: 279 | url = url + '&max_id=' + max_id 280 | if include_entities != None: 281 | url = url + '&include_entities=' + include_entities 282 | if tweet_mode != None: 283 | url = url + '&tweet_mode=' + tweet_mode 284 | response = requests.get(url, headers=self.headers).json() 285 | return response 286 | 287 | def statuses_lookup(self, id, include_entities=None, trim_user=None, map=None, tweet_mode=None): 288 | url = 'https://api.twitter.com/1.1/statuses/lookup.json' 289 | if len(id) != 0: 290 | url = url + '?id=' + ','.join(id) 291 | if include_entities != None: 292 | url = url + '&include_entities=' + include_entities 293 | if trim_user != None: 294 | url = url + '&trim_user=' + trim_user 295 | if map != None: 296 | url = url + '&map=' + map 297 | if tweet_mode != None: 298 | url = url + '&tweet_mode=' + tweet_mode 299 | response = requests.get(url, headers=self.headers).json() 300 | return response 301 | 302 | def statuses_retweeters_ids(self, id, cursor=None, stringify_ids=None): 303 | url = 'https://api.twitter.com/1.1/statuses/retweeters/ids.json?id=' + id 304 | if cursor != None: 305 | url = url + '&cursor=' + cursor 306 | if stringify_ids != None: 307 | url = url + '&stringify_ids=' + stringify_ids 308 | response = requests.get(url, headers=self.headers).json() 309 | return response 310 | 311 | def statuses_retweets(self, id, count=None, trim_user=None): 312 | url = 'https://api.twitter.com/1.1/statuses/retweets/' + id + '.json' 313 | if count != None: 314 | url = url + '&count=' + count 315 | if trim_user != None: 316 | url = url + '&trim_user=' + trim_user 317 | response = requests.get(url, headers=self.headers).json() 318 | return response 319 | 320 | def statuses_show(self, id, trim_user=None, include_entities=None, tweet_mode=None): 321 | url = 'https://api.twitter.com/1.1/statuses/show.json?id=' + id 322 | if trim_user != None: 323 | url = url + '&trim_user=' + trim_user 324 | if include_entities != None: 325 | url = url + '&include_entities=' + include_entities 326 | if tweet_mode != None: 327 | url = url + '&tweet_mode=' + tweet_mode 328 | response = requests.get(url, headers=self.headers).json() 329 | return response 330 | 331 | def statuses_user_timeline(self, screen_name, since_id=None, max_id=None, count=None, trim_user=None, exclude_replies=None, contributor_details=None, include_rts=None, tweet_mode=None): 332 | url = 'https://api.twitter.com/1.1/statuses/user_timeline.json?screen_name=' + screen_name 333 | if since_id != None: 334 | url = url + '&since_id=' + since_id 335 | if max_id != None: 336 | url = url + '&max_id=' + max_id 337 | if count != None: 338 | url = url + '&count=' + count 339 | if max_id != None: 340 | url = url + '&max_id=' + max_id 341 | if trim_user != None: 342 | url = url + '&trim_user=' + trim_user 343 | if exclude_replies != None: 344 | url = url + '&exclude_replies=' + exclude_replies 345 | if contributor_details != None: 346 | url = url + '&contributor_details=' + contributor_details 347 | if include_rts != None: 348 | url = url + '&include_rts=' + include_rts 349 | if tweet_mode != None: 350 | url = url + '&tweet_mode=' + tweet_mode 351 | response = requests.get(url, headers=self.headers).json() 352 | return response 353 | 354 | def trends_available(self): 355 | url = 'https://api.twitter.com/1.1/trends/available.json' 356 | response = requests.get(url, headers=self.headers).json() 357 | return response 358 | 359 | def trends_closest(self, lat, long): 360 | url = 'https://api.twitter.com/1.1/trends/closest.json?lat=' + lat + '&long=' + long 361 | response = requests.get(url, headers=self.headers).json() 362 | return response 363 | 364 | def trends_place(self, id, exclude=None): 365 | url = 'https://api.twitter.com/1.1/trends/place.json?id=' + id 366 | if exclude != None: 367 | url = url + '&exclude=' + exclude 368 | response = requests.get(url, headers=self.headers).json() 369 | return response 370 | 371 | def users_lookup(self, screen_name, include_entities=None, tweet_mode=None): 372 | url = 'https://api.twitter.com/1.1/users/lookup.json' 373 | if len(screen_name) != 0: 374 | url = url + '?screen_name=' + ','.join(screen_name) 375 | if include_entities != None: 376 | url = url + '&include_entities=' + include_entities 377 | if tweet_mode != None: 378 | url = url + '&tweet_mode=' + tweet_mode 379 | response = requests.get(url, headers=self.headers).json() 380 | return response 381 | 382 | def users_search(self, q, page=None, count=None, include_entities=None, tweet_mode=None): 383 | url = 'https://api.twitter.com/1.1/users/search.json?q=' + q 384 | if page != None: 385 | url = url + '&page=' + page 386 | if count != None: 387 | url = url + '&count=' + count 388 | if include_entities != None: 389 | url = url + '&include_entities=' + include_entities 390 | if tweet_mode != None: 391 | url = url + '&tweet_mode=' + tweet_mode 392 | response = requests.get(url, headers=self.headers).json() 393 | return response 394 | 395 | def user_show(self, screen_name, include_entities=None, tweet_mode=None): 396 | url = 'https://api.twitter.com/1.1/users/show.json?screen_name=' + screen_name 397 | if tweet_mode != None: 398 | url = url + '&tweet_mode=' + tweet_mode 399 | response = requests.get(url, headers=self.headers).json() 400 | return response 401 | 402 | ### Twitter API v2 ### 403 | ### OR ### 404 | ### Twitter API Private ### 405 | 406 | def user_tweets(self, screen_name=None, user_id=None): 407 | params = ( 408 | ('userId', user_id), 409 | ) 410 | if screen_name == None: 411 | if user_id == None: 412 | raise TwitterError("Neither 'screen_name' nor 'user_id' was entered.") 413 | else: 414 | response = requests.get('https://api.twitter.com/2/timeline/profile/' + user_id + '.json', headers=self.headers, params=params).json() 415 | else: 416 | user_id = requests.get('https://api.twitter.com/1.1/users/show.json?screen_name=' + screen_name, headers=self.headers).json()["id_str"] 417 | response = requests.get('https://api.twitter.com/2/timeline/profile/' + user_id + '.json', headers=self.headers, params=params).json() 418 | 419 | return response 420 | 421 | def trend(self): 422 | response = requests.get('https://twitter.com/i/api/2/guide.json', headers=self.headers).json() 423 | 424 | return response 425 | 426 | def searchbox(self, text): 427 | params = ( 428 | ('q', text), 429 | ('src', 'search_box'), 430 | ) 431 | response = requests.get('https://twitter.com/i/api/1.1/search/typeahead.json', headers=self.headers, params=params).json() 432 | 433 | return response 434 | 435 | def topic_search(self, text): 436 | params = ( 437 | ('q', text), 438 | ('tweet_search_mode', 'extended'), 439 | ) 440 | response = requests.get('https://twitter.com/i/api/2/search/adaptive.json', headers=self.headers, params=params).json() 441 | 442 | return response 443 | 444 | def latest_search(self, text): 445 | params = ( 446 | ('q', text), 447 | ('tweet_search_mode', 'live'), 448 | ) 449 | response = requests.get('https://twitter.com/i/api/2/search/adaptive.json', headers=self.headers, params=params).json() 450 | 451 | return response 452 | 453 | def image_search(self, text): 454 | params = ( 455 | ('q', text), 456 | ('tweet_mode', 'extended'), 457 | ('result_filter', 'image'), 458 | ) 459 | response = requests.get('https://twitter.com/i/api/2/search/adaptive.json', headers=self.headers, params=params).json() 460 | 461 | return response 462 | 463 | def video_search(self, text): 464 | params = ( 465 | ('q', text), 466 | ('tweet_mode', 'extended'), 467 | ('result_filter', 'video'), 468 | ) 469 | response = requests.get('https://twitter.com/i/api/2/search/adaptive.json', headers=self.headers, params=params).json() 470 | 471 | return response 472 | 473 | def user_search(self, text): 474 | params = ( 475 | ('q', text), 476 | ('tweet_mode', 'extended'), 477 | ('result_filter', 'user'), 478 | ) 479 | response = requests.get('https://twitter.com/i/api/2/search/adaptive.json', headers=self.headers, params=params).json() 480 | 481 | return response 482 | 483 | def screenname_available(self, id): 484 | params = ( 485 | ('username', id), 486 | ) 487 | response = requests.get('https://twitter.com/i/api/i/users/username_available.json', headers=self.headers, params=params).json() 488 | 489 | return response 490 | 491 | def get_status(self, tweetid): 492 | response = requests.get('https://api.twitter.com/2/timeline/conversation/' + tweetid + '.json', headers=self.headers).json() 493 | 494 | return response 495 | 496 | def shadowban_check(self, screen_name=None, user_id=None): 497 | if not screen_name == None: 498 | no_tweet = False 499 | protect = False 500 | 501 | suspend = False 502 | not_found = False 503 | 504 | search_ban = False 505 | search_suggestion_ban = False 506 | ghost_ban = False 507 | reply_deboosting = False 508 | 509 | adaptive = requests.get("https://api.twitter.com/2/search/adaptive.json?q=from:" + screen_name + "&count=20&spelling_corrections=0", headers=self.headers) 510 | typeahead = requests.get("https://api.twitter.com/1.1/search/typeahead.json?src=search_box&result_type=users&q=" + screen_name, headers=self.headers) 511 | show = requests.get("https://api.twitter.com/1.1/users/show.json?screen_name=" + screen_name, headers=self.headers) 512 | 513 | if "errors" in show.json(): 514 | if show.json()["errors"][0]["code"] == 63: 515 | suspend = True 516 | elif show.json()["errors"][0]["code"] == 50: 517 | not_found = True 518 | 519 | else: 520 | if show.json()["protected"] == False: 521 | if "status" in show.json(): 522 | profile = requests.get("https://api.twitter.com/2/timeline/profile/" + str(show.json()["id"]) +".json?include_tweet_replies=1&include_want_retweets=0&include_reply_count=1&count=1000", headers=self.headers) 523 | 524 | if adaptive.json()['globalObjects']['tweets']: 525 | pass 526 | else: 527 | search_ban = True 528 | 529 | if typeahead.json()["num_results"] == 0: 530 | search_suggestion_ban = True 531 | 532 | for i in profile.json()["globalObjects"]["tweets"]: 533 | for _ in profile.json()["globalObjects"]["tweets"][i]: 534 | if _ == "in_reply_to_status_id_str": 535 | conversation = requests.get("https://api.twitter.com/2/timeline/conversation/" + str(profile.json()["globalObjects"]["tweets"][i]["in_reply_to_status_id_str"]) + ".json?include_reply_count=1&send_error_codes=true&count=20", headers=self.headers) 536 | if conversation.status_code == 404: 537 | ghost_ban = True 538 | reply_deboosting = True 539 | else: 540 | deboosting_l = [] 541 | for i in conversation.json()["globalObjects"]["tweets"]: 542 | deboosting_l.append(conversation.json()["globalObjects"]["tweets"][i]["user_id_str"]) 543 | if str(show.json()["id"]) in deboosting_l: 544 | pass 545 | else: 546 | reply_deboosting = True 547 | break 548 | else: 549 | continue 550 | break 551 | 552 | else: 553 | no_tweet = True 554 | else: 555 | protect = True 556 | 557 | elif not user_id == None: 558 | 559 | screen_name = requests.get('https://api.twitter.com/1.1/users/show.json?user_id=' + user_id, headers=self.headers).json()["screen_name"] 560 | 561 | no_tweet = False 562 | protect = False 563 | 564 | suspend = False 565 | not_found = False 566 | 567 | search_ban = False 568 | search_suggestion_ban = False 569 | ghost_ban = False 570 | reply_deboosting = False 571 | 572 | adaptive = requests.get("https://api.twitter.com/2/search/adaptive.json?q=from:" + screen_name + "&count=20&spelling_corrections=0", headers=self.headers) 573 | typeahead = requests.get("https://api.twitter.com/1.1/search/typeahead.json?src=search_box&result_type=users&q=" + screen_name, headers=self.headers) 574 | show = requests.get("https://api.twitter.com/1.1/users/show.json?screen_name=" + screen_name, headers=self.headers) 575 | 576 | if "errors" in show.json(): 577 | if show.json()["errors"][0]["code"] == 63: 578 | suspend = True 579 | elif show.json()["errors"][0]["code"] == 50: 580 | not_found = True 581 | 582 | else: 583 | if show.json()["protected"] == False: 584 | if "status" in show.json(): 585 | profile = requests.get("https://api.twitter.com/2/timeline/profile/" + str(show.json()["id"]) +".json?include_tweet_replies=1&include_want_retweets=0&include_reply_count=1&count=1000", headers=self.headers) 586 | 587 | if adaptive.json()['globalObjects']['tweets']: 588 | pass 589 | else: 590 | search_ban = True 591 | 592 | if typeahead.json()["num_results"] == 0: 593 | search_suggestion_ban = True 594 | 595 | for i in profile.json()["globalObjects"]["tweets"]: 596 | for _ in profile.json()["globalObjects"]["tweets"][i]: 597 | if _ == "in_reply_to_status_id_str": 598 | conversation = requests.get("https://api.twitter.com/2/timeline/conversation/" + str(profile.json()["globalObjects"]["tweets"][i]["in_reply_to_status_id_str"]) + ".json?include_reply_count=1&send_error_codes=true&count=20", headers=self.headers) 599 | if conversation.status_code == 404: 600 | ghost_ban = True 601 | reply_deboosting = True 602 | else: 603 | deboosting_l = [] 604 | for i in conversation.json()["globalObjects"]["tweets"]: 605 | deboosting_l.append(conversation.json()["globalObjects"]["tweets"][i]["user_id_str"]) 606 | if str(show.json()["id"]) in deboosting_l: 607 | pass 608 | else: 609 | reply_deboosting = True 610 | break 611 | else: 612 | continue 613 | break 614 | 615 | else: 616 | no_tweet = True 617 | else: 618 | protect = True 619 | 620 | else: 621 | raise TwitterError("Neither 'screen_name' nor 'user_id' was entered.") 622 | 623 | return {'no_tweet':no_tweet, 'protect':protect, 'suspend':suspend, 'not_found':not_found, 'search_ban':search_ban, 'search_suggestion_ban':search_suggestion_ban, 'ghost_ban':ghost_ban, 'reply_deboosting':reply_deboosting} 624 | 625 | ###ログインありアカウント操作### 626 | 627 | class API(object): 628 | def __init__(self, auth): 629 | self.headersss = { 630 | 'origin': 'https://twitter.com', 631 | 'cookie': 'auth_token=' + auth["auth_token"] + '; ct0=' + auth["ct0"], 632 | 'User-Agent': ua.ie 633 | } 634 | 635 | self.headers = { 636 | 'authorization': 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA', 637 | 'x-csrf-token': auth["ct0"], 638 | 'cookie': 'auth_token=' + auth["auth_token"] + '; ct0=' + auth["ct0"], 639 | 'User-Agent': ua.ie 640 | } 641 | 642 | self.headerss = { 643 | 'authorization': 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA', 644 | 'x-csrf-token': auth["ct0"], 645 | 'content-type': 'application/json', 646 | 'cookie': 'auth_token=' + auth["auth_token"] + '; ct0=' + auth["ct0"], 647 | 'User-Agent': ua.ie 648 | } 649 | 650 | def Login(session_u, session_p): 651 | response = requests.get('https://twitter.com/account/begin_password_reset') 652 | soup = BeautifulSoup(response.text, "lxml") 653 | authenticity = soup.find(attrs={'name':'authenticity_token'}).get('value') 654 | 655 | headers = { 656 | 'cookie': '_mb_tk=' + authenticity, 657 | 'User-Agent': ua.ie 658 | } 659 | 660 | data = { 661 | 'redirect_after_login': '/', 662 | 'remember_me': '1', 663 | 'authenticity_token': authenticity, 664 | 'session[username_or_email]': session_u, 665 | 'session[password]': session_p 666 | } 667 | 668 | response = requests.post('https://twitter.com/sessions', headers=headers, data=data, allow_redirects=False) 669 | print(BeautifulSoup(response.text, "html.parser")) 670 | auth_token = response.cookies.get_dict()["auth_token"] 671 | 672 | response = requests.get('https://twitter.com/i/release_notes') 673 | ct0 = response.cookies.get_dict()["ct0"] 674 | 675 | return {'auth_token':auth_token, 'ct0':ct0} 676 | 677 | def generate_ct0(self): 678 | response = requests.get('https://twitter.com/i/release_notes') 679 | ct0 = response.cookies.get_dict()["ct0"] 680 | 681 | return ct0 682 | 683 | def generate_authenticity(self): 684 | response = requests.get('https://twitter.com/account/begin_password_reset') 685 | soup = BeautifulSoup(response.text, "lxml") 686 | authenticity_token = soup.find(attrs={'name':'authenticity_token'}).get('value') 687 | 688 | return authenticity_token 689 | 690 | def generate_token(self): 691 | headers = { 692 | 'authorization': 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA', 693 | 'User-Agent': ua.ie 694 | } 695 | response = requests.post('https://api.twitter.com/1.1/guest/activate.json', headers=headers).json() 696 | 697 | return response 698 | 699 | def user_info(self, screen_name=None, user_id=None): 700 | if screen_name == None: 701 | if user_id == None: 702 | raise TwitterError("Neither 'screen_name' nor 'user_id' was entered.") 703 | else: 704 | response = requests.get('https://api.twitter.com/1.1/users/show.json?user_id=' + user_id, headers=self.headers).json() 705 | else: 706 | response = requests.get('https://api.twitter.com/1.1/users/show.json?screen_name=' + screen_name, headers=self.headers).json() 707 | 708 | return response 709 | 710 | def user_tweets(self, screen_name=None, user_id=None): 711 | params = ( 712 | ('userId', user_id), 713 | ) 714 | if screen_name == None: 715 | if user_id == None: 716 | raise TwitterError("Neither 'screen_name' nor 'user_id' was entered.") 717 | else: 718 | response = requests.get('https://api.twitter.com/2/timeline/profile/' + user_id + '.json', headers=self.headers, params=params).json() 719 | else: 720 | user_id = requests.get('https://api.twitter.com/1.1/users/show.json?screen_name=' + screen_name, headers=self.headers).json()["id_str"] 721 | response = requests.get('https://api.twitter.com/2/timeline/profile/' + user_id + '.json', headers=self.headers, params=params).json() 722 | 723 | return response 724 | 725 | def trend(self): 726 | response = requests.get('https://twitter.com/i/api/2/guide.json', headers=self.headers).json() 727 | 728 | return response 729 | 730 | def searchbox(self, text): 731 | params = ( 732 | ('q', text), 733 | ('src', 'search_box'), 734 | ) 735 | response = requests.get('https://twitter.com/i/api/1.1/search/typeahead.json', headers=self.headers, params=params).json() 736 | 737 | return response 738 | 739 | def topic_search(self, text): 740 | params = ( 741 | ('q', text), 742 | ('tweet_search_mode', 'extended'), 743 | ) 744 | response = requests.get('https://twitter.com/i/api/2/search/adaptive.json', headers=self.headers, params=params).json() 745 | 746 | return response 747 | 748 | def latest_search(self, text): 749 | params = ( 750 | ('q', text), 751 | ('tweet_search_mode', 'live'), 752 | ) 753 | response = requests.get('https://twitter.com/i/api/2/search/adaptive.json', headers=self.headers, params=params).json() 754 | 755 | return response 756 | 757 | def image_search(self, text): 758 | params = ( 759 | ('q', text), 760 | ('tweet_mode', 'extended'), 761 | ('result_filter', 'image'), 762 | ) 763 | response = requests.get('https://twitter.com/i/api/2/search/adaptive.json', headers=self.headers, params=params).json() 764 | 765 | return response 766 | 767 | def video_search(self, text): 768 | params = ( 769 | ('q', text), 770 | ('tweet_mode', 'extended'), 771 | ('result_filter', 'video'), 772 | ) 773 | response = requests.get('https://twitter.com/i/api/2/search/adaptive.json', headers=self.headers, params=params).json() 774 | 775 | return response 776 | 777 | def user_search(self, text): 778 | params = ( 779 | ('q', text), 780 | ('tweet_mode', 'extended'), 781 | ('result_filter', 'user'), 782 | ) 783 | response = requests.get('https://twitter.com/i/api/2/search/adaptive.json', headers=self.headers, params=params).json() 784 | 785 | return response 786 | 787 | def screenname_available(self, id): 788 | params = ( 789 | ('username', id), 790 | ) 791 | response = requests.get('https://twitter.com/i/api/i/users/username_available.json', headers=self.headers, params=params).json() 792 | 793 | return response 794 | 795 | def get_status(self, tweetid): 796 | response = requests.get('https://api.twitter.com/2/timeline/conversation/' + tweetid + '.json', headers=self.headers).json() 797 | 798 | return response 799 | 800 | 801 | def update_status(self, text, conversation_control=None, in_reply_to_status_id=None, card_uri=None): 802 | if in_reply_to_status_id == None: 803 | if conversation_control == None: 804 | if card_uri == None: 805 | data = { 806 | 'status': text 807 | } 808 | response = requests.post('https://twitter.com/i/api/1.1/statuses/update.json', headers=self.headers, data=data).json() 809 | elif not card_uri == None: 810 | data = { 811 | 'card_uri': card_uri, 812 | 'status': text 813 | } 814 | 815 | response = requests.post('https://twitter.com/i/api/1.1/statuses/update.json', headers=self.headers, data=data).json() 816 | 817 | elif conversation_control == 1: 818 | if card_uri == None: 819 | data = { 820 | 'conversation_control': 'community', 821 | 'status': text 822 | } 823 | response = requests.post('https://twitter.com/i/api/1.1/statuses/update.json', headers=self.headers, data=data).json() 824 | elif not card_uri == None: 825 | data = { 826 | 'card_uri': card_uri, 827 | 'conversation_control': 'community', 828 | 'status': text 829 | } 830 | 831 | response = requests.post('https://twitter.com/i/api/1.1/statuses/update.json', headers=self.headers, data=data).json() 832 | 833 | elif conversation_control == 2: 834 | if card_uri == None: 835 | data = { 836 | 'conversation_control': 'by_invitation', 837 | 'status': text 838 | } 839 | response = requests.post('https://twitter.com/i/api/1.1/statuses/update.json', headers=self.headers, data=data).json() 840 | elif not card_uri == None: 841 | data = { 842 | 'card_uri': card_uri, 843 | 'conversation_control': 'by_invitation', 844 | 'status': text 845 | } 846 | 847 | response = requests.post('https://twitter.com/i/api/1.1/statuses/update.json', headers=self.headers, data=data).json() 848 | 849 | elif not in_reply_to_status_id == None: 850 | if conversation_control == None: 851 | if card_uri == None: 852 | data = { 853 | 'auto_populate_reply_metadata': 'true', 854 | 'in_reply_to_status_id': in_reply_to_status_id, 855 | 'status': text 856 | } 857 | response = requests.post('https://twitter.com/i/api/1.1/statuses/update.json', headers=self.headers, data=data).json() 858 | elif not card_uri == None: 859 | data = { 860 | 'auto_populate_reply_metadata': 'true', 861 | 'in_reply_to_status_id': in_reply_to_status_id, 862 | 'card_uri': card_uri, 863 | 'status': text 864 | } 865 | 866 | response = requests.post('https://twitter.com/i/api/1.1/statuses/update.json', headers=self.headers, data=data).json() 867 | 868 | elif conversation_control == 1: 869 | if card_uri == None: 870 | data = { 871 | 'auto_populate_reply_metadata': 'true', 872 | 'in_reply_to_status_id': in_reply_to_status_id, 873 | 'conversation_control': 'community', 874 | 'status': text 875 | } 876 | response = requests.post('https://twitter.com/i/api/1.1/statuses/update.json', headers=self.headers, data=data).json() 877 | elif not card_uri == None: 878 | data = { 879 | 'card_uri': card_uri, 880 | 'auto_populate_reply_metadata': 'true', 881 | 'in_reply_to_status_id': in_reply_to_status_id, 882 | 'conversation_control': 'community', 883 | 'status': text 884 | } 885 | 886 | response = requests.post('https://twitter.com/i/api/1.1/statuses/update.json', headers=self.headers, data=data).json() 887 | 888 | elif conversation_control == 2: 889 | if card_uri == None: 890 | data = { 891 | 'auto_populate_reply_metadata': 'true', 892 | 'in_reply_to_status_id': in_reply_to_status_id, 893 | 'conversation_control': 'by_invitation', 894 | 'status': text 895 | } 896 | response = requests.post('https://twitter.com/i/api/1.1/statuses/update.json', headers=self.headers, data=data).json() 897 | elif not card_uri == None: 898 | data = { 899 | 'card_uri': card_uri, 900 | 'auto_populate_reply_metadata': 'true', 901 | 'in_reply_to_status_id': in_reply_to_status_id, 902 | 'conversation_control': 'by_invitation', 903 | 'status': text 904 | } 905 | 906 | response = requests.post('https://twitter.com/i/api/1.1/statuses/update.json', headers=self.headers, data=data).json() 907 | 908 | return response 909 | 910 | def get_dm(self): 911 | 912 | response = requests.get('https://twitter.com/i/api/1.1/dm/inbox_initial_state.json', headers=self.headers).json() 913 | 914 | return response 915 | 916 | def send_dm(self, text, screen_name=None, user_id=None): 917 | if screen_name == None: 918 | if user_id == None: 919 | raise TwitterError("Neither 'screen_name' nor 'user_id' was entered.") 920 | else: 921 | data = { 922 | 'recipient_ids': user_id, 923 | 'text': text 924 | } 925 | 926 | response = requests.post('https://twitter.com/i/api/1.1/dm/new.json', headers=self.headers, data=data).json() 927 | 928 | else: 929 | response = requests.get('https://api.twitter.com/1.1/users/show.json?screen_name=' + screen_name, headers=self.headers).json() 930 | data = { 931 | 'recipient_ids': response['id'], 932 | 'text': text 933 | } 934 | 935 | response = requests.post('https://twitter.com/i/api/1.1/dm/new.json', headers=self.headers, data=data).json() 936 | 937 | return response 938 | 939 | def delete_dm(self, conversation_id_1=None, conversation_id_2=None): 940 | response = requests.post('post https://twitter.com/i/api/1.1/dm/conversation/' + int(conversation_id_1) + '-' + int(conversation_id_2) + '/delete.json', headers=self.headers).json() 941 | return response 942 | 943 | def destroy_status(self, id): 944 | data = { 945 | 'id': id 946 | } 947 | response = requests.post('https://twitter.com/i/api/1.1/statuses/destroy.json', headers=self.headers, data=data).json() 948 | 949 | return response 950 | 951 | def create_favorite(self, id): 952 | data = { 953 | 'id': id 954 | } 955 | response = requests.post('https://twitter.com/i/api/1.1/favorites/create.json', headers=self.headers, data=data).json() 956 | 957 | return response 958 | 959 | def destroy_favorite(self, id): 960 | data = { 961 | 'id': id 962 | } 963 | response = requests.post('https://twitter.com/i/api/1.1/favorites/destroy.json', headers=self.headers, data=data).json() 964 | 965 | return response 966 | 967 | def retweet(self, id): 968 | data = { 969 | 'id': id 970 | } 971 | response = requests.post('https://twitter.com/i/api/1.1/statuses/retweet.json', headers=self.headers, data=data).json() 972 | 973 | return response 974 | 975 | def unretweet(self, id): 976 | data = { 977 | 'id': id 978 | } 979 | response = requests.post('https://twitter.com/i/api/1.1/statuses/unretweet.json', headers=self.headers, data=data).json() 980 | 981 | return response 982 | 983 | def create_friendship(self, screen_name=None, user_id=None): 984 | if screen_name == None: 985 | if user_id == None: 986 | raise TwitterError("Neither 'screen_name' nor 'user_id' was entered.") 987 | else: 988 | data = { 989 | 'id': user_id 990 | } 991 | 992 | response = requests.post('https://twitter.com/i/api/1.1/friendships/create.json', headers=self.headers, data=data).json() 993 | 994 | else: 995 | data = { 996 | 'screen_name': screen_name 997 | } 998 | 999 | response = requests.post('https://twitter.com/i/api/1.1/friendships/create.json', headers=self.headers, data=data).json() 1000 | 1001 | return response 1002 | 1003 | def destroy_friendship(self, screen_name=None, user_id=None): 1004 | if screen_name == None: 1005 | if user_id == None: 1006 | raise TwitterError("Neither 'screen_name' nor 'user_id' was entered.") 1007 | else: 1008 | data = { 1009 | 'id': user_id 1010 | } 1011 | 1012 | response = requests.post('https://twitter.com/i/api/1.1/friendships/destroy.json', headers=self.headers, data=data).json() 1013 | 1014 | else: 1015 | data = { 1016 | 'screen_name': screen_name 1017 | } 1018 | 1019 | response = requests.post('https://twitter.com/i/api/1.1/friendships/destroy.json', headers=self.headers, data=data).json() 1020 | 1021 | return response 1022 | 1023 | def notifications(self): 1024 | response = requests.get('https://twitter.com/i/api/2/notifications/all.json', headers=self.headers).json() 1025 | 1026 | return response 1027 | 1028 | def pin_tweet(self, id): 1029 | data = { 1030 | 'id': id 1031 | } 1032 | 1033 | response = requests.post('https://twitter.com/i/api/1.1/account/pin_tweet.json', headers=self.headers, data=data).json() 1034 | 1035 | return response 1036 | 1037 | def unpin_tweet(self, id): 1038 | data = { 1039 | 'id': id 1040 | } 1041 | 1042 | response = requests.post('https://twitter.com/i/api/1.1/account/unpin_tweet.json', headers=self.headers, data=data).json() 1043 | 1044 | return response 1045 | 1046 | def change_id(self, id): 1047 | data = { 1048 | 'screen_name': id 1049 | } 1050 | 1051 | response = requests.post('https://twitter.com/i/api/1.1/account/settings.json', headers=self.headers, data=data).json() 1052 | 1053 | return response 1054 | 1055 | def private(self, protected): 1056 | if not protected.lower() in ["true", "false"]: 1057 | raise TwitterError("""Please enter "true" or "false".""") 1058 | elif protected.lower() in ["true", "false"]: 1059 | data = { 1060 | 'protected': protected 1061 | } 1062 | 1063 | response = requests.post('https://twitter.com/i/api/1.1/account/settings.json', headers=self.headers, data=data).json() 1064 | 1065 | return response 1066 | 1067 | def gender(self, gender): 1068 | if gender.lower() in ["female", "male"]: 1069 | data = '{"preferences":{"gender_preferences":{"use_gender_for_personalization":true,"gender_override":{"type":"' + gender.lower() + '","value":"' + gender.lower() + '"}}}}' 1070 | 1071 | response = requests.post('https://twitter.com/i/api/1.1/account/settings.json', headers=self.headers, data=data).json() 1072 | else: 1073 | data = '{"preferences":{"gender_preferences":{"use_gender_for_personalization":true,"gender_override":{"type":"custom","value":"' + gender.lower() + '"}}}}' 1074 | 1075 | return response 1076 | 1077 | def protect_password_reset(self, password, protect=None): 1078 | if protect.lower() in ["true", "false"]: 1079 | data = { 1080 | 'protect_password_reset': protect, 1081 | 'current_password': password 1082 | } 1083 | 1084 | response = requests.post('https://twitter.com/i/api/1.1/account/settings.json', headers=self.headers, data=data).json() 1085 | 1086 | else: 1087 | raise TwitterError("""Please enter "true" or "false".""") 1088 | 1089 | return response 1090 | 1091 | def session_revoke(self, hashed_token): 1092 | data = { 1093 | 'hashed_token': hashed_token 1094 | } 1095 | 1096 | response = requests.post('https://twitter.com/i/api/account/sessions/revoke', headers=self.headers, data=data).json() 1097 | 1098 | return response 1099 | 1100 | def sessions_revoke_all(self): 1101 | 1102 | response = requests.post('https://twitter.com/i/api/account/sessions/revoke_all', headers=self.headers).json() 1103 | 1104 | return response 1105 | 1106 | def allow_media_tagging(self, allow_level): 1107 | if allow_level.lower() in ["all", "following", "none"]: 1108 | data = { 1109 | 'allow_media_tagging': allow_level.lower() 1110 | } 1111 | 1112 | response = requests.post('https://twitter.com/i/api/1.1/account/settings.json', headers=self.headers, data=data).json() 1113 | 1114 | else: 1115 | raise TwitterError("""Please enter "all" or "following" or "none".""") 1116 | 1117 | return response 1118 | 1119 | def nsfw(self, nsfw): 1120 | if nsfw.lower() in ["true", "false"]: 1121 | data = { 1122 | 'nsfw_user': nsfw.lower() 1123 | } 1124 | 1125 | response = requests.post('https://twitter.com/i/api/1.1/account/settings.json', headers=self.headers, data=data).json() 1126 | 1127 | else: 1128 | raise TwitterError("""Please enter "true" or "false".""") 1129 | 1130 | return response 1131 | 1132 | def geo_enabled(self, geo): 1133 | if geo.lower() in ["true", "false"]: 1134 | data = { 1135 | 'geo_enabled': geo.lower() 1136 | } 1137 | 1138 | response = requests.post('https://twitter.com/i/api/1.1/account/settings.json', headers=self.headers, data=data).json() 1139 | 1140 | else: 1141 | raise TwitterError("""Please enter "true" or "false".""") 1142 | 1143 | return response 1144 | 1145 | def geo_delete(self): 1146 | response = requests.post('https://twitter.com/i/api/1.1/geo/delete_location_data.json', headers=self.headers).json() 1147 | 1148 | return response 1149 | 1150 | def display_sensitive_media(self, display): 1151 | if display.lower() in ["true", "false"]: 1152 | data = { 1153 | 'display_sensitive_media': display.lower() 1154 | } 1155 | 1156 | response = requests.post('https://twitter.com/i/api/1.1/account/settings.json', headers=self.headers, data=data).json() 1157 | 1158 | else: 1159 | raise TwitterError("""Please enter "true" or "false".""") 1160 | 1161 | return response 1162 | 1163 | def twitter_interests(self): 1164 | response = requests.get('https://twitter.com/i/api/1.1/account/personalization/twitter_interests.json', headers=self.headers).json() 1165 | 1166 | return response 1167 | 1168 | def set_explore(self, places): 1169 | if places.lower() in ["true", "false"]: 1170 | data = { 1171 | 'use_current_location': places.lower() 1172 | } 1173 | 1174 | response = requests.post('https://twitter.com/i/api/2/guide/set_explore_settings.json', headers=self.headers, data=data).json() 1175 | 1176 | else: 1177 | data = { 1178 | 'places': places 1179 | } 1180 | 1181 | response = requests.post('https://twitter.com/i/api/2/guide/set_explore_settings.json', headers=self.headers, data=data).json() 1182 | 1183 | return response 1184 | 1185 | def topic_follow(self, id): 1186 | data = '{"variables":"{\\"topicId\\":\\"' + id + '\\"}"}' 1187 | 1188 | response = requests.post('https://twitter.com/i/api/graphql/4cBaE5ehyzJ1xr5-AoT5cw/TopicFollow', headers=self.headerss, data=data).json() 1189 | 1190 | return response 1191 | 1192 | def topic_unfollow(self, id): 1193 | data = '{"variables":"{\\"topicId\\":\\"' + id + '\\"}"}' 1194 | 1195 | response = requests.post('https://twitter.com/i/api/graphql/v4k95ijrXpxhwGdTWWNc9g/TopicUnfollow', headers=self.headerss, data=data).json() 1196 | 1197 | return response 1198 | 1199 | def followed_topics(self, id): 1200 | params = ( 1201 | ('variables', '{"userId":"' + id + '"}'), 1202 | ) 1203 | 1204 | response = requests.get('https://twitter.com/i/api/graphql/sXXi7qCBNBIXxhMLXpMFgQ/FollowedTopics', headers=self.headerss, params=params).json() 1205 | 1206 | return response 1207 | 1208 | def not_interested_topics(self): 1209 | response = requests.get('https://twitter.com/i/api/graphql/IynHqLeaa4Xm0TT7JuIZZg/NotInterestedTopics', headers=self.headerss).json() 1210 | 1211 | return response 1212 | 1213 | def recommendations(self): 1214 | response = requests.get('https://twitter.com/i/api/1.1/users/recommendations.json', headers=self.headers).json() 1215 | 1216 | return response 1217 | 1218 | def lists_all(self, id): 1219 | params = ( 1220 | ('variables', '{"userId":"' + id + '","withTweetResult":false,"withUserResult":false}'), 1221 | ) 1222 | 1223 | response = requests.get('https://twitter.com/i/api/graphql/zpuJN3UciLfyrdIK-6zuHA/CombinedLists', headers=self.headerss, params=params).json() 1224 | 1225 | return response 1226 | 1227 | def create_list(self, name, private="False", description=""): 1228 | data = '{"variables":"{\\"isPrivate\\":' + private.lower() + ',\\"name\\":\\"' + name + '\\",\\"description\\":\\"' + description + '\\",\\"withUserResult\\":false}"}' 1229 | 1230 | response = requests.post('https://twitter.com/i/api/graphql/uUTfBUYah4ct184vDaV2KA/CreateList', headers=self.headerss, data=data).json() 1231 | 1232 | return response 1233 | 1234 | def destroy_list(self, id): 1235 | data = '{"variables":"{\\"listId\\":\\"' + id + '\\"}"}' 1236 | 1237 | response = requests.post('https://twitter.com/i/api/graphql/UnN9Th1BDbeLjpgjGSpL3Q/DeleteList', headers=self.headerss, data=data).json() 1238 | 1239 | return response 1240 | 1241 | def update_list(self, id, name="", private="False", description=""): 1242 | data = '{"variables":"{\\"listId\\":\\"' + id + '\\",\\"isPrivate\\":' + private.lower() + ',\\"description\\":\\"' + description + '\\",\\"name\\":\\"' + name + '\\",\\"withUserResult\\":false}"}' 1243 | 1244 | response = requests.post('https://twitter.com/i/api/graphql/9CCuAshk9gX5ceEMhc2H5A/UpdateList', headers=self.headerss, data=data).json() 1245 | 1246 | return response 1247 | 1248 | def add_list_member(self, id, user_id): 1249 | data = '{"variables":"{\\"listId\\":\\"' + id + '\\",\\"userId\\":\\"' + user_id + '\\",\\"withUserResult\\":false}"}' 1250 | 1251 | response = requests.post('https://twitter.com/i/api/graphql/1PeyBdMyCv1GtFn10VNL-g/ListAddMember', headers=self.headerss, data=data).json() 1252 | 1253 | return response 1254 | 1255 | def remove_list_member(self, id, user_id): 1256 | data = '{"variables":"{\\"listId\\":\\"' + id + '\\",\\"userId\\":\\"' + user_id + '\\",\\"withUserResult\\":false}"}' 1257 | 1258 | response = requests.post('https://twitter.com/i/api/graphql/DsE0uIywHZ52-Itoq2dhSw/ListRemoveMember', headers=self.headerss, data=data).json() 1259 | 1260 | return response 1261 | 1262 | def list_members(self, id): 1263 | params = ( 1264 | ('variables', '{"listId":"' + id + '","withTweetResult":false,"withUserResult":false}'), 1265 | ) 1266 | 1267 | response = requests.get('https://twitter.com/i/api/graphql/l7oY9paKsUYC1IWil9PF_w/ListMembers', headers=self.headerss, params=params).json() 1268 | 1269 | return response 1270 | 1271 | def create_card(self, quantity, minutes, one="Hello", two="World", three="!", four="byPython"): 1272 | if quantity == 2: 1273 | data = { 1274 | 'card_data': '{"twitter:card":"poll2choice_text_only","twitter:api:api:endpoint":"1","twitter:long:duration_minutes":' + minutes + ',"twitter:string:choice1_label":"' + one + '","twitter:string:choice2_label":"' + two + '"}' 1275 | } 1276 | 1277 | response = requests.post('https://caps.twitter.com/v2/cards/create.json', headers=self.headers, data=data).json() 1278 | 1279 | elif quantity == 3: 1280 | data = { 1281 | 'card_data': '{"twitter:card":"poll3choice_text_only","twitter:api:api:endpoint":"1","twitter:long:duration_minutes":' + minutes + ',"twitter:string:choice1_label":"' + one + '","twitter:string:choice2_label":"' + two + '","twitter:string:choice3_label":"' + three + '"}' 1282 | } 1283 | 1284 | response = requests.post('https://caps.twitter.com/v2/cards/create.json', headers=self.headers, data=data).json() 1285 | 1286 | elif quantity == 4: 1287 | data = { 1288 | 'card_data': '{"twitter:card":"poll4choice_text_only","twitter:api:api:endpoint":"1","twitter:long:duration_minutes":' + minutes + ',"twitter:string:choice1_label":"' + one + '","twitter:string:choice2_label":"' + two + '","twitter:string:choice3_label":"' + three + '","twitter:string:choice4_label":"' + four + '"}' 1289 | } 1290 | 1291 | response = requests.post('https://caps.twitter.com/v2/cards/create.json', headers=self.headers, data=data).json() 1292 | 1293 | else: 1294 | raise TwitterError("Please specify the number of votes between 2 and 4.") 1295 | 1296 | return response 1297 | 1298 | def Twitter_Web_Client(self, text, place_id="", authenticity_token=None): 1299 | if authenticity_token == None: 1300 | response = requests.get('https://twitter.com/account/begin_password_reset') 1301 | soup = BeautifulSoup(response.text, "lxml") 1302 | authenticity_token = soup.find(attrs={'name':'authenticity_token'}).get('value') 1303 | data = { 1304 | 'authenticity_token': authenticity_token, 1305 | 'batch_mode': 'off', 1306 | 'place_id': place_id, 1307 | 'status': text, 1308 | } 1309 | 1310 | response = requests.post('https://twitter.com/i/tweet/create', headers=self.headersss, data=data).json() 1311 | 1312 | elif not authenticity_token == None: 1313 | data = { 1314 | 'authenticity_token': authenticity_token, 1315 | 'batch_mode': 'off', 1316 | 'place_id': place_id, 1317 | 'status': text, 1318 | } 1319 | 1320 | response = requests.post('https://twitter.com/i/tweet/create', headers=self.headersss, data=data).json() 1321 | 1322 | return response 1323 | 1324 | def add_bookmark(self, id): 1325 | data = { 1326 | 'tweet_mode': 'extended', 1327 | 'tweet_id': id 1328 | } 1329 | 1330 | response = requests.post('https://twitter.com/i/api/1.1/bookmark/entries/add.json', headers=self.headers, data=data).json() 1331 | 1332 | return response 1333 | 1334 | def mute_conversation(self, id): 1335 | data = { 1336 | 'tweet_mode': 'extended', 1337 | 'tweet_id': id 1338 | } 1339 | 1340 | response = requests.post('https://twitter.com/i/api/1.1/mutes/conversations/create.json', headers=self.headers, data=data).json() 1341 | 1342 | return response 1343 | 1344 | def unmute_conversation(self, id): 1345 | data = { 1346 | 'tweet_mode': 'extended', 1347 | 'tweet_id': id 1348 | } 1349 | 1350 | response = requests.post('https://twitter.com/i/api/1.1/mutes/conversations/destroy.json', headers=self.headers, data=data).json() 1351 | 1352 | return response 1353 | 1354 | def verify_password(self, password): 1355 | data = { 1356 | 'password': password 1357 | } 1358 | 1359 | response = requests.post('https://twitter.com/i/api/1.1/account/verify_password.json', headers=self.headers, data=data) 1360 | 1361 | return response.json() | response.cookies.get_dict() 1362 | 1363 | def account_data(self, verify=None, password=""): 1364 | if verify == None: 1365 | data = { 1366 | 'password': password 1367 | } 1368 | 1369 | response = requests.post('https://twitter.com/i/api/1.1/account/verify_password.json', headers=self.headers, data=data) 1370 | if "errors" in response.json(): 1371 | raise TwitterError(response.json()["errors"][0]["message"]) 1372 | elif response.json()["status"] == "ok": 1373 | cookie = self.headers["cookie"] + '; _twitter_sess=' + response.cookies.get_dict()["_twitter_sess"] 1374 | self.headers["cookie"] = cookie 1375 | 1376 | response = requests.get('https://twitter.com/i/api/1.1/account/personalization/p13n_data.json', headers=self.headers).json() 1377 | 1378 | elif not verify == None: 1379 | cookie = self.headers["cookie"] + '; _twitter_sess=' + verify 1380 | self.headers["cookie"] = cookie 1381 | 1382 | response = requests.get('https://twitter.com/i/api/1.1/account/personalization/p13n_data.json', headers=self.headers).json() 1383 | 1384 | return response 1385 | 1386 | def shadowban_check(self, screen_name=None, user_id=None): 1387 | if not screen_name == None: 1388 | no_tweet = False 1389 | protect = False 1390 | 1391 | suspend = False 1392 | not_found = False 1393 | 1394 | search_ban = False 1395 | search_suggestion_ban = False 1396 | ghost_ban = False 1397 | reply_deboosting = False 1398 | 1399 | adaptive = requests.get("https://api.twitter.com/2/search/adaptive.json?q=from:" + screen_name + "&count=20&spelling_corrections=0", headers=self.headers) 1400 | typeahead = requests.get("https://api.twitter.com/1.1/search/typeahead.json?src=search_box&result_type=users&q=" + screen_name, headers=self.headers) 1401 | show = requests.get("https://api.twitter.com/1.1/users/show.json?screen_name=" + screen_name, headers=self.headers) 1402 | 1403 | if "errors" in show.json(): 1404 | if show.json()["errors"][0]["code"] == 63: 1405 | suspend = True 1406 | elif show.json()["errors"][0]["code"] == 50: 1407 | not_found = True 1408 | 1409 | else: 1410 | if show.json()["protected"] == False: 1411 | if "status" in show.json(): 1412 | profile = requests.get("https://api.twitter.com/2/timeline/profile/" + str(show.json()["id"]) +".json?include_tweet_replies=1&include_want_retweets=0&include_reply_count=1&count=1000", headers=self.headers) 1413 | 1414 | if adaptive.json()['globalObjects']['tweets']: 1415 | pass 1416 | else: 1417 | search_ban = True 1418 | 1419 | if typeahead.json()["num_results"] == 0: 1420 | search_suggestion_ban = True 1421 | 1422 | for i in profile.json()["globalObjects"]["tweets"]: 1423 | for _ in profile.json()["globalObjects"]["tweets"][i]: 1424 | if _ == "in_reply_to_status_id_str": 1425 | conversation = requests.get("https://api.twitter.com/2/timeline/conversation/" + str(profile.json()["globalObjects"]["tweets"][i]["in_reply_to_status_id_str"]) + ".json?include_reply_count=1&send_error_codes=true&count=20", headers=self.headers) 1426 | if conversation.status_code == 404: 1427 | ghost_ban = True 1428 | reply_deboosting = True 1429 | else: 1430 | deboosting_l = [] 1431 | for i in conversation.json()["globalObjects"]["tweets"]: 1432 | deboosting_l.append(conversation.json()["globalObjects"]["tweets"][i]["user_id_str"]) 1433 | if str(show.json()["id"]) in deboosting_l: 1434 | pass 1435 | else: 1436 | reply_deboosting = True 1437 | break 1438 | else: 1439 | continue 1440 | break 1441 | 1442 | else: 1443 | no_tweet = True 1444 | else: 1445 | protect = True 1446 | 1447 | elif not user_id == None: 1448 | 1449 | screen_name = requests.get('https://api.twitter.com/1.1/users/show.json?user_id=' + user_id, headers=self.headers).json()["screen_name"] 1450 | 1451 | no_tweet = False 1452 | protect = False 1453 | 1454 | suspend = False 1455 | not_found = False 1456 | 1457 | search_ban = False 1458 | search_suggestion_ban = False 1459 | ghost_ban = False 1460 | reply_deboosting = False 1461 | 1462 | adaptive = requests.get("https://api.twitter.com/2/search/adaptive.json?q=from:" + screen_name + "&count=20&spelling_corrections=0", headers=self.headers) 1463 | typeahead = requests.get("https://api.twitter.com/1.1/search/typeahead.json?src=search_box&result_type=users&q=" + screen_name, headers=self.headers) 1464 | show = requests.get("https://api.twitter.com/1.1/users/show.json?screen_name=" + screen_name, headers=self.headers) 1465 | 1466 | if "errors" in show.json(): 1467 | if show.json()["errors"][0]["code"] == 63: 1468 | suspend = True 1469 | elif show.json()["errors"][0]["code"] == 50: 1470 | not_found = True 1471 | 1472 | else: 1473 | if show.json()["protected"] == False: 1474 | if "status" in show.json(): 1475 | profile = requests.get("https://api.twitter.com/2/timeline/profile/" + str(show.json()["id"]) +".json?include_tweet_replies=1&include_want_retweets=0&include_reply_count=1&count=1000", headers=self.headers) 1476 | 1477 | if adaptive.json()['globalObjects']['tweets']: 1478 | pass 1479 | else: 1480 | search_ban = True 1481 | 1482 | if typeahead.json()["num_results"] == 0: 1483 | search_suggestion_ban = True 1484 | 1485 | for i in profile.json()["globalObjects"]["tweets"]: 1486 | for _ in profile.json()["globalObjects"]["tweets"][i]: 1487 | if _ == "in_reply_to_status_id_str": 1488 | conversation = requests.get("https://api.twitter.com/2/timeline/conversation/" + str(profile.json()["globalObjects"]["tweets"][i]["in_reply_to_status_id_str"]) + ".json?include_reply_count=1&send_error_codes=true&count=20", headers=self.headers) 1489 | if conversation.status_code == 404: 1490 | ghost_ban = True 1491 | reply_deboosting = True 1492 | else: 1493 | deboosting_l = [] 1494 | for i in conversation.json()["globalObjects"]["tweets"]: 1495 | deboosting_l.append(conversation.json()["globalObjects"]["tweets"][i]["user_id_str"]) 1496 | if str(show.json()["id"]) in deboosting_l: 1497 | pass 1498 | else: 1499 | reply_deboosting = True 1500 | break 1501 | else: 1502 | continue 1503 | break 1504 | 1505 | else: 1506 | no_tweet = True 1507 | else: 1508 | protect = True 1509 | 1510 | else: 1511 | raise TwitterError("Neither 'screen_name' nor 'user_id' was entered.") 1512 | 1513 | return {'no_tweet':no_tweet, 'protect':protect, 'suspend':suspend, 'not_found':not_found, 'search_ban':search_ban, 'search_suggestion_ban':search_suggestion_ban, 'ghost_ban':ghost_ban, 'reply_deboosting':reply_deboosting} 1514 | 1515 | def change_password(self, old, new): 1516 | 1517 | data = { 1518 | 'current_password': old, 1519 | 'password': new, 1520 | 'password_confirmation': new 1521 | } 1522 | 1523 | response = requests.post('https://twitter.com/i/api/i/account/change_password.json', headers=self.headers, data=data).json() 1524 | 1525 | return response 1526 | --------------------------------------------------------------------------------