Skip to main content

Async API Wrapper for 2ch Imageboard with typings

Project description

api2ch

Python PyPI License: MIT

Python Tests codecov

⚡️ Async API Wrapper for 2ch Imageboard with typings

Docs: https://2ch.hk/api/res/1.html

📝 Table of Contents


🎒 Installation

Just

pip install api2ch

🛠 Examples

Simple

from api2ch import Api2ch

api = Api2ch()

resp = api.threads('vg')
for t in resp.threads[:3]:
    print(f'— {t.subject}, {t.posts_count} 💬, {t.views} 👁')

Output:

— Paradox Thread №6 стрессовый, 771 💬, 1879 👁
— BioWare General: Varric Tethras Edition, 207 💬, 644 👁
— Fate/Grand Order #193, 683 💬, 4804 👁

Simple Async

import asyncio

from api2ch import Api2chAsync


async def main():
    async with Api2chAsync() as api:
        resp = await api.threads('hw')
        for t in resp.threads[:3]:
            print(f'— {t.subject}, {t.posts_count} 💬, {t.views} 👁')


asyncio.run(main())

Output:

— Видеокарты AMD #95, 418 💬, 3778 👁
— Сап. Впервые в этом разделе. Как научится разбираться в железе?, 3 💬, 9 👁
— Ноутбукотред №36, 185 💬, 970 👁

Boards

from api2ch import Api2ch

api = Api2ch()

for board in ('tv', 'hw', 'fiz'):
    c = api.catalog(board)
    print(f'/{c.board} | {c.board_name}, "{c.board_info_outer}", bump limit: {c.bump_limit}')

Output:

/tv | Сериалы, "сериалы для домохозяек, игры престолов в /got/", bump limit: 500
/hw | Компьютерное железо, "железо, видеокарты, ноутбуки, intel, amd, nvidia, ati", bump limit: 500
/fiz | Физкультура, "физкультура, здоровье, сбросить вес, набрать вес, бицуха", bump limit: 800

Boards Async

import asyncio

from api2ch import Api2chAsync


async def main():
    async with Api2chAsync() as api:
        coros = [api.catalog(board) for board in ('spc', 'un', 'math')]

        for coro in asyncio.as_completed(coros):
            c = await coro
            print(f'/{c.board} | {c.board_name}, "{c.board_info_outer}", bump limit: {c.bump_limit}')


asyncio.run(main())

Output:

/un | Образование, "образование, вуз, школа, поступление, гиа, егэ, уже не школьник", bump limit: 500
/spc | Космос и астрономия, "космос, астрономия, вселенные, звезды, огурцы", bump limit: 500
/math | Математика, "Доска о модулях над кольцами, пучках на многообразиях и гомологиях с когомологиями.", bump limit: 500

Top threads

from api2ch import Api2ch

api = Api2ch()

boards = api.boards_by_types()
for board in boards.Art:
    threads = api.threads(board.id)
    top_thread = threads.sorted_by_views()[0]
    print(f'— /{threads.request.board} | {board.name} | Top thread: {top_thread.subject}, {top_thread.views} 👁')

Output:

— /di | Столовая | Top thread: НОВОЙ БАНОЧКИ НИТЬ ИДИ, 123475 👁
— /de | Дизайн | Top thread: Зарплата, 48958 👁
— /diy | Хобби | Top thread: Кристаллический тред, 1620541 👁
— /mus | Музыканты | Top thread: Язычковых тред., 153772 👁
— /pa | Живопись | Top thread: Сталин 3000, 40392 👁
— /p | Фотография | Top thread: Ссылкотред, 34182 👁
— /wp | Обои и высокое разрешение | Top thread: Милитари пак, 38348 👁
— /wrk | Работа и карьера | Top thread: Яндекс Дзена /zen тред 11, 33648 👁

Top Threads Async

import asyncio

from api2ch import Api2chAsync


async def main():
    async with Api2chAsync() as api:
        boards = await api.boards_by_types()

        coros = [api.threads(board.id) for board in boards.Technology]

        for coro in asyncio.as_completed(coros):
            threads = await coro
            top_thread = threads.sorted_by_views()[0]
            print(f'— /{threads.request.board} | Top thread: {top_thread.subject}, {top_thread.views} 👁')


