|
#!/usr/bin/env python |
|
|
|
from argparse import ArgumentParser |
|
from base64 import urlsafe_b64encode |
|
from hashlib import sha256 |
|
from pprint import pprint |
|
from secrets import token_urlsafe |
|
from sys import exit |
|
from urllib.parse import urlencode |
|
from webbrowser import open as open_url |
|
|
|
import requests |
|
|
|
# Latest app version can be found using GET /v1/application-info/android |
|
USER_AGENT = "PixivAndroidApp/5.0.234 (Android 11; Pixel 5)" |
|
REDIRECT_URI = "https://app-api.pixiv.net/web/v1/users/auth/pixiv/callback" |
|
LOGIN_URL = "https://app-api.pixiv.net/web/v1/login" |
|
AUTH_TOKEN_URL = "https://oauth.secure.pixiv.net/auth/token" |
|
CLIENT_ID = "MOBrBDS8blbauoSck0ZfDbtuzpyT" |
|
CLIENT_SECRET = "lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj" |
|
|
|
|
|
def s256(data): |
|
"""S256 transformation method.""" |
|
|
|
return urlsafe_b64encode(sha256(data).digest()).rstrip(b"=").decode("ascii") |
|
|
|
|
|
def oauth_pkce(transform): |
|
"""Proof Key for Code Exchange by OAuth Public Clients (RFC7636).""" |
|
|
|
code_verifier = token_urlsafe(32) |
|
code_challenge = transform(code_verifier.encode("ascii")) |
|
|
|
return code_verifier, code_challenge |
|
|
|
|
|
def print_auth_token_response(response): |
|
data = response.json() |
|
|
|
try: |
|
access_token = data["access_token"] |
|
refresh_token = data["refresh_token"] |
|
except KeyError: |
|
print("error:") |
|
pprint(data) |
|
exit(1) |
|
|
|
print("access_token:", access_token) |
|
print("refresh_token:", refresh_token) |
|
print("expires_in:", data.get("expires_in", 0)) |
|
|
|
|
|
def login(): |
|
code_verifier, code_challenge = oauth_pkce(s256) |
|
login_params = { |
|
"code_challenge": code_challenge, |
|
"code_challenge_method": "S256", |
|
"client": "pixiv-android", |
|
} |
|
|
|
open_url(f"{LOGIN_URL}?{urlencode(login_params)}") |
|
|
|
try: |
|
code = input("code: ").strip() |
|
except (EOFError, KeyboardInterrupt): |
|
return |
|
|
|
response = requests.post( |
|
AUTH_TOKEN_URL, |
|
data={ |
|
"client_id": CLIENT_ID, |
|
"client_secret": CLIENT_SECRET, |
|
"code": code, |
|
"code_verifier": code_verifier, |
|
"grant_type": "authorization_code", |
|
"include_policy": "true", |
|
"redirect_uri": REDIRECT_URI, |
|
}, |
|
headers={"User-Agent": USER_AGENT}, |
|
) |
|
|
|
print_auth_token_response(response) |
|
|
|
|
|
def refresh(refresh_token): |
|
response = requests.post( |
|
AUTH_TOKEN_URL, |
|
data={ |
|
"client_id": CLIENT_ID, |
|
"client_secret": CLIENT_SECRET, |
|
"grant_type": "refresh_token", |
|
"include_policy": "true", |
|
"refresh_token": refresh_token, |
|
}, |
|
headers={"User-Agent": USER_AGENT}, |
|
) |
|
print_auth_token_response(response) |
|
|
|
|
|
def main(): |
|
parser = ArgumentParser() |
|
subparsers = parser.add_subparsers() |
|
parser.set_defaults(func=lambda _: parser.print_usage()) |
|
login_parser = subparsers.add_parser("login") |
|
login_parser.set_defaults(func=lambda _: login()) |
|
refresh_parser = subparsers.add_parser("refresh") |
|
refresh_parser.add_argument("refresh_token") |
|
refresh_parser.set_defaults(func=lambda ns: refresh(ns.refresh_token)) |
|
args = parser.parse_args() |
|
args.func(args) |
|
|
|
|
|
if __name__ == "__main__": |
|
main() |
Traceback (most recent call last):
File "C:\Users\k2106\go-cqbot\HiBiAPI\hibi\lib\site-packages\urllib3\connectionpool.py", line 703, in urlopen
httplib_response = self._make_request(
File "C:\Users\k2106\go-cqbot\HiBiAPI\hibi\lib\site-packages\urllib3\connectionpool.py", line 386, in _make_request
self._validate_conn(conn)
File "C:\Users\k2106\go-cqbot\HiBiAPI\hibi\lib\site-packages\urllib3\connectionpool.py", line 1042, in validate_conn
conn.connect()
File "C:\Users\k2106\go-cqbot\HiBiAPI\hibi\lib\site-packages\urllib3\connection.py", line 414, in connect
self.sock = ssl_wrap_socket(
File "C:\Users\k2106\go-cqbot\HiBiAPI\hibi\lib\site-packages\urllib3\util\ssl.py", line 449, in ssl_wrap_socket
ssl_sock = ssl_wrap_socket_impl(
File "C:\Users\k2106\go-cqbot\HiBiAPI\hibi\lib\site-packages\urllib3\util\ssl.py", line 493, in _ssl_wrap_socket_impl
return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
File "C:\Users\k2106\AppData\Local\Programs\Python\Python310\lib\ssl.py", line 512, in wrap_socket
return self.sslsocket_class._create(
File "C:\Users\k2106\AppData\Local\Programs\Python\Python310\lib\ssl.py", line 1070, in _create
self.do_handshake()
File "C:\Users\k2106\AppData\Local\Programs\Python\Python310\lib\ssl.py", line 1341, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\k2106\go-cqbot\HiBiAPI\hibi\lib\site-packages\requests\adapters.py", line 489, in send
resp = conn.urlopen(
File "C:\Users\k2106\go-cqbot\HiBiAPI\hibi\lib\site-packages\urllib3\connectionpool.py", line 787, in urlopen
retries = retries.increment(
File "C:\Users\k2106\go-cqbot\HiBiAPI\hibi\lib\site-packages\urllib3\util\retry.py", line 592, in increment
raise MaxRetryError(_pool, url, error or ResponseError(cause))
urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='oauth.secure.pixiv.net', port=443): Max retries exceeded with url: /auth/token (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)')))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\k2106\go-cqbot\HiBiAPI\pixiv_auth.py", line 158, in
main()
File "C:\Users\k2106\go-cqbot\HiBiAPI\pixiv_auth.py", line 154, in main
args.func(args)
File "C:\Users\k2106\go-cqbot\HiBiAPI\pixiv_auth.py", line 149, in
login_parser.set_defaults(func=lambda _: login())
File "C:\Users\k2106\go-cqbot\HiBiAPI\pixiv_auth.py", line 101, in login
response = requests.post(
File "C:\Users\k2106\go-cqbot\HiBiAPI\hibi\lib\site-packages\requests\api.py", line 115, in post
return request("post", url, data=data, json=json, **kwargs)
File "C:\Users\k2106\go-cqbot\HiBiAPI\hibi\lib\site-packages\requests\api.py", line 59, in request
return session.request(method=method, url=url, **kwargs)
File "C:\Users\k2106\go-cqbot\HiBiAPI\hibi\lib\site-packages\requests\sessions.py", line 587, in request
resp = self.send(prep, **send_kwargs)
File "C:\Users\k2106\go-cqbot\HiBiAPI\hibi\lib\site-packages\requests\sessions.py", line 701, in send
r = adapter.send(request, **kwargs)
File "C:\Users\k2106\go-cqbot\HiBiAPI\hibi\lib\site-packages\requests\adapters.py", line 563, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='oauth.secure.pixiv.net', port=443): Max retries exceeded with url: /auth/token (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:997)')))
I've set up a pixiv-nginx, which works as a Reverse Proxy, when done, I can access pixiv in my browser and get the code through F12, but when I run the script it raised the error above. How can I fix the problem?
我设置了pixiv-nginx,原理是对pixiv进行反代,设置完之后我可以再浏览器里访问pixiv并且从F12里找到code,但是我运行这个脚本的时候出现了如上报错。请问我如何解决这个问题?
(The meaning of the English and Chinese should be the same.)