{"id":34028956,"url":"https://github.com/uburuntu/api2ch","last_synced_at":"2026-04-08T15:31:05.080Z","repository":{"id":57410814,"uuid":"293478902","full_name":"uburuntu/api2ch","owner":"uburuntu","description":"⚡️ 2ch Imageboard API Wrapper with typings and asyncio support","archived":false,"fork":false,"pushed_at":"2022-05-01T00:19:43.000Z","size":46,"stargazers_count":11,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-04-01T02:10:04.093Z","etag":null,"topics":["2ch","api","asyncio","dvach","python"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/uburuntu.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-09-07T09:14:19.000Z","updated_at":"2025-12-22T09:19:49.000Z","dependencies_parsed_at":"2022-08-28T01:21:17.471Z","dependency_job_id":null,"html_url":"https://github.com/uburuntu/api2ch","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/uburuntu/api2ch","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uburuntu%2Fapi2ch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uburuntu%2Fapi2ch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uburuntu%2Fapi2ch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uburuntu%2Fapi2ch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/uburuntu","download_url":"https://codeload.github.com/uburuntu/api2ch/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/uburuntu%2Fapi2ch/sbom","scorecard":{"id":906520,"data":{"date":"2025-08-11","repo":{"name":"github.com/uburuntu/api2ch","commit":"cb99067813c1c051c94ee9bb0721bbda3bc32114"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.5,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/pythonpublish.yml:1","Warn: no topLevel permission defined: .github/workflows/tests.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pythonpublish.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/uburuntu/api2ch/pythonpublish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pythonpublish.yml:18: update your workflow using https://app.stepsecurity.io/secureworkflow/uburuntu/api2ch/pythonpublish.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/uburuntu/api2ch/tests.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tests.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/uburuntu/api2ch/tests.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/tests.yml:42: update your workflow using https://app.stepsecurity.io/secureworkflow/uburuntu/api2ch/tests.yml/master?enable=pin","Warn: pipCommand not pinned by hash: .github/workflows/pythonpublish.yml:24","Warn: pipCommand not pinned by hash: .github/workflows/pythonpublish.yml:25","Warn: pipCommand not pinned by hash: .github/workflows/pythonpublish.yml:26","Warn: pipCommand not pinned by hash: .github/workflows/tests.yml:28","Warn: pipCommand not pinned by hash: .github/workflows/tests.yml:29","Warn: pipCommand not pinned by hash: .github/workflows/tests.yml:30","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   6 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Vulnerabilities","score":0,"reason":"19 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2022-238 / GHSA-h3qr-fjhm-jphw","Warn: Project is vulnerable to: PYSEC-2023-120 / GHSA-45c4-8wx5-qw6w","Warn: Project is vulnerable to: PYSEC-2024-24 / GHSA-5h86-8mv2-jq9f","Warn: Project is vulnerable to: GHSA-5m98-qgg9-wh84","Warn: Project is vulnerable to: GHSA-7gpw-8wmc-pm8g","Warn: Project is vulnerable to: GHSA-8495-4g3g-x7pr","Warn: Project is vulnerable to: PYSEC-2024-26 / GHSA-8qpw-xqxj-h4r2","Warn: Project is vulnerable to: GHSA-9548-qrrj-x5pj","Warn: Project is vulnerable to: PYSEC-2023-246 / GHSA-gfw2-4jvh-wgfg","Warn: Project is vulnerable to: GHSA-pjjw-qhg8-p2p9","Warn: Project is vulnerable to: PYSEC-2023-250 / GHSA-q3qx-c6g2-7pw2","Warn: Project is vulnerable to: PYSEC-2023-251 / GHSA-qvrw-v9rv-5rjx","Warn: Project is vulnerable to: PYSEC-2021-76 / GHSA-v6wp-4m6f-gcjg","Warn: Project is vulnerable to: PYSEC-2023-247 / GHSA-xx9p-xxvh-7g8j","Warn: Project is vulnerable to: PYSEC-2021-47 / GHSA-5jqp-qgf6-3pvh","Warn: Project is vulnerable to: GHSA-mr82-8j83-vxmv","Warn: Project is vulnerable to: GHSA-9hjg-9r4m-mvj7","Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56","Warn: Project is vulnerable to: PYSEC-2023-74 / GHSA-j8r2-6x86-q33q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-24T17:33:58.916Z","repository_id":57410814,"created_at":"2025-08-24T17:33:58.916Z","updated_at":"2025-08-24T17:33:58.916Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31562685,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"ssl_error","status_checked_at":"2026-04-08T14:31:17.202Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["2ch","api","asyncio","dvach","python"],"created_at":"2025-12-13T17:23:27.366Z","updated_at":"2026-04-08T15:31:05.073Z","avatar_url":"https://github.com/uburuntu.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# api2ch\n\n[![Python](https://img.shields.io/badge/Python-3.6%20%7C%203.7%20%7C%203.8%20%7C%203.9%20%7C%203.10%20%7C%203.11-blue.svg?longCache=true)]()\n[![PyPI](https://img.shields.io/pypi/v/api2ch.svg)](https://pypi.python.org/pypi/api2ch)\n[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)\n\n[![Python Tests](https://github.com/uburuntu/api2ch/actions/workflows/tests.yml/badge.svg)](https://github.com/uburuntu/api2ch/actions/workflows/tests.yml)\n[![codecov](https://codecov.io/gh/uburuntu/api2ch/branch/master/graph/badge.svg)](https://codecov.io/gh/uburuntu/api2ch)\n\n⚡️ Async API Wrapper for 2ch Imageboard with typings\n\nDocs: https://2ch.hk/api/res/1.html\n\n![](https://i.imgur.com/VLbQhEv.jpg)\n\n## 📝 Table of Contents\n\n- [🎒 Installation](#-installation)\n- [🛠 Examples](#-examples)\n  - [Simple](#simple)\n  - [Simple Async](#simple-async)\n  - [Boards](#boards)\n  - [Boards Async](#boards-async)\n  - [Top threads](#top-threads)\n  - [Top Threads Async](#top-threads-async)\n  - [Complex](#complex)\n  - [Complex Async](#complex-async)\n- [📜 Manual](#-manual)\n  - [Methods](#methods)\n  - [Types](#types)\n  - [In case of unsupported types](#in-case-of-unsupported-types)\n- [💬 Contributing](#-contributing)\n- [📝 License](#-license)\n\n\n---\n\n## 🎒 Installation\n\nJust\n\n```\npip install api2ch\n```\n\n## 🛠 Examples\n\n### Simple\n\n```python3\nfrom api2ch import Api2ch\n\napi = Api2ch()\n\nresp = api.threads('vg')\nfor t in resp.threads[:3]:\n    print(f'— {t.subject}, {t.posts_count} 💬, {t.views} 👁')\n```\n\nOutput:\n\n```text\n— Paradox Thread №6 стрессовый, 771 💬, 1879 👁\n— BioWare General: Varric Tethras Edition, 207 💬, 644 👁\n— Fate/Grand Order #193, 683 💬, 4804 👁\n```\n\n### Simple Async\n\n```python3\nimport asyncio\n\nfrom api2ch import Api2chAsync\n\n\nasync def main():\n    async with Api2chAsync() as api:\n        resp = await api.threads('hw')\n        for t in resp.threads[:3]:\n            print(f'— {t.subject}, {t.posts_count} 💬, {t.views} 👁')\n\n\nasyncio.run(main())\n```\n\nOutput:\n\n```text\n— Видеокарты AMD #95, 418 💬, 3778 👁\n— Сап. Впервые в этом разделе. Как научится разбираться в железе?, 3 💬, 9 👁\n— Ноутбукотред №36, 185 💬, 970 👁\n```\n\n### Boards\n\n```python3\nfrom api2ch import Api2ch\n\napi = Api2ch()\n\nfor board in ('tv', 'hw', 'fiz'):\n    c = api.catalog(board)\n    print(f'/{c.board} | {c.board_name}, \"{c.board_info_outer}\", bump limit: {c.bump_limit}')\n```\n\nOutput:\n\n```text\n/tv | Сериалы, \"сериалы для домохозяек, игры престолов в /got/\", bump limit: 500\n/hw | Компьютерное железо, \"железо, видеокарты, ноутбуки, intel, amd, nvidia, ati\", bump limit: 500\n/fiz | Физкультура, \"физкультура, здоровье, сбросить вес, набрать вес, бицуха\", bump limit: 800\n```\n\n### Boards Async\n\n```python3\nimport asyncio\n\nfrom api2ch import Api2chAsync\n\n\nasync def main():\n    async with Api2chAsync() as api:\n        coros = [api.catalog(board) for board in ('spc', 'un', 'math')]\n\n        for coro in asyncio.as_completed(coros):\n            c = await coro\n            print(f'/{c.board} | {c.board_name}, \"{c.board_info_outer}\", bump limit: {c.bump_limit}')\n\n\nasyncio.run(main())\n```\n\nOutput:\n\n```text\n/un | Образование, \"образование, вуз, школа, поступление, гиа, егэ, уже не школьник\", bump limit: 500\n/spc | Космос и астрономия, \"космос, астрономия, вселенные, звезды, огурцы\", bump limit: 500\n/math | Математика, \"Доска о модулях над кольцами, пучках на многообразиях и гомологиях с когомологиями.\", bump limit: 500\n```\n\n### Top threads\n\n```python3\nfrom api2ch import Api2ch\n\napi = Api2ch()\n\nboards = api.boards_by_types()\nfor board in boards.Art:\n    threads = api.threads(board.id)\n    top_thread = threads.sorted_by_views()[0]\n    print(f'— /{threads.request.board} | {board.name} | Top thread: {top_thread.subject}, {top_thread.views} 👁')\n```\n\nOutput:\n\n```text\n— /di | Столовая | Top thread: НОВОЙ БАНОЧКИ НИТЬ ИДИ, 123475 👁\n— /de | Дизайн | Top thread: Зарплата, 48958 👁\n— /diy | Хобби | Top thread: Кристаллический тред, 1620541 👁\n— /mus | Музыканты | Top thread: Язычковых тред., 153772 👁\n— /pa | Живопись | Top thread: Сталин 3000, 40392 👁\n— /p | Фотография | Top thread: Ссылкотред, 34182 👁\n— /wp | Обои и высокое разрешение | Top thread: Милитари пак, 38348 👁\n— /wrk | Работа и карьера | Top thread: Яндекс Дзена /zen тред 11, 33648 👁\n```\n\n### Top Threads Async\n\n```python3\nimport asyncio\n\nfrom api2ch import Api2chAsync\n\n\nasync def main():\n    async with Api2chAsync() as api:\n        boards = await api.boards_by_types()\n\n        coros = [api.threads(board.id) for board in boards.Technology]\n\n        for coro in asyncio.as_completed(coros):\n            threads = await coro\n            top_thread = threads.sorted_by_views()[0]\n            print(f'— /{threads.request.board} | Top thread: {top_thread.subject}, {top_thread.views} 👁')\n\n\nasyncio.run(main())\n```\n\nOutput:\n\n```text\n— /ra | Top thread: OsmocomBB - Motorola, 1517590 👁\n— /hw | Top thread: VR тред возрожденный #4, 17638 👁\n— /t | Top thread: Выбираем робот-пылесос, 22336 👁\n— /s | Top thread: Форки лиса, 49613 👁\n— /pr | Top thread: Советов ньюфагу тред, 25838 👁\n— /gd | Top thread: В этом треде ищем напарников для создания своих, 38633 👁\n— /mobi | Top thread: PUBG MOBILE/Пупок мобайл-THREAD, 70643 👁\n```\n\n### Complex\n\n```python3\nimport api2ch\n\napi = api2ch.Api2ch()\n\n\ndef parse_post(url: str) -\u003e str:\n    valid, board, thread_id = api2ch.parse_url(url)\n    if not valid:\n        raise api2ch.Api2chError(404, 'Invalid URL')\n\n    thread = api.thread(board, thread_id)\n    post = thread.posts[0]\n    text = ''\n\n    text += f'{post.dt().isoformat()} | Пост №{post.post_id}: {post.url(thread.board)}:\\n\\n'\n    text += f'{post.header}\\n' if thread.enable_subject else ''\n    text += f'{post.body_text}\\n\\n'\n\n    if post.files:\n        text += 'Файлы:\\n'\n        for f in post.files:\n            text += f'— {f.original_name}, {f.size_string}: {f.url()}\\n'\n\n    return text\n\n\ndef pretty_print_post(url: str):\n    try:\n        text = parse_post(url)\n    except api2ch.Api2chError as e:\n        print('Request Error', e.code, e.reason)\n    else:\n        print(text)\n\n\nif __name__ == '__main__':\n    pretty_print_post('https://2ch.hk/cg/res/1323206.html')\n```\n\nOutput:\n\n```text\n2018-07-19T10:13:24 | Пост №1323206: https://2ch.hk/cg/res/1323206.html#1323206:\n\nТред для междоусобных холиваров\nСравниваем платформы, а так же помогаем ньюфагам определиться с выбором приставки и техническими вопросами.\n\nОбязателен к прочтению FAQ раздела: https://2ch.hk/faq/faq_cg.html\n\nФайлы:\n— изображение.png, 84 Кб: https://2ch.hk/cg/src/1323206/15319844042830.png\n```\n\n### Complex Async\n\n[complex_async.py](examples/complex_async.py), same as previous but:\n\n- `api = api2ch.Api2chAsync()`\n- and `thread = await api.thread(board, thread_id)`\n\n## 📜 Manual\n\n### Methods\n\n`Api2ch` methods (and same for `Api2chAsync` but with `async`):\n\n```python3\nclass Api2ch(Api2chBase):\n    ...\n    def thread(self, board: str, thread: Union[str, int]) -\u003e ResponseThread:\n        ...\n    def threads(self, board: str) -\u003e ResponseThreads:\n        ...\n    def catalog(self, board: str) -\u003e ResponseCatalog:\n        ...\n    def catalog_by_date(self, board: str) -\u003e ResponseCatalogByDate:\n        ...\n    def page(self, board: str, page: Union[str, int]) -\u003e ResponsePage:\n        ...\n    def boards(self) -\u003e ResponseBoards:\n        ...\n    def boards_by_types(self) -\u003e ResponseBoardsByTypes:\n        ...\n    def thread_posts_by_num(self, board: str, thread: Union[str, int], num: Union[str, int]) -\u003e ResponseThreadPostsByNum:\n        ...\n    def thread_posts_by_post(self, board: str, thread: Union[str, int], post: Union[str, int]) -\u003e ResponseThreadPostsByPost:\n        ...\n    def single_post(self, board: str, post: Union[str, int]) -\u003e ResponseSinglePost:\n        ...\n```\n\nAlso available method `download_thread_media` (default path: `./dowloads_2ch/%thread_id%/`):\n\n```python3\nfrom api2ch import download_thread_media\n\ndownload_thread_media(url='https://2ch.hk/api/res/1.html', with_thumbnails=True, skip_if_exists=True)\n```\n\n### Types\n\nThis library uses [pydantic](https://github.com/samuelcolvin/pydantic/) for parsing API responses. You can see data models in [api2ch/models](api2ch/models).\n\n### In case of unsupported types\n\nAPI results can change and the library may not parse the new result. So you can request «raw» dicts:\n\n```python3\napi = Api2ch(raw_results=True)\n```\n\n## 💬 Contributing\n\nContributions, issues and feature requests are welcome!\n\n## 📝 License\n\nThis project is [MIT](LICENSE) licensed.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuburuntu%2Fapi2ch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fuburuntu%2Fapi2ch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fuburuntu%2Fapi2ch/lists"}