twitter-openapi-python 0.0.23__tar.gz → 0.0.26__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- twitter_openapi_python-0.0.26/PKG-INFO +102 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/README.md +39 -3
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/pyproject.toml +2 -2
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/setup.py +15 -5
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/api/post_api.py +25 -6
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/client.py +62 -46
- twitter_openapi_python-0.0.26/twitter_openapi_python.egg-info/PKG-INFO +102 -0
- twitter_openapi_python-0.0.26/twitter_openapi_python.egg-info/requires.txt +2 -0
- twitter_openapi_python-0.0.23/PKG-INFO +0 -15
- twitter_openapi_python-0.0.23/twitter_openapi_python.egg-info/PKG-INFO +0 -15
- twitter_openapi_python-0.0.23/twitter_openapi_python.egg-info/requires.txt +0 -2
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/LICENSE +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/LICENSE.AGPL +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/setup.cfg +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/__init__.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/api/__init__.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/api/default_api.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/api/initial_state_api.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/api/tweet_api.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/api/user_api.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/api/user_list_api.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/api/users_api.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/api/v11_get_api.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/api/v11_post_api.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/models/__init__.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/models/base.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/models/header.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/models/initial_state.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/models/response.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/models/timeline.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/py.typed +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/utils/__init__.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/utils/api.py +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python.egg-info/SOURCES.txt +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python.egg-info/dependency_links.txt +0 -0
- {twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: twitter_openapi_python
|
|
3
|
+
Version: 0.0.26
|
|
4
|
+
Summary: Twitter OpenAPI
|
|
5
|
+
Home-page: https://github.com/fa0311/twitter_openapi_python
|
|
6
|
+
Author: fa0311
|
|
7
|
+
Author-email: yuki@yuki0311.com
|
|
8
|
+
License: proprietary or AGPL-3.0-or-later
|
|
9
|
+
Keywords: OpenAPI,OpenAPI-Generator,Twitter OpenAPI
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
License-File: LICENSE.AGPL
|
|
13
|
+
|
|
14
|
+
# twitter_openapi_python
|
|
15
|
+
|
|
16
|
+
Twitter scraping with data validation by pydantic.
|
|
17
|
+
|
|
18
|
+

|
|
19
|
+
|
|
20
|
+
## Setup
|
|
21
|
+
|
|
22
|
+
```shell
|
|
23
|
+
pip install twitter-openapi-python
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import json
|
|
30
|
+
import datetime
|
|
31
|
+
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
from tweepy_authlib import CookieSessionUserHandler
|
|
34
|
+
from twitter_openapi_python import TwitterOpenapiPython
|
|
35
|
+
|
|
36
|
+
# login by tweepy_authlib
|
|
37
|
+
if Path("cookie.json").exists():
|
|
38
|
+
with open("cookie.json", "r") as f:
|
|
39
|
+
cookies_dict = json.load(f)
|
|
40
|
+
if isinstance(cookies_dict, list):
|
|
41
|
+
cookies_dict = {k["name"]: k["value"] for k in cookies_dict}
|
|
42
|
+
else:
|
|
43
|
+
auth_handler = CookieSessionUserHandler(
|
|
44
|
+
screen_name=input("screen_name: "),
|
|
45
|
+
password=input("password: "),
|
|
46
|
+
)
|
|
47
|
+
cookies_dict = auth_handler.get_cookies().get_dict()
|
|
48
|
+
|
|
49
|
+
# To extract cookies from Windows (Linux by default)
|
|
50
|
+
# If you use tweepy_authlib, you must be on Windows
|
|
51
|
+
client = TwitterOpenapiPython()
|
|
52
|
+
client.additional_api_headers = {
|
|
53
|
+
"sec-ch-ua-platform": '"Windows"',
|
|
54
|
+
}
|
|
55
|
+
client.additional_browser_headers = {
|
|
56
|
+
"sec-ch-ua-platform": '"Windows"',
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# get client from cookies
|
|
60
|
+
撫 = client.get_client_from_cookies(cookies=cookies_dict)
|
|
61
|
+
|
|
62
|
+
# tweet "Hello World!!" with current time
|
|
63
|
+
time = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
64
|
+
撫.get_post_api().post_create_tweet(tweet_text=f"Hello World!!{time}")
|
|
65
|
+
|
|
66
|
+
# get user info
|
|
67
|
+
response = 撫.get_user_api().get_user_by_screen_name("elonmusk")
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Login
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from twitter_openapi_python import TwitterOpenapiPython
|
|
74
|
+
|
|
75
|
+
# guest client
|
|
76
|
+
撫 = TwitterOpenapiPython().get_guest_client()
|
|
77
|
+
tweet = 撫.get_default_api().get_tweet_result_by_rest_id("1349129669258448897")
|
|
78
|
+
assert tweet.data is not None
|
|
79
|
+
assert tweet.data.tweet.legacy is not None
|
|
80
|
+
print(tweet.data.tweet.legacy.full_text)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Multiple OS
|
|
84
|
+
|
|
85
|
+
The Token can only be used on the same OS that issued the Token
|
|
86
|
+
In other words, if the sec-ch-ua-platform does not match, the Token cannot be used.
|
|
87
|
+
This library uses the Linux Chrome header by default.
|
|
88
|
+
To use Token issued by Windows, do the following.
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
client = TwitterOpenapiPython()
|
|
92
|
+
client.additional_api_headers = {
|
|
93
|
+
"sec-ch-ua-platform": '"Windows"',
|
|
94
|
+
};
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
This project is dual licensed. You can choose one of the following licenses:
|
|
100
|
+
|
|
101
|
+
- [Custom License](./LICENSE)
|
|
102
|
+
- [GNU Affero General Public License v3.0](./LICENSE.AGPL)
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
|
|
2
1
|
# twitter_openapi_python
|
|
3
2
|
|
|
4
3
|
Twitter scraping with data validation by pydantic.
|
|
5
4
|
|
|
6
5
|

|
|
7
6
|
|
|
7
|
+
## Setup
|
|
8
|
+
|
|
8
9
|
```shell
|
|
9
10
|
pip install twitter-openapi-python
|
|
10
11
|
```
|
|
11
12
|
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
12
15
|
```python
|
|
13
16
|
import json
|
|
14
17
|
import datetime
|
|
@@ -30,8 +33,18 @@ else:
|
|
|
30
33
|
)
|
|
31
34
|
cookies_dict = auth_handler.get_cookies().get_dict()
|
|
32
35
|
|
|
36
|
+
# To extract cookies from Windows (Linux by default)
|
|
37
|
+
# If you use tweepy_authlib, you must be on Windows
|
|
38
|
+
client = TwitterOpenapiPython()
|
|
39
|
+
client.additional_api_headers = {
|
|
40
|
+
"sec-ch-ua-platform": '"Windows"',
|
|
41
|
+
}
|
|
42
|
+
client.additional_browser_headers = {
|
|
43
|
+
"sec-ch-ua-platform": '"Windows"',
|
|
44
|
+
}
|
|
45
|
+
|
|
33
46
|
# get client from cookies
|
|
34
|
-
𝕏 =
|
|
47
|
+
𝕏 = client.get_client_from_cookies(cookies=cookies_dict)
|
|
35
48
|
|
|
36
49
|
# tweet "Hello World!!" with current time
|
|
37
50
|
time = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
@@ -41,6 +54,8 @@ time = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
|
41
54
|
response = 𝕏.get_user_api().get_user_by_screen_name("elonmusk")
|
|
42
55
|
```
|
|
43
56
|
|
|
57
|
+
### Login
|
|
58
|
+
|
|
44
59
|
```python
|
|
45
60
|
from twitter_openapi_python import TwitterOpenapiPython
|
|
46
61
|
|
|
@@ -50,4 +65,25 @@ tweet = 𝕏.get_default_api().get_tweet_result_by_rest_id("1349129669258448897"
|
|
|
50
65
|
assert tweet.data is not None
|
|
51
66
|
assert tweet.data.tweet.legacy is not None
|
|
52
67
|
print(tweet.data.tweet.legacy.full_text)
|
|
53
|
-
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Multiple OS
|
|
71
|
+
|
|
72
|
+
The Token can only be used on the same OS that issued the Token
|
|
73
|
+
In other words, if the sec-ch-ua-platform does not match, the Token cannot be used.
|
|
74
|
+
This library uses the Linux Chrome header by default.
|
|
75
|
+
To use Token issued by Windows, do the following.
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
client = TwitterOpenapiPython()
|
|
79
|
+
client.additional_api_headers = {
|
|
80
|
+
"sec-ch-ua-platform": '"Windows"',
|
|
81
|
+
};
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
This project is dual licensed. You can choose one of the following licenses:
|
|
87
|
+
|
|
88
|
+
- [Custom License](./LICENSE)
|
|
89
|
+
- [GNU Affero General Public License v3.0](./LICENSE.AGPL)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "twitter_openapi_python"
|
|
3
|
-
version = "0.0.
|
|
3
|
+
version = "0.0.26"
|
|
4
4
|
description = "Twitter OpenAPI"
|
|
5
5
|
authors = ["fa0311 <yuki@yuki0311.com>"]
|
|
6
6
|
license = "proprietary" # or "AGPL-3.0-only"
|
|
@@ -14,7 +14,7 @@ include = ["twitter_openapi_python/py.typed"]
|
|
|
14
14
|
python = "^3.7"
|
|
15
15
|
pydantic = ">=2.6"
|
|
16
16
|
|
|
17
|
-
twitter-openapi-python-generated = "0.0.
|
|
17
|
+
twitter-openapi-python-generated = "0.0.24"
|
|
18
18
|
|
|
19
19
|
[tool.poetry.dev-dependencies]
|
|
20
20
|
|
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
# coding: utf-8
|
|
2
2
|
|
|
3
|
+
import re
|
|
4
|
+
|
|
3
5
|
from setuptools import find_packages, setup
|
|
4
6
|
|
|
5
7
|
NAME = "twitter_openapi_python"
|
|
6
|
-
VERSION = "0.0.
|
|
8
|
+
VERSION = "0.0.26"
|
|
7
9
|
PYTHON_REQUIRES = ">=3.7"
|
|
8
10
|
REQUIRES = [
|
|
9
|
-
"twitter_openapi_python_generated == 0.0.
|
|
11
|
+
"twitter_openapi_python_generated == 0.0.24",
|
|
10
12
|
"pydantic >= 2.6",
|
|
11
13
|
]
|
|
14
|
+
GITHUB_RAW_URL = "https://raw.githubusercontent.com/fa0311/twitter_openapi_python/refs/heads/master/twitter_openapi_python/"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def image_replace(text: str, url: str):
|
|
18
|
+
return re.sub(
|
|
19
|
+
r"!\[(.*?)\]\((.*?)\)",
|
|
20
|
+
r"",
|
|
21
|
+
text,
|
|
22
|
+
)
|
|
23
|
+
|
|
12
24
|
|
|
13
25
|
setup(
|
|
14
26
|
name=NAME,
|
|
@@ -23,8 +35,6 @@ setup(
|
|
|
23
35
|
include_package_data=True,
|
|
24
36
|
license="proprietary or AGPL-3.0-or-later",
|
|
25
37
|
long_description_content_type="text/markdown",
|
|
26
|
-
long_description=""
|
|
27
|
-
Twitter scraping with data validation by pydantic.
|
|
28
|
-
""", # noqa: E501
|
|
38
|
+
long_description=image_replace(open("README.md").read(), GITHUB_RAW_URL),
|
|
29
39
|
package_data={"twitter_openapi_python": ["py.typed"]},
|
|
30
40
|
)
|
|
@@ -31,6 +31,10 @@ class PostApiUtils:
|
|
|
31
31
|
self,
|
|
32
32
|
tweet_text: str,
|
|
33
33
|
media_ids: Optional[list[str]] = None,
|
|
34
|
+
tagged_users: Optional[list[list[str]]] = None,
|
|
35
|
+
in_reply_to_tweet_id: Optional[str] = None,
|
|
36
|
+
attachment_url: Optional[str] = None,
|
|
37
|
+
conversation_control: Optional[str] = None,
|
|
34
38
|
) -> ResponseType[models.CreateTweetResponse]:
|
|
35
39
|
variables = non_nullable(
|
|
36
40
|
twitter.PostCreateTweetRequestVariables.from_dict(
|
|
@@ -43,13 +47,28 @@ class PostApiUtils:
|
|
|
43
47
|
)
|
|
44
48
|
)
|
|
45
49
|
variables.tweet_text = tweet_text
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
if media_ids:
|
|
51
|
+
tagged_or = tagged_users or []
|
|
52
|
+
variables.media.media_entities = [
|
|
53
|
+
twitter.PostCreateTweetRequestVariablesMediaMediaEntitiesInner(
|
|
54
|
+
media_id=media_id,
|
|
55
|
+
tagged_users=tagged_or[idx] if len(tagged_or) > idx else [],
|
|
56
|
+
)
|
|
57
|
+
for idx, media_id in enumerate(media_ids)
|
|
58
|
+
]
|
|
59
|
+
variables.attachment_url = attachment_url
|
|
60
|
+
if conversation_control:
|
|
61
|
+
variables.conversation_control = (
|
|
62
|
+
twitter.PostCreateTweetRequestVariablesConversationControl(
|
|
63
|
+
mode=conversation_control
|
|
64
|
+
)
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if in_reply_to_tweet_id:
|
|
68
|
+
variables.reply = twitter.PostCreateTweetRequestVariablesReply(
|
|
69
|
+
exclude_reply_user_ids=[],
|
|
70
|
+
in_reply_to_tweet_id=in_reply_to_tweet_id,
|
|
50
71
|
)
|
|
51
|
-
for media_id in media_ids or []
|
|
52
|
-
]
|
|
53
72
|
|
|
54
73
|
res = self.api.post_create_tweet_with_http_info(
|
|
55
74
|
path_query_id=self.flag["CreateTweet"]["queryId"],
|
{twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/client.py
RENAMED
|
@@ -58,43 +58,60 @@ class TwitterOpenapiPythonClient:
|
|
|
58
58
|
|
|
59
59
|
|
|
60
60
|
class TwitterOpenapiPython:
|
|
61
|
-
hash: str = "
|
|
61
|
+
hash: str = "4b27150977e1bdd807de8969dc0ddd7918ac9923"
|
|
62
62
|
placeholder_url = "https://raw.githubusercontent.com/fa0311/twitter-openapi/{hash}/src/config/placeholder.json"
|
|
63
|
-
|
|
64
|
-
user_agent: str = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36"
|
|
63
|
+
header = "https://raw.githubusercontent.com/fa0311/latest-user-agent/refs/heads/main/header.json"
|
|
65
64
|
access_token: str = "AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA"
|
|
65
|
+
twitter_url: str = "https://x.com/home"
|
|
66
|
+
additional_browser_headers = {}
|
|
67
|
+
additional_api_headers = {}
|
|
68
|
+
|
|
69
|
+
def get_header(self) -> tuple[dict[str, str], dict[str, str]]:
|
|
70
|
+
http = urllib3.PoolManager()
|
|
71
|
+
res = http.request("GET", self.header)
|
|
72
|
+
data = json.loads(res.data)
|
|
73
|
+
ignore = ["host", "connection"]
|
|
66
74
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
"
|
|
94
|
-
|
|
95
|
-
"
|
|
96
|
-
|
|
97
|
-
|
|
75
|
+
def getHader(name: str) -> dict[str, str]:
|
|
76
|
+
return {
|
|
77
|
+
key: value for key, value in data[name].items() if key not in ignore
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
{
|
|
82
|
+
**getHader("chrome-fetch"),
|
|
83
|
+
"accept-encoding": "identity",
|
|
84
|
+
"referer": self.twitter_url,
|
|
85
|
+
"priority": "u=1, i",
|
|
86
|
+
"x-twitter-client-language": "en",
|
|
87
|
+
"x-twitter-active-user": "yes",
|
|
88
|
+
# 'x-twitter-auth-type': 'xxxx'
|
|
89
|
+
# 'x-csrf-token': 'xxxx',
|
|
90
|
+
# 'x-guest-token': 'xxxx',
|
|
91
|
+
"authorization": f"Bearer {self.access_token}",
|
|
92
|
+
**self.additional_api_headers,
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
**getHader("chrome"),
|
|
96
|
+
**self.additional_browser_headers,
|
|
97
|
+
},
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
def remove_prefix(self, text: str) -> str:
|
|
101
|
+
if text.startswith("x-twitter-"):
|
|
102
|
+
return text[10:]
|
|
103
|
+
if text.startswith("x-"):
|
|
104
|
+
return text[2:]
|
|
105
|
+
return text
|
|
106
|
+
|
|
107
|
+
def kebab_to_upper_camel(self, text: dict[str, Any]) -> dict[str, Any]:
|
|
108
|
+
res = {}
|
|
109
|
+
for key, value in text.items():
|
|
110
|
+
new_key = "".join(
|
|
111
|
+
[x.capitalize() for x in self.remove_prefix(key).split("-")]
|
|
112
|
+
)
|
|
113
|
+
res[new_key] = value
|
|
114
|
+
return res
|
|
98
115
|
|
|
99
116
|
def cookie_normalize(self, cookie: list[str]) -> dict[str, str]:
|
|
100
117
|
return {
|
|
@@ -117,7 +134,7 @@ class TwitterOpenapiPython:
|
|
|
117
134
|
self,
|
|
118
135
|
cookies: dict[str, str],
|
|
119
136
|
) -> TwitterOpenapiPythonClient:
|
|
120
|
-
api_key = self.
|
|
137
|
+
api_key = self.kebab_to_upper_camel(self.get_header()[0])
|
|
121
138
|
|
|
122
139
|
if cookies.get("ct0"):
|
|
123
140
|
api_key.update({"AuthType": "OAuth2Session"})
|
|
@@ -132,27 +149,28 @@ class TwitterOpenapiPython:
|
|
|
132
149
|
configuration=api_conf,
|
|
133
150
|
cookie=self.cookie_to_str(cookies),
|
|
134
151
|
)
|
|
135
|
-
api_client.user_agent =
|
|
152
|
+
api_client.user_agent = api_key["UserAgent"]
|
|
136
153
|
return self.get_twitter_openapi_python_client(api_client)
|
|
137
154
|
|
|
138
155
|
def get_guest_client(self) -> TwitterOpenapiPythonClient:
|
|
139
156
|
http = urllib3.PoolManager()
|
|
140
157
|
session = {}
|
|
141
158
|
|
|
159
|
+
header = self.get_header()
|
|
160
|
+
|
|
142
161
|
res_1 = http.request(
|
|
143
162
|
"GET",
|
|
144
|
-
|
|
163
|
+
self.twitter_url,
|
|
145
164
|
redirect=False,
|
|
146
|
-
headers=
|
|
165
|
+
headers=header[1],
|
|
147
166
|
)
|
|
148
167
|
cookie = res_1.headers._container["set-cookie"][1:]
|
|
149
168
|
session.update(self.cookie_normalize(cookie))
|
|
150
169
|
res_2 = http.request(
|
|
151
170
|
"GET",
|
|
152
|
-
|
|
171
|
+
self.twitter_url,
|
|
153
172
|
redirect=False,
|
|
154
|
-
headers=
|
|
155
|
-
| {"Cookie": self.cookie_to_str(session)},
|
|
173
|
+
headers=header[1],
|
|
156
174
|
)
|
|
157
175
|
|
|
158
176
|
find = re.findall(r'document.cookie="(.*?)";', res_2.data.decode())
|
|
@@ -161,15 +179,13 @@ class TwitterOpenapiPython:
|
|
|
161
179
|
session.pop("ct0")
|
|
162
180
|
|
|
163
181
|
if not session.get("gt"):
|
|
164
|
-
activate_header =
|
|
165
|
-
"
|
|
166
|
-
"x-twitter-active-user": "yes",
|
|
167
|
-
"x-twitter-client-language": "en",
|
|
182
|
+
activate_header = header[0] | {
|
|
183
|
+
"cookie": self.cookie_to_str(session),
|
|
168
184
|
}
|
|
169
185
|
res_3 = http.request(
|
|
170
186
|
"POST",
|
|
171
187
|
"https://api.x.com/1.1/guest/activate.json",
|
|
172
|
-
headers=activate_header
|
|
188
|
+
headers=activate_header,
|
|
173
189
|
)
|
|
174
190
|
gt = json.loads(res_3.data.decode())["guest_token"]
|
|
175
191
|
session.update({"gt": gt})
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: twitter-openapi-python
|
|
3
|
+
Version: 0.0.26
|
|
4
|
+
Summary: Twitter OpenAPI
|
|
5
|
+
Home-page: https://github.com/fa0311/twitter_openapi_python
|
|
6
|
+
Author: fa0311
|
|
7
|
+
Author-email: yuki@yuki0311.com
|
|
8
|
+
License: proprietary or AGPL-3.0-or-later
|
|
9
|
+
Keywords: OpenAPI,OpenAPI-Generator,Twitter OpenAPI
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
License-File: LICENSE.AGPL
|
|
13
|
+
|
|
14
|
+
# twitter_openapi_python
|
|
15
|
+
|
|
16
|
+
Twitter scraping with data validation by pydantic.
|
|
17
|
+
|
|
18
|
+

|
|
19
|
+
|
|
20
|
+
## Setup
|
|
21
|
+
|
|
22
|
+
```shell
|
|
23
|
+
pip install twitter-openapi-python
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
import json
|
|
30
|
+
import datetime
|
|
31
|
+
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
from tweepy_authlib import CookieSessionUserHandler
|
|
34
|
+
from twitter_openapi_python import TwitterOpenapiPython
|
|
35
|
+
|
|
36
|
+
# login by tweepy_authlib
|
|
37
|
+
if Path("cookie.json").exists():
|
|
38
|
+
with open("cookie.json", "r") as f:
|
|
39
|
+
cookies_dict = json.load(f)
|
|
40
|
+
if isinstance(cookies_dict, list):
|
|
41
|
+
cookies_dict = {k["name"]: k["value"] for k in cookies_dict}
|
|
42
|
+
else:
|
|
43
|
+
auth_handler = CookieSessionUserHandler(
|
|
44
|
+
screen_name=input("screen_name: "),
|
|
45
|
+
password=input("password: "),
|
|
46
|
+
)
|
|
47
|
+
cookies_dict = auth_handler.get_cookies().get_dict()
|
|
48
|
+
|
|
49
|
+
# To extract cookies from Windows (Linux by default)
|
|
50
|
+
# If you use tweepy_authlib, you must be on Windows
|
|
51
|
+
client = TwitterOpenapiPython()
|
|
52
|
+
client.additional_api_headers = {
|
|
53
|
+
"sec-ch-ua-platform": '"Windows"',
|
|
54
|
+
}
|
|
55
|
+
client.additional_browser_headers = {
|
|
56
|
+
"sec-ch-ua-platform": '"Windows"',
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# get client from cookies
|
|
60
|
+
撫 = client.get_client_from_cookies(cookies=cookies_dict)
|
|
61
|
+
|
|
62
|
+
# tweet "Hello World!!" with current time
|
|
63
|
+
time = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
64
|
+
撫.get_post_api().post_create_tweet(tweet_text=f"Hello World!!{time}")
|
|
65
|
+
|
|
66
|
+
# get user info
|
|
67
|
+
response = 撫.get_user_api().get_user_by_screen_name("elonmusk")
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Login
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from twitter_openapi_python import TwitterOpenapiPython
|
|
74
|
+
|
|
75
|
+
# guest client
|
|
76
|
+
撫 = TwitterOpenapiPython().get_guest_client()
|
|
77
|
+
tweet = 撫.get_default_api().get_tweet_result_by_rest_id("1349129669258448897")
|
|
78
|
+
assert tweet.data is not None
|
|
79
|
+
assert tweet.data.tweet.legacy is not None
|
|
80
|
+
print(tweet.data.tweet.legacy.full_text)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Multiple OS
|
|
84
|
+
|
|
85
|
+
The Token can only be used on the same OS that issued the Token
|
|
86
|
+
In other words, if the sec-ch-ua-platform does not match, the Token cannot be used.
|
|
87
|
+
This library uses the Linux Chrome header by default.
|
|
88
|
+
To use Token issued by Windows, do the following.
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
client = TwitterOpenapiPython()
|
|
92
|
+
client.additional_api_headers = {
|
|
93
|
+
"sec-ch-ua-platform": '"Windows"',
|
|
94
|
+
};
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## License
|
|
98
|
+
|
|
99
|
+
This project is dual licensed. You can choose one of the following licenses:
|
|
100
|
+
|
|
101
|
+
- [Custom License](./LICENSE)
|
|
102
|
+
- [GNU Affero General Public License v3.0](./LICENSE.AGPL)
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: twitter_openapi_python
|
|
3
|
-
Version: 0.0.23
|
|
4
|
-
Summary: Twitter OpenAPI
|
|
5
|
-
Home-page: https://github.com/fa0311/twitter_openapi_python
|
|
6
|
-
Author: fa0311
|
|
7
|
-
Author-email: yuki@yuki0311.com
|
|
8
|
-
License: proprietary or AGPL-3.0-or-later
|
|
9
|
-
Keywords: OpenAPI,OpenAPI-Generator,Twitter OpenAPI
|
|
10
|
-
Description-Content-Type: text/markdown
|
|
11
|
-
License-File: LICENSE
|
|
12
|
-
License-File: LICENSE.AGPL
|
|
13
|
-
|
|
14
|
-
Twitter scraping with data validation by pydantic.
|
|
15
|
-
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: twitter-openapi-python
|
|
3
|
-
Version: 0.0.23
|
|
4
|
-
Summary: Twitter OpenAPI
|
|
5
|
-
Home-page: https://github.com/fa0311/twitter_openapi_python
|
|
6
|
-
Author: fa0311
|
|
7
|
-
Author-email: yuki@yuki0311.com
|
|
8
|
-
License: proprietary or AGPL-3.0-or-later
|
|
9
|
-
Keywords: OpenAPI,OpenAPI-Generator,Twitter OpenAPI
|
|
10
|
-
Description-Content-Type: text/markdown
|
|
11
|
-
License-File: LICENSE
|
|
12
|
-
License-File: LICENSE.AGPL
|
|
13
|
-
|
|
14
|
-
Twitter scraping with data validation by pydantic.
|
|
15
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/py.typed
RENAMED
|
File without changes
|
|
File without changes
|
{twitter_openapi_python-0.0.23 → twitter_openapi_python-0.0.26}/twitter_openapi_python/utils/api.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|