Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Mikubill authored Aug 25, 2021
2 parents 12adfae + a508287 commit d790daa
Show file tree
Hide file tree
Showing 13 changed files with 367 additions and 84 deletions.
1 change: 1 addition & 0 deletions .github/workflows/python-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ jobs:
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
run: |
python3 socks5_server.py&
coverage run test.py
codecov --token=$CODECOV_TOKEN
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dumpObj.py
url.txt

# pypi
venv/
dist/
build/
PixivPy.egg-info/
Expand Down
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ _Based on PixivPy: https://github.com/upbit/pixivpy_
pip install pixivpy-async
```

## Or install with socks proxy support:
```bash
pip install pixivpy-async[socks]
```

## Import Package

Import **async** pixivpy:
Expand Down Expand Up @@ -76,12 +81,25 @@ Use environment variables, automatically recognized by aiohttp (not support sock

Specify the proxy address, support socks5/socks4/http (not support https)

If use the socks5/socks4 proxy, make sure the package is installed with [socks proxy support](#or-install-with-socks-proxy-support).

```python
...PixivClient(proxy="socks5://127.0.0.1:8080")
...PixivAPI(proxy="socks5://127.0.0.1:8080")
...AppPixivAPI(proxy="socks5://127.0.0.1:8080")
```

If the package is not installed with [socks proxy support](#or-install-with-socks-proxy-support), and your application runs on Windows, please make sure that event loop uses the policy **asyncio.WindowsSelectorEventLoopPolicy** before loop runs. [#issue4536](https://github.com/aio-libs/aiohttp/issues/4536#issuecomment-579740877)

```python
import asyncio

if __name__ == '__main__':
policy = asyncio.WindowsSelectorEventLoopPolicy()
asyncio.set_event_loop_policy(policy)
asyncio.run(...) # use pixivpy_async with socks proxy
```

Note that env will be ignored when a proxy is specified.

## Login
Expand Down Expand Up @@ -115,13 +133,27 @@ await aapi.user_bookmarks_illust(2088434)
await aapi.user_following(7314824)
await aapi.user_follower(275527)
await aapi.user_mypixiv(275527)
await aapi.user_related(...)
await aapi.user_follow_add(...)
await aapi.user_follow_del(...)
await aapi.user_bookmark_tags_illust(...)
await aapi.user_list(...)
await aapi.search_user(...)
await aapi.trending_tags_illust()
await aapi.search_illust(first_tag, search_target='partial_match_for_tags')
await aapi.illust_ranking('day_male')
await aapi.illust_follow(req_auth=True)
await aapi.illust_recommended(req_auth=True)
await aapi.illust_ranking('day', date='2016-08-01')
await aapi.illust_bookmark_detail(...)
await aapi.illust_bookmark_add(...)
await aapi.illust_bookmark_delete(...)
await aapi.download(image_url, path=directory, name=name)
await aapi.search_novel(...)
await aapi.user_novels(...)
await aapi.novel_series(...)
await aapi.novel_detail(...)
await aapi.novel_text(...)

await papi.works(46363414)
await papi.users(1184799)
Expand Down
34 changes: 34 additions & 0 deletions README.zh-cn.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ _基于PixivPy: https://github.com/upbit/pixivpy_
pip install pixivpy-async --upgrade
```

## 或安装本库并安装socks代理支持

```bash
pip install pixivpy-async[socks]
```

## 导入

导入 pixivpy-async:
Expand Down Expand Up @@ -76,12 +82,25 @@ Pixivpy-Async支持多种代理模式,均需在Init时指定。

指定代理地址,支持socks5/socks4/http(不支持https)