asyncio.run(main())

Output:

— /ra | Top thread: OsmocomBB - Motorola, 1517590 👁
— /hw | Top thread: VR тред возрожденный #4, 17638 👁
— /t | Top thread: Выбираем робот-пылесос, 22336 👁
— /s | Top thread: Форки лиса, 49613 👁
— /pr | Top thread: Советов ньюфагу тред, 25838 👁
— /gd | Top thread: В этом треде ищем напарников для создания своих, 38633 👁
— /mobi | Top thread: PUBG MOBILE/Пупок мобайл-THREAD, 70643 👁

Complex

import api2ch

api = api2ch.Api2ch()


def parse_post(url: str) -> str:
    valid, board, thread_id = api2ch.parse_url(url)
    if not valid:
        raise api2ch.Api2chError(404, 'Invalid URL')

    thread = api.thread(board, thread_id)
    post = thread.posts[0]
    text = ''

    text += f'{post.dt().isoformat()} | Пост №{post.post_id}: {post.url(thread.board)}:\n\n'
    text += f'{post.header}\n' if thread.enable_subject else ''
    text += f'{post.body_text}\n\n'

    if post.files:
        text += 'Файлы:\n'
        for f in post.files:
            text += f'— {f.original_name}, {f.size_string}: {f.url()}\n'

    return text


def pretty_print_post(url: str):
    try:
        text = parse_post(url)
    except api2ch.Api2chError as e:
        print('Request Error', e.code, e.reason)
    else:
        print(text)


if __name__ == '__main__':
    pretty_print_post('https://2ch.hk/cg/res/1323206.html')

Output:

2018-07-19T10:13:24 | Пост №1323206: https://2ch.hk/cg/res/1323206.html#1323206:

Тред для междоусобных холиваров
Сравниваем платформы, а так же помогаем ньюфагам определиться с выбором приставки и техническими вопросами.

Обязателен к прочтению FAQ раздела: https://2ch.hk/faq/faq_cg.html

Файлы:
— изображение.png, 84 Кб: https://2ch.hk/cg/src/1323206/15319844042830.png

Complex Async

complex_async.py, same as previous but:

  • api = api2ch.Api2chAsync()
  • and thread = await api.thread(board, thread_id)

📜 Manual

Methods

Api2ch methods (and same for Api2chAsync but with async):

class Api2ch(Api2chBase):
    ...
    def thread(self, board: str, thread: Union[str, int]) -> ResponseThread:
        ...
    def threads(self, board: str) -> ResponseThreads:
        ...
    def catalog(self, board: str) -> ResponseCatalog:
        ...
    def catalog_by_date(self, board: str) -> ResponseCatalogByDate:
        ...
    def page(self, board: str, page: Union[str, int]) -> ResponsePage:
        ...
    def boards(self) -> ResponseBoards:
        ...
    def boards_by_types(self) -> ResponseBoardsByTypes:
        ...
    def thread_posts_by_num(self, board: str, thread: Union[str, int], num: Union[str, int]) -> ResponseThreadPostsByNum:
        ...
    def thread_posts_by_post(self, board: str, thread: Union[str, int], post: Union[str, int]) -> ResponseThreadPostsByPost:
        ...
    def single_post(self, board: str, post: Union[str, int]) -> ResponseSinglePost:
        ...

Also available method download_thread_media (default path: ./dowloads_2ch/%thread_id%/):

from api2ch import download_thread_media

download_thread_media(url='https://2ch.hk/api/res/1.html', with_thumbnails=True, skip_if_exists=True)

Types

This library uses pydantic for parsing API responses. You can see data models in api2ch/models.

In case of unsupported types

API results can change and the library may not parse the new result. So you can request «raw» dicts:

api = Api2ch(raw_results=True)

💬 Contributing

Contributions, issues and feature requests are welcome!

📝 License

This project is MIT licensed.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

api2ch-1.2.1.tar.gz (16.4 kB view hashes)

Uploaded Source

Built Distribution

api2ch-1.2.1-py3-none-any.whl (16.1 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page