├── .gitignore ├── LICENSE ├── README.md ├── data └── 7418294751977327878.json ├── main.py ├── requirements.txt └── tiktokcomment ├── __init__.py ├── tiktokcomment.py └── typing ├── __init__.py ├── comment.py └── comments.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 romysaputrasihananda 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Twitter: romy](https://img.shields.io/twitter/follow/RomySihananda)](https://twitter.com/RomySihananda) 2 | 3 | # tiktok-comment-scrapper 4 | 5 | ![](https://raw.githubusercontent.com/RomySaputraSihananda/RomySaputraSihananda/main/images/GA-U-u2bsAApmn9.jpeg) 6 | Get all comments from tiktok video url or id 7 | 8 | ## Requirements 9 | 10 | - **Python >= 3.11.4** 11 | - **Requests >= 2.31.0** 12 | 13 | ## Installation 14 | 15 | ```sh 16 | # Clonig Repository 17 | git clone https://github.com/romysaputrasihananda/tiktok-comment-scrapper 18 | 19 | # Change Directory 20 | cd tiktok-comment-scrapper 21 | 22 | # Install Requirement 23 | pip install -r requirements.txt 24 | ``` 25 | 26 | ## Example Usages 27 | 28 | ```sh 29 | python main.py --url=7170139292767882522 --size=10 --output=data 30 | ``` 31 | 32 | ### Flags 33 | 34 | | Flag | Alias | Description | Example | Default | 35 | | :------- | :---: | :-----------------------------: | :-------------- | :-----------------: | 36 | | --url | -u | Url or video id of tiktok video | --url=id or url | 7170139292767882522 | 37 | | --size | -s | number of comments | --size=10 | 50 | 38 | | --output | -o | json file output path | --output=data | data | 39 | 40 | ## Sample Output 41 | 42 | ![](https://raw.githubusercontent.com/RomySaputraSihananda/RomySaputraSihananda/main/images/Screenshot_20231211_001804.png) 43 | 44 | ```json 45 | { 46 | "caption": "makk aku jadi animee🤩#faceplay #faceplayapp #anime #harem #xysryo ", 47 | "date_now": "2023-12-10T22:06:04", 48 | "video_url": "https://t.tiktok.com/i18n/share/video/7170139292767882522/?_d=0&comment_author_id=6838487455625479169&mid=7157599449395496962&preview_pb=0®ion=ID&share_comment_id=7310977412674093829&share_item_id=7170139292767882522&sharer_language=en&source=h5_t&u_code=0", 49 | "comments": [ 50 | { 51 | "username": "user760722966", 52 | "nickname": "rehan", 53 | "comment": "testing 😁😁", 54 | "create_time": "2023-12-10T21:46:36", 55 | "avatar": "https://p16-sign-useast2a.tiktokcdn.com/tos-useast2a-avt-0068-giso/f64f2c7df8a16098d3b3c80e958ffc52~c5_100x100.jpg?x-expires=1702306800&x-signature=KhUeuGmPAVij9A8gbgh7wK6rn98%3D", 56 | "total_reply": 0, 57 | "replies": [] 58 | }, 59 | { 60 | "username": "user760722966", 61 | "nickname": "rehan", 62 | "comment": "bagus", 63 | "create_time": "2023-12-10T18:55:47", 64 | "avatar": "https://p16-sign-useast2a.tiktokcdn.com/tos-useast2a-avt-0068-giso/f64f2c7df8a16098d3b3c80e958ffc52~c5_100x100.jpg?x-expires=1702306800&x-signature=KhUeuGmPAVij9A8gbgh7wK6rn98%3D", 65 | "total_reply": 3, 66 | "replies": [ 67 | { 68 | "username": "ryo.syntax", 69 | "nickname": "Bukan Rio", 70 | "comment": "good game", 71 | "create_time": "2023-12-10T18:56:19", 72 | "avatar": "https://p16-sign-useast2a.tiktokcdn.com/tos-useast2a-avt-0068-giso/be4a9d0479f29d00cb3d06905ff5a972~c5_100x100.jpg?x-expires=1702306800&x-signature=IvkeSvXmvkmE0hZG5dtgpqcFn3A%3D" 73 | } 74 | // more replies 75 | ] 76 | } 77 | // more comments 78 | ] 79 | } 80 | ``` 81 | 82 | ## License 83 | 84 | This project is licensed under the [MIT License](LICENSE). 85 | -------------------------------------------------------------------------------- /data/7418294751977327878.json: -------------------------------------------------------------------------------- 1 | {"caption": "nemu video lama rambutku lucu! 😩🐰💖", "video_url": "https://t.tiktok.com/i18n/share/video/7418294751977327878/?_d=0&comment_author_id=7266762544739861510&mid=7392157175172385537&preview_pb=0®ion=ID&share_comment_id=7418301035179574022&share_item_id=7418294751977327878&sharer_language=en&source=h5_t&u_code=0", "comments": [{"comment_id": "7418301035179574022", "username": "septianreza1", "nickname": "reza setengah nomjoh", "comment": "wedeh", "create_time": "2024-09-25T02:56:56", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/ff1395ba796e47efec1f1ea744540569~c5_100x100.jpg?lk3s=30310797&nonce=60663&refresh_token=52b3e677ad9f8a6ec2823869c8403a52&x-expires=1729620000&x-signature=PxyzQ3mOYE7mo6Nz8Cu7vGvDIzA%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7419248482387313414", "username": "rifky_pridantyo", "nickname": "𝐂𝐂` leo boy♌ akun ketiga 🎈", "comment": "salken ya heheh", "create_time": "2024-09-27T16:13:35", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/89229ac9f26ca27ade33766886b5dc6d~c5_100x100.jpg?lk3s=30310797&nonce=70401&refresh_token=1ad73c98f908391bba7bb7aef5411513&x-expires=1729620000&x-signature=mM%2FgFZmEpsOMRWEvI%2BzdHb%2FOUfw%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418493767806288646", "username": "xxla.y", "nickname": "lalapowh🧸", "comment": "My oshii🥰", "create_time": "2024-09-25T15:24:56", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/6c02e7d99fbc5518dd6a609c8b97e652~c5_100x100.jpg?lk3s=30310797&nonce=24347&refresh_token=fe7fe6c1559a8bf5bc662e5556ad1445&x-expires=1729620000&x-signature=PyRQfdj8JLOmJ8vJpBJ9gICNcds%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418409665316406022", "username": "rizcorza7", "nickname": "Corza7", "comment": "Apa si cakep mulu yocannnnn🥰🥰", "create_time": "2024-09-25T09:58:33", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/b7139cd1b6b18e582826a2049ca99924~c5_100x100.jpg?lk3s=30310797&nonce=58721&refresh_token=969c93d7dc93a2de35c0236a7df71249&x-expires=1729620000&x-signature=Z98boLiwuPW55OLDhAVJNK8uviA%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418385656126292742", "username": "arfin_hosino", "nickname": "Arfin Hosino", "comment": "ahh lucu banget mbak bumi ini 🥰", "create_time": "2024-09-25T08:25:18", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/5376421e47ca0e423f3a7e96cfc34874~c5_100x100.jpg?lk3s=30310797&nonce=65027&refresh_token=d8dc8e248050beccd3537234c1b81efd&x-expires=1729620000&x-signature=yhihrDwlSekV%2B0oLRLCXqwBulXM%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418430287463695110", "username": "inyourdream771", "nickname": "perdanawildan", "comment": "imi rambut bulan bulan awal 2023 kalp gasalah", "create_time": "2024-09-25T11:18:33", "avatar": "https://p16-sign-useast2a.tiktokcdn.com/tos-useast2a-avt-0068-giso/084065841019072f9f14e17153de26f2~c5_100x100.jpg?lk3s=30310797&nonce=62374&refresh_token=72b9efe795bf96927ba169a24f4fb1f1&x-expires=1729620000&x-signature=sDv6Jz5Y228AsloGDAsmLfZnA8Q%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418575915603985158", "username": "tvupifyp100", "nickname": "RufiTV🎈🇵🇸🇲🇨", "comment": "fyp😳😳😊😊anime", "create_time": "2024-09-25T20:43:41", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/34c4654edb2503848ad1430dafde1b69~c5_100x100.jpg?lk3s=30310797&nonce=83697&refresh_token=753627bb799544d429632ddf4cf51a4e&x-expires=1729620000&x-signature=IFGVXW40ueb%2B1sNwXzxJfrpJMTY%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418344755388957446", "username": "kacynntea", "nickname": "cincaw♡", "comment": "my yochaaan🥰", "create_time": "2024-09-25T05:46:41", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/72871f51c338dd08d78db361d7201c2f~c5_100x100.jpg?lk3s=30310797&nonce=24897&refresh_token=b6525497b110c5e28487251bfd78399c&x-expires=1729620000&x-signature=33bHNF%2FksLP%2FYcqJDgeHNUCyoGw%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418351039286182661", "username": "haekalrinaldi", "nickname": "Haekal Rinaldi", "comment": "yochaaanng 💖", "create_time": "2024-09-25T06:10:58", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/694f7afca1a336ad1a9a61cf960b2729~c5_100x100.jpg?lk3s=30310797&nonce=78354&refresh_token=c74429f4acbeeb781d90d1b794c8f19f&x-expires=1729620000&x-signature=genC9WhMcSQpSPPFDfn0Cbby0XU%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418420315850457862", "username": "moriyafirefox", "nickname": "モリヤ・fzn", "comment": "hurunk gini geysss ✨", "create_time": "2024-09-25T10:39:53", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/8a150e99462af5ae3d29675c54272689~c5_100x100.jpg?lk3s=30310797&nonce=17122&refresh_token=99b4b5b5650d92e3f51eaaac5763dfa9&x-expires=1729620000&x-signature=dedhbNml1X1ku7c6DxRQkpmukww%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418427985508549381", "username": "amandadeyyyy", "nickname": "dey", "comment": "ceweku ceweku😖💘💘", "create_time": "2024-09-25T11:09:42", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/a618df7abac267f685cf6bfd4b18a902~c5_100x100.jpg?lk3s=30310797&nonce=98225&refresh_token=a6f6cfa552af3367c31f70d8d732d36c&x-expires=1729620000&x-signature=DM9toEr1f1OOh6R1eDoKAh2aipc%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7419196496656777989", "username": "helen_rcm", "nickname": "Helen🎀", "comment": "Assalamualaikum 🌹🌹🌹", "create_time": "2024-09-27T12:51:50", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/28b3c89643638ea922aa84aada6c52ab~c5_100x100.jpg?lk3s=30310797&nonce=42899&refresh_token=ca02d7be5913cffee81ade4f890d2ae5&x-expires=1729620000&x-signature=7nnAoE9r7ZKBztL%2BEYJu%2BpwaGAA%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418957932345705221", "username": "lanaishaq", "nickname": "Lana Ishaq", "comment": "tiba tiba yochan muncul disinii", "create_time": "2024-09-26T21:25:59", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/672b0f84b409e0049cb7387381de5b2a~c5_100x100.jpg?lk3s=30310797&nonce=25744&refresh_token=d360dd9fd138e35fe27beb90bcb07c7b&x-expires=1729620000&x-signature=upKv6yWG2mIlN%2FLZvAayO6BmSdI%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418342418900714245", "username": "aditya.kurniawan38", "nickname": "Aditya Kurniawan", "comment": "apa ini?🥺", "create_time": "2024-09-25T05:37:31", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/7390551160590172166~c5_100x100.jpg?lk3s=30310797&nonce=88178&refresh_token=f03309e6d68cd74cc95055d8f13fa344&x-expires=1729620000&x-signature=opXlt4mh9zpFWzDVh%2FXzQjjutNA%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418333516158829317", "username": "spcrkn", "nickname": "らくーん", "comment": "Kak", "create_time": "2024-09-25T05:02:59", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/41eba5214130d1b12520fa0357c82bdb~c5_100x100.jpg?lk3s=30310797&nonce=34089&refresh_token=56ce8c2ed80cfb12ef9b48e1ce6ed264&x-expires=1729620000&x-signature=6ZbBpmfM7oniSJ9%2B84s4JwVFbWM%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7419190192664232709", "username": "genera308", "nickname": "Genera", "comment": "Halo kak🤗💕💕", "create_time": "2024-09-27T12:27:25", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/42c2246af660724f4534ccbafb6a687f~c5_100x100.jpg?lk3s=30310797&nonce=86858&refresh_token=65b87eac018cceb31fb99fee5b8860ad&x-expires=1729620000&x-signature=kA5h7C6FqijXCGskSzTKpD05iOs%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7419334072864015122", "username": "lily_jss", "nickname": "Lily🦁Cek message", "comment": "Hey cntk follow back sy 🥰🥰😊", "create_time": "2024-09-27T21:45:30", "avatar": "https://p16-sign-sg.tiktokcdn.com/aweme/100x100/tos-alisg-avt-0068/8b89c0c2035fe51099fb9d3f62ab0bb3.jpg?lk3s=30310797&nonce=10164&refresh_token=2705cc24e22512366e19ec0c725d4e7c&x-expires=1729620000&x-signature=QsKVt8b247804Dh%2BqIgCJZcKS%2Bo%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418369356578587398", "username": "starssiantihero", "nickname": "Bin. 🍵", "comment": "anu... 💍", "create_time": "2024-09-25T07:21:59", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/36e3b22667a5a29d5bd386d2d93e50c0~c5_100x100.jpg?lk3s=30310797&nonce=733&refresh_token=9d2e455344ed0207c6e15bea664f4cbd&x-expires=1729620000&x-signature=ge3pNcAzvg%2BzRvVhIrZGVeh0UI4%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418304051563512582", "username": "romysaputrasihana", "nickname": "mee.romys", "comment": "gas warnain lagi", "create_time": "2024-09-25T03:08:38", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/7939861fa1cc37e5b9ba8abf78f8608b~c5_100x100.jpg?lk3s=30310797&nonce=71006&refresh_token=c7937c3447d577680cc60edc03340ade&x-expires=1729620000&x-signature=sCbH45Qv9egx8CLig0LO1cttP3w%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418430545748673287", "username": "ihan_raihan28", "nickname": "ihan Raihan", "comment": "🍀🩷✨", "create_time": "2024-09-25T11:19:23", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/8eab128d3bde35b69b08b286e68b6056~c5_100x100.jpg?lk3s=30310797&nonce=5844&refresh_token=a058ac5237946ea3b5f76e1a8f898d50&x-expires=1729620000&x-signature=cTcdhz96bmVoYlvKsWSMU1W6PVw%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418388381934158597", "username": "coro_kun", "nickname": "-Coro-", "comment": "lucu terus", "create_time": "2024-09-25T08:35:57", "avatar": "https://p16-sign-useast2a.tiktokcdn.com/tos-useast2a-avt-0068-giso/6084a2e987b3d8afd1993dc0e3786f28~c5_100x100.jpg?lk3s=30310797&nonce=33104&refresh_token=9fa2de79e84a36d5b2076fd8949e5ca2&x-expires=1729620000&x-signature=sO56O2f%2Fa1HWdaKNf2QEboHVwxY%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7419180041295266565", "username": "iamanna_002", "nickname": "Anna🍇", "comment": "Haloo😁", "create_time": "2024-09-27T11:47:59", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/16c8ab76e783d0eec3abb1ee52aeddb7~c5_100x100.jpg?lk3s=30310797&nonce=75661&refresh_token=4f023847e99e436bed44662fb86fe4a2&x-expires=1729620000&x-signature=Z01755jLtprticZdr7Ux1fxHt%2Fo%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418425853925294854", "username": "mamorru.u", "nickname": "wekekekkek", "comment": "Catoknya mini bgt😂", "create_time": "2024-09-25T11:01:23", "avatar": "https://p16-sign-useast2a.tiktokcdn.com/tos-useast2a-avt-0068-giso/f1065c4f2c975a980b3edd9a0ce853bb~c5_100x100.jpg?lk3s=30310797&nonce=82454&refresh_token=3bb4000849eb108b91d282c57fce9888&x-expires=1729620000&x-signature=EBexIcPFhR8E5HVLDfXlFx1kMSA%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418491557803131654", "username": "sudesnusap", "nickname": "Raenand", "comment": "@hyungseokk11 katanya mau nonton gochi", "create_time": "2024-09-25T15:16:28", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/e22183980e38009863f3d807ff07c0ed~c5_100x100.jpg?lk3s=30310797&nonce=82216&refresh_token=9ad3354ced6e3f3c254c420f648ec1d0&x-expires=1729620000&x-signature=IpbHcGnXyfsgGtrIL%2BhMe5fdnaI%3D&shp=30310797&shcp=-", "total_reply": 1, "replies": [{"comment_id": "7419153469528113925", "username": "hyungseokk11", "nickname": "Parkhyungseok11", "comment": "gasss", "create_time": "2024-09-27T10:04:56", "avatar": "https://p16-sign-useast2a.tiktokcdn.com/tos-useast2a-avt-0068-giso/9fd00a5e87c6192f002bb726f5c033ce~c5_100x100.jpg?lk3s=30310797&nonce=93935&refresh_token=06dd9c1fcb3d576ce6ed4eb6d876b7fb&x-expires=1729620000&x-signature=Yj0jX51dhxrep4TSYVPzbA55jd0%3D&shp=30310797&shcp=-", "total_reply": null, "replies": []}]}, {"comment_id": "7418297531752661766", "username": "paiiizyahoo", "nickname": "PaiiiZ Yahoo", "comment": "p", "create_time": "2024-09-25T02:43:20", "avatar": "https://p16-sign-sg.tiktokcdn.com/aweme/100x100/tos-alisg-avt-0068/7335388471235706901.jpg?lk3s=30310797&nonce=5606&refresh_token=7c542fd8a1fd8efd029aa264101949e8&x-expires=1729620000&x-signature=J6t0HHRBlp1MOVa1KyNLM9Hl2js%3D&shp=30310797&shcp=-", "total_reply": 1, "replies": [{"comment_id": "7418300928664552197", "username": "fall.for.yo", "nickname": "fall for yo", "comment": "p", "create_time": "2024-09-25T02:56:27", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/7847e80138190bfa5386e39bb3094a23~c5_100x100.jpg?lk3s=30310797&nonce=66837&refresh_token=fb71bccc32180cce2ddb61a9b12d64a2&x-expires=1729620000&x-signature=za8wzNwiJF519Y9ZHwhFUrfT7AI%3D&shp=30310797&shcp=-", "total_reply": null, "replies": []}]}, {"comment_id": "7419994842392331025", "username": "newworld_778", "nickname": "newworld_77", "comment": "🚂🚂🚂🎁🎁🎁", "create_time": "2024-09-29T16:29:51", "avatar": "https://p16-sign-sg.tiktokcdn.com/aweme/100x100/tos-alisg-avt-0068/2c561cda61d019e3662504a5d3e33360.jpg?lk3s=30310797&nonce=28306&refresh_token=d494670e0244f58f48746dd7772411e9&x-expires=1729620000&x-signature=F2vvVhNtCF%2FPbDNWR9Szv8dGfuc%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418486523685716741", "username": "vinsmokelhnk", "nickname": "vinsmoke lhnk", "comment": "♥️", "create_time": "2024-09-25T14:56:51", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/fa06521b2e2274dcfd10367b6ece3e32~c5_100x100.jpg?lk3s=30310797&nonce=19735&refresh_token=6ae77a7cb894bd9ed37aaf8227be771f&x-expires=1729620000&x-signature=u56DWCpuxbbELKovk%2BcwV0U8pZA%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7419200341566423813", "username": "iamanna_004", "nickname": "NaNa⭐️_MSM", "comment": "sya ingin mensupport live kk nya , boleh check pesan yg sya krm ke kk? 🥰", "create_time": "2024-09-27T13:06:46", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/2777721bde819e885d7137a03a36bd45~c5_100x100.jpg?lk3s=30310797&nonce=45031&refresh_token=1d0478cc2ac0ac026a0be36d6d9d292e&x-expires=1729620000&x-signature=bhFor3sMPq1Ht8L0lPYcoSRbUkU%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7419180036514120453", "username": "iamanna_002", "nickname": "Anna🍇", "comment": "🔥Sya sudah mengirim psan pribadi ada ide yg menguntungkan kk nya , 🔥sya tunggu tanggapan kk nya ya☄️🥰", "create_time": "2024-09-27T11:48:02", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/16c8ab76e783d0eec3abb1ee52aeddb7~c5_100x100.jpg?lk3s=30310797&nonce=75661&refresh_token=4f023847e99e436bed44662fb86fe4a2&x-expires=1729620000&x-signature=Z01755jLtprticZdr7Ux1fxHt%2Fo%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418542111111742214", "username": "kujwu", "nickname": "Kuju", "comment": "mode buah naga 😳", "create_time": "2024-09-25T18:32:30", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/ceba6389e2851632afd7f202c88db569~c5_100x100.jpg?lk3s=30310797&nonce=97417&refresh_token=8c33eef9f2cca50b954c5d7d5e45bbe7&x-expires=1729620000&x-signature=8TzsxV%2FWC2hf5eE6%2BcPxh%2BAsOkQ%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7419727908501357318", "username": "geek.index", "nickname": "Geek Index", "comment": "\"hari ini rambut nya warna apa kak yo\"", "create_time": "2024-09-28T23:13:53", "avatar": "https://p16-sign-sg.tiktokcdn.com/aweme/100x100/tos-alisg-avt-0068/c37c835e1b8b1b34230e936b180e5424.jpg?lk3s=30310797&nonce=46369&refresh_token=b5ca90f0c4db0cbf4d2fce467402abab&x-expires=1729620000&x-signature=q1PdS5fEqqFotbuguH1K%2BK7IS2c%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7419196310366094085", "username": "anakkurangpiknik", "nickname": "anak kurang piknik", "comment": "Pinky girl🫣🥰", "create_time": "2024-09-27T12:51:05", "avatar": "https://p16-sign-useast2a.tiktokcdn.com/tos-useast2a-avt-0068-giso/2967a3230c9a6352e79b3e30b84eaa4e~c5_100x100.jpg?lk3s=30310797&nonce=70695&refresh_token=c23cf0cfe43725ea4b4ec2c2380c7c2c&x-expires=1729620000&x-signature=J2cgDJ3lL5vrzIVm27WE%2BMtZuDQ%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418543439006647045", "username": "yustinusadi6", "nickname": "ADI WIBU LOVERS ⚽️⚽️🎆🎆", "comment": "mirip freya jkt48", "create_time": "2024-09-25T18:37:37", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/21001331e298e834ba5f3edb0a6090ad~c5_100x100.jpg?lk3s=30310797&nonce=85765&refresh_token=1a7a84d01a19a41a81a17d63e92185d5&x-expires=1729620000&x-signature=fWX8ygJj5RobbAdq5AFZjrDHe1U%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418429285827183365", "username": "aarachman", "nickname": "Amin", "comment": "menyalaaaa", "create_time": "2024-09-25T11:14:48", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/1394671971553c8fe734b920a64c8954~c5_100x100.jpg?lk3s=30310797&nonce=41927&refresh_token=eea368d2c5e91406509f2c6763ddb217&x-expires=1729620000&x-signature=sVfzTNd7IpEiuGguKJD%2BSHxmzWo%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418336105004598022", "username": "ram.anakbaik", "nickname": "ram ditinggal ashel", "comment": "ihhh lucu kaya gulali :)", "create_time": "2024-09-25T05:12:59", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/859240dde3862fd850e79f97e24cbe18~c5_100x100.jpg?lk3s=30310797&nonce=93047&refresh_token=04dd5522d764513cd41cd3fbfbaf894d&x-expires=1729620000&x-signature=Au0s009yeqbfaTg5LjhqMBFf7N4%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}, {"comment_id": "7418321561776423685", "username": "pujiipunyanemo", "nickname": "Puji_PunyaNemo", "comment": "gasss pink lagi kak lucuuuu🥰", "create_time": "2024-09-25T04:16:36", "avatar": "https://p16-sign-va.tiktokcdn.com/tos-maliva-avt-0068/0ab572427ba94e908d6e5a768c621ebf~c5_100x100.jpg?lk3s=30310797&nonce=58072&refresh_token=93daf2ebdb77ba35f9818927caa98d3e&x-expires=1729620000&x-signature=4k8lzw22MpUhBq1jzNclbX9hMEw%3D&shp=30310797&shcp=-", "total_reply": 0, "replies": []}], "has_more": 0} -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import re 2 | import os 3 | import click 4 | import json 5 | 6 | from loguru import logger 7 | 8 | from tiktokcomment import TiktokComment 9 | from tiktokcomment.typing import Comments 10 | 11 | __title__ = 'TikTok Comment Scrapper' 12 | __version__ = '2.0.0' 13 | 14 | @click.command( 15 | help=__title__ 16 | ) 17 | @click.version_option( 18 | version=__version__, 19 | prog_name=__title__ 20 | ) 21 | @click.option( 22 | "--aweme_id", 23 | help='id video tiktok', 24 | callback=lambda _, __, value: match.group(0) if(match := re.match(r"^\d+$", value)) else None 25 | ) 26 | @click.option( 27 | "--output", 28 | default='data/', 29 | help='directory output data' 30 | ) 31 | def main( 32 | aweme_id: str, 33 | output: str 34 | ): 35 | if(not aweme_id): 36 | raise ValueError('example id : 7418294751977327878') 37 | 38 | logger.info( 39 | 'start scrap comments %s' % aweme_id 40 | ) 41 | 42 | comments: Comments = TiktokComment()( 43 | aweme_id=aweme_id 44 | ) 45 | 46 | if not ( 47 | os.path.exists( 48 | dir := os.path.dirname(output) 49 | ) 50 | ): 51 | os.makedirs(dir) 52 | 53 | json.dump( 54 | comments.dict, 55 | open( 56 | (final_path := '%s%s.json' % (output, aweme_id)), 57 | 'w' 58 | ), 59 | ensure_ascii=False 60 | ) 61 | 62 | logger.info( 63 | 'save comments %s on %s' % (aweme_id, final_path) 64 | ) 65 | 66 | 67 | if(__name__ == '__main__'): 68 | main() -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Requests==2.31.0 2 | -------------------------------------------------------------------------------- /tiktokcomment/__init__.py: -------------------------------------------------------------------------------- 1 | from .tiktokcomment import TiktokComment -------------------------------------------------------------------------------- /tiktokcomment/tiktokcomment.py: -------------------------------------------------------------------------------- 1 | import jmespath 2 | 3 | from typing import Any, Dict, Iterator 4 | from requests import Session, Response 5 | from loguru import logger 6 | from typing import Optional 7 | from datetime import datetime 8 | from tiktokcomment.typing import Comments, Comment 9 | 10 | class TiktokComment: 11 | BASE_URL: str = 'https://www.tiktok.com' 12 | API_URL: str = '%s/api' % BASE_URL 13 | 14 | def __init__( 15 | self: 'TiktokComment' 16 | ) -> None: 17 | self.__session: Session = Session() 18 | 19 | def __parse_comment( 20 | self: 'TiktokComment', 21 | data: Dict[str, Any] 22 | ) -> Comment: 23 | data: Dict[str, Any] = jmespath.search( 24 | """ 25 | { 26 | comment_id: cid, 27 | username: user.unique_id, 28 | nickname: user.nickname, 29 | comment: text, 30 | create_time: create_time, 31 | avatar: user.avatar_thumb.url_list[0], 32 | total_reply: reply_comment_total 33 | } 34 | """ , 35 | data 36 | ) 37 | 38 | comment: Comment = Comment( 39 | **data, 40 | replies=list( 41 | self.get_all_replies(data.get('comment_id')) 42 | ) if data.get('total_reply') else [] 43 | ) 44 | 45 | logger.info('%s - %s : %s' % ( 46 | comment.create_time, 47 | comment.username, 48 | comment.comment 49 | ) 50 | ) 51 | 52 | return comment 53 | 54 | def get_all_replies( 55 | self: 'TiktokComment', 56 | comment_id: str 57 | ) -> Iterator[Comment]: 58 | page: int = 1 59 | while True: 60 | if( 61 | not (replies := self.get_replies( 62 | comment_id=comment_id, 63 | page=page 64 | )) 65 | ): break 66 | for reply in replies: 67 | yield reply 68 | 69 | page += 1 70 | 71 | def get_replies( 72 | self: 'TiktokComment', 73 | comment_id: str, 74 | size: Optional[int] = 50, 75 | page: Optional[int] = 1 76 | ): 77 | response: Response = self.__session.get( 78 | '%s/comment/list/reply/' % self.API_URL, 79 | params={ 80 | 'aid': 1988, 81 | 'comment_id': comment_id, 82 | 'item_id': self.aweme_id, 83 | 'count': size, 84 | 'cursor': (page - 1) * size 85 | } 86 | ) 87 | 88 | return [ 89 | self.__parse_comment( 90 | comment 91 | ) for comment in response.json().pop('comments') 92 | ] 93 | 94 | def get_all_comments( 95 | self: 'TiktokComment', 96 | aweme_id: str 97 | ) -> Comments: 98 | page: int = 1 99 | data: Comments = self.get_comments( 100 | aweme_id=aweme_id, 101 | page=page 102 | ) 103 | while(True): 104 | page += 1 105 | 106 | comments: Comments = self.get_comments( 107 | aweme_id=aweme_id, 108 | page=page 109 | ) 110 | if(not comments.has_more): break 111 | 112 | data.comments.extend( 113 | comments.comments 114 | ) 115 | 116 | return data 117 | 118 | def get_comments( 119 | self: 'TiktokComment', 120 | aweme_id: str, 121 | size: Optional[int] = 50, 122 | page: Optional[int] = 1 123 | ) -> Comments: 124 | self.aweme_id: str = aweme_id 125 | 126 | response: Response = self.__session.get( 127 | '%s/comment/list/' % self.API_URL, 128 | params={ 129 | 'aid': 1988, 130 | 'aweme_id': aweme_id, 131 | 'count': size, 132 | 'cursor': (page - 1) * size 133 | } 134 | ) 135 | 136 | data: Dict[str, Any] = jmespath.search( 137 | """ 138 | { 139 | caption: comments[0].share_info.title, 140 | video_url: comments[0].share_info.url, 141 | comments: comments, 142 | has_more: has_more 143 | } 144 | """, 145 | response.json() 146 | ) 147 | 148 | return Comments( 149 | comments=[ 150 | self.__parse_comment( 151 | comment 152 | ) for comment in data.pop('comments') 153 | ], 154 | **data, 155 | ) 156 | 157 | def __call__( 158 | self: 'TiktokComment', 159 | aweme_id: str 160 | ) -> Comments: 161 | return self.get_all_comments( 162 | aweme_id=aweme_id 163 | ) 164 | -------------------------------------------------------------------------------- /tiktokcomment/typing/__init__.py: -------------------------------------------------------------------------------- 1 | from .comments import Comments 2 | from .comment import Comment -------------------------------------------------------------------------------- /tiktokcomment/typing/comment.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from datetime import datetime 4 | 5 | from typing import Optional, List, Dict, Any 6 | 7 | class Comment: 8 | def __init__( 9 | self: 'Comment', 10 | comment_id: str, 11 | username: str, 12 | nickname: str, 13 | comment: str, 14 | create_time: str, 15 | avatar: str, 16 | total_reply: int, 17 | replies: Optional[List['Comment']] = [] 18 | ) -> None: 19 | self._comment_id: str = comment_id 20 | self._username: str = username 21 | self._nickname: str = nickname 22 | self._comment: str = comment 23 | self._create_time: str = datetime\ 24 | .fromtimestamp( 25 | create_time 26 | ).strftime("%Y-%m-%dT%H:%M:%S") 27 | self._avatar: str = avatar 28 | self._total_reply: int = total_reply 29 | self._replies: List['Comment'] = replies 30 | 31 | @property 32 | def comment_id( 33 | self: 'Comment' 34 | ) -> str: 35 | return self._comment_id 36 | 37 | @property 38 | def username( 39 | self: 'Comment' 40 | ) -> str: 41 | return self._username 42 | 43 | @property 44 | def nickname( 45 | self: 'Comment' 46 | ) -> str: 47 | return self._nickname 48 | 49 | @property 50 | def comment( 51 | self: 'Comment' 52 | ) -> str: 53 | return self._comment 54 | 55 | @property 56 | def create_time( 57 | self: 'Comment' 58 | ) -> str: 59 | return self._create_time 60 | 61 | @property 62 | def avatar( 63 | self: 'Comment' 64 | ) -> str: 65 | return self._avatar 66 | 67 | @property 68 | def total_reply( 69 | self: 'Comment' 70 | ) -> int: 71 | return self._total_reply 72 | 73 | @property 74 | def replies( 75 | self: 'Comment' 76 | ) -> List['Comment']: 77 | return self._replies 78 | 79 | @property 80 | def dict( 81 | self: 'Comment' 82 | ) -> Dict[str, Any]: 83 | return { 84 | 'comment_id': self._comment_id, 85 | 'username': self._username, 86 | 'nickname': self._nickname, 87 | 'comment': self._comment, 88 | 'create_time': self._create_time, 89 | 'avatar': self._avatar, 90 | 'total_reply': self._total_reply, 91 | 'replies': [reply.dict for reply in self._replies] 92 | } 93 | 94 | @property 95 | def json( 96 | self: 'Comment' 97 | ) -> str: 98 | return json.dumps(self.json) 99 | 100 | def __str__( 101 | self: 'Comment' 102 | ) -> str: 103 | return self.json -------------------------------------------------------------------------------- /tiktokcomment/typing/comments.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from typing import List, Any, Dict 4 | 5 | from .comment import Comment 6 | 7 | class Comments: 8 | def __init__( 9 | self: 'Comments', 10 | caption: str, 11 | video_url: str, 12 | comments: List[Comment], 13 | has_more: int 14 | ) -> None: 15 | self._caption: str = caption 16 | self._video_url: str = video_url 17 | self._comments: List[Comment] = comments 18 | self._has_more: int = has_more 19 | 20 | @property 21 | def caption( 22 | self: 'Comments' 23 | ) -> str: 24 | return self._caption 25 | 26 | @property 27 | def video_url( 28 | self: 'Comments' 29 | ) -> str: 30 | return self._video_url 31 | 32 | @property 33 | def comments( 34 | self: 'Comments' 35 | ) -> List[Comment]: 36 | return self._comments 37 | 38 | @property 39 | def has_more( 40 | self: 'Comments' 41 | ) -> int: 42 | return self._has_more 43 | 44 | @property 45 | def dict( 46 | self: 'Comments' 47 | ) -> Dict[str, Any]: 48 | return { 49 | 'caption': self._caption, 50 | 'video_url': self._video_url, 51 | 'comments': [comment.dict for comment in self._comments], 52 | 'has_more': self._has_more 53 | } 54 | 55 | @property 56 | def json( 57 | self: 'Comments' 58 | ) -> str: 59 | return json.dumps(self.dict) 60 | 61 | def __str__( 62 | self: 'Comments' 63 | ) -> str: 64 | return self.json --------------------------------------------------------------------------------