如果使用的是socks5/socks4代理,请确保安装的本库拥有[socks代理支持](#或安装本库并安装socks代理支持)

```python
...PixivClient(proxy="socks5://127.0.0.1:8080")
...PixivAPI(proxy="socks5://127.0.0.1:8080")
...AppPixivAPI(proxy="socks5://127.0.0.1:8080")
```

如果本库安装时没有安装[socks代理支持](#或安装本库并安装socks代理支持),并且你的应用运行在Windows上,请确保事件循环在运行前将策略设置为 **asyncio.WindowsSelectorEventLoopPolicy**[#issue4536](https://github.com/aio-libs/aiohttp/issues/4536#issuecomment-579740877)

```python
import asyncio

if __name__ == '__main__':
policy = asyncio.WindowsSelectorEventLoopPolicy()
asyncio.set_event_loop_policy(policy)
asyncio.run(...) # use pixivpy_async with socks proxy
```

注意,指定了proxy后env会被忽略。

## 登录
Expand Down Expand Up @@ -116,16 +135,31 @@ await aapi.user_bookmarks_illust(2088434)
await aapi.user_following(7314824)
await aapi.user_follower(275527)
await aapi.user_mypixiv(275527)
await aapi.user_related(...)
await aapi.user_follow_add(...)
await aapi.user_follow_del(...)
await aapi.user_bookmark_tags_illust(...)
await aapi.user_list(...)
await aapi.search_user(...)

await aapi.trending_tags_illust()
await aapi.search_illust(first_tag, search_target='partial_match_for_tags')
await aapi.illust_ranking('day_male')
await aapi.illust_follow(req_auth=True)
await aapi.illust_recommended(req_auth=True)
await aapi.illust_bookmark_detail(...)
await aapi.illust_bookmark_add(...)
await aapi.illust_bookmark_delete(...)

await aapi.illust_ranking('day', date='2016-08-01')
await aapi.download(image_url, path=directory, name=name)

await aapi.search_novel(...)
await aapi.user_novels(...)
await aapi.novel_series(...)
await aapi.novel_detail(...)
await aapi.novel_text(...)

await papi.works(46363414)
await papi.users(1184799)
await papi.me_feeds(show_r18=0)
Expand Down
2 changes: 1 addition & 1 deletion pixivpy_async/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""
Pixiv API library
"""
__version__ = '1.2.12'
__version__ = '1.2.13'

from .aapi import AppPixivAPI
from .papi import PixivAPI
Expand Down
73 changes: 71 additions & 2 deletions pixivpy_async/aapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,21 @@ async def user_bookmarks_illust(
)
return await self.requests_(method=method, url=url, params=params, auth=req_auth)

async def user_related(
self,
seed_user_id,
filter: str = 'for_ios',
offset: int = None,
req_auth: bool = True
):
method, url = self.api.user_related
params = self.set_params(
seed_user_id=seed_user_id,
filter=filter,
offset=offset
)
return await self.requests_(method=method, url=url, params=params, auth=req_auth)

# 关注用户的新作
# restrict: ["public", "private"]
async def illust_follow(
Expand Down Expand Up @@ -290,10 +305,11 @@ async def illust_recommended(
max_bookmark_id_for_recommend: int = None,
min_bookmark_id_for_recent_illust: int = None,
offset: int = None,
include_ranking_illusts=None,
include_ranking_illusts = None,
bookmark_illust_ids: list = None,
include_privacy_policy=None,
req_auth: bool = True
req_auth: bool = True,
viewed: [int] = None
) -> dict:
if req_auth:
method, url = self.api.illust_recommended_auth
Expand All @@ -303,6 +319,7 @@ async def illust_recommended(
content_type=content_type,
offset=offset,
filter=filter,
viewed=viewed,
bookmark_illust_ids=bookmark_illust_ids,
include_ranking_illusts=include_ranking_illusts,
include_ranking_label=include_ranking_label,
Expand Down Expand Up @@ -596,6 +613,58 @@ async def search_novel(
)
return await self.requests_(method=method, url=url, params=params, auth=req_auth)

async def user_novels(
self,
user_id: int,
filter: str = 'for_ios',
offset: int = None,
req_auth: bool = True
):
method, url = self.api.user_novels
params = self.set_params(
user_id=user_id,
filter=filter,
offset=offset
)
return await self.requests_(method=method, url=url, params=params, auth=req_auth)

async def novel_series(
self,
series_id: int,
filter: str = 'for_ios',
last_order=None,
req_auth: bool = True
):
method, url = self.api.novel_series
params = self.set_params(
series_id=series_id,
filter=filter,
last_order=last_order
)
return await self.requests_(method=method, url=url, params=params, auth=req_auth)

async def novel_detail(
self,
novel_id: int,
req_auth: bool = True
):
method, url = self.api.novel_detail
params = self.set_params(
novel_id=novel_id,
)
return await self.requests_(method=method, url=url, params=params, auth=req_auth)

async def novel_text(
self,
novel_id: int,
req_auth: bool = True
):
method, url = self.api.novel_text
params = self.set_params(
novel_id=novel_id,
)
return await self.requests_(method=method, url=url, params=params, auth=req_auth)

# 特辑详情 (无需登录,调用Web API)
async def showcase_article(
self,
Expand Down
30 changes: 26 additions & 4 deletions pixivpy_async/api.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
class API:
def __init__(self, app_hosts="https://app-api.pixiv.net",
def __init__(self,
app_hosts="https://app-api.pixiv.net",
pub_hosts="https://public-api.secure.pixiv.net",
auth_hosts="https://oauth.secure.pixiv.net"):
self.appv1 = '%s/v1' % app_hosts
Expand All @@ -25,6 +26,10 @@ def user_illusts(self):
def user_bookmarks_illust(self):
return 'GET', '%s/user/bookmarks/illust' % self.appv1

@property
def user_related(self):
return 'GET', '%s/user/related' % self.appv1

@property
def illust_follow(self):
return 'GET', '%s/illust/follow' % self.appv2
Expand Down Expand Up @@ -87,11 +92,11 @@ def user_follower(self):

@property
def user_follow_add(self):
return 'GET', '%s/user/follow/add' % self.appv1
return 'POST', '%s/user/follow/add' % self.appv1

@property
def user_follow_del(self):
return 'GET', '%s/user/follow/add' % self.appv1
return 'POST', '%s/user/follow/delete' % self.appv1

@property
def user_mypixiv(self):
Expand All @@ -113,6 +118,22 @@ def search_user(self):
def search_novel(self):
return 'GET', '%s/search/novel' % self.appv1

@property
def user_novels(self):
return 'GET', '%s/user/novels' % self.appv1

@property
def novel_series(self):
return 'GET', '%s/novel/series' % self.appv2

@property
def novel_detail(self):
return 'GET', '%s/novel/detail' % self.appv2

@property
def novel_text(self):
return 'GET', '%s/novel/text' % self.appv1

"""
Public API
"""
Expand Down Expand Up @@ -169,7 +190,8 @@ def users_works(self, author_id):
return 'GET', '%s/users/%d/works.json' % (self.apiv1, author_id)

def users_favorite_works(self, author_id):
return 'GET', '%s/users/%d/favorite_works.json' % (self.apiv1, author_id)
return 'GET', '%s/users/%d/favorite_works.json' % (self.apiv1,
author_id)

def users_feeds(self, author_id):
return 'GET', '%s/users/%d/feeds.json' % (self.apiv1, author_id)
Expand Down
28 changes: 22 additions & 6 deletions pixivpy_async/client.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import asyncio
import aiohttp
from aiohttp_socks import ProxyConnector
from .bypass_sni import get_bypass_client

from .bypass_sni import get_bypass_client

class PixivClient:
def __init__(self, limit=30, timeout=10, env=False, internal=False, proxy=None, bypass=False):
Expand All @@ -19,20 +18,37 @@ def __init__(self, limit=30, timeout=10, env=False, internal=False, proxy=None,
If you want to use proxy chaining, read https://github.com/romis2012/aiohttp-socks.
"""

if proxy:
try:
from aiohttp_socks import ProxyConnector
self.conn = ProxyConnector.from_url(proxy, limit_per_host=limit)
_flag = False
except ModuleNotFoundError as e:
if proxy.startswith('socks'):
raise e
else:
self.conn = aiohttp.TCPConnector(limit_per_host=limit)
_flag = True
else:
self.conn = aiohttp.TCPConnector(limit_per_host=limit)

self.internal = internal

if bypass:
self.client = get_bypass_client()
else:
if proxy:
self.conn = ProxyConnector.from_url(proxy, limit_per_host=limit)
else:
self.conn = aiohttp.TCPConnector(limit_per_host=limit)
self.client = aiohttp.ClientSession(
connector=self.conn,
timeout=aiohttp.ClientTimeout(total=timeout),
trust_env=env,
)

if proxy and _flag:
from functools import partial
self.client.get = partial(self.client.get, proxy=proxy)
self.client.post = partial(self.client.post, proxy=proxy)

def start(self):
return self.client

Expand Down
5 changes: 4 additions & 1 deletion pixivpy_async/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ def parse_qs(next_url):
query = up.urlparse(next_url).query
for key, value in up.parse_qs(query).items():
if '[' in key and key.endswith(']'):
result_qs[key.split('[')[0]] = value
if key.split('[')[0] in result_qs:
result_qs[key.split('[')[0]].extend(value)
else:
result_qs[key.split('[')[0]] = value
else:
result_qs[key] = value[-1]

Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
aiohttp[speedups]
aiofiles
aiohttp-socks
pysocks
Loading

0 comments on commit d790daa

Please sign in to comment.