> This page is for 플랫폼, version 레거시.
> For other versions, use one of these documentation indexes:
> - V4 (default): https://next.developer.frame.io/platform/v4/llms.txt
> - V4 실험적: https://next.developer.frame.io/platform/v4-experimental/llms.txt
> - 레거시: https://next.developer.frame.io/platform/v2/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://next.developer.frame.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://next.developer.frame.io/_mcp/server.

# 프로젝트에서 모든 코멘트 수집하기

## 개요




코멘트 스크래퍼는 프로젝트의 모든 에셋을 검색하고, 코멘트를 스크랩하여 .csv 파일로 출력합니다. 이 연습에서는 다음 리소스를 사용합니다.



* [Python SDK](https://github.com/Frameio/python-frameio-client) - SDK가 페이지 매김을 처리해 주며, 개발자 토큰(Bearer 인증)과 함께 사용할 수 있는 클라이언트를 설정합니다.
* [Python 코멘트 스크래퍼](https://github.com/Frameio/comment-scraper-python) - 여기서 사용하는 코드 샘플을 확인할 수 있습니다.




### Glitch에서 사용해 보기

Glitch는 자체 애플리케이션을 설정하고 해당 서버를 사용하여 테스트 및 실행할 수 있는 간단한 도구입니다. Glitch에 익숙하지 않다면 [Glitch 사용](/other-tools/using-glitch) 가이드를 확인하세요. 코멘트 스크래퍼가 서버에서 작동하는 것을 보려면 [Glitch](https://glitch.com)에 설정된 Flask 앱인 [Frame.io Comment Scraper in Python](https://glitch.com/~frameio-comment-scraper)을 확인해 보세요.

### 필수 범위




이 가이드를 시작하기 전에 최소한 다음 범위가 포함된 토큰이 있는지 확인해야 합니다.




| 범위 | 이유 |
| ---------- | ---------- |
| **Projects:** Read | 반드시 필요한 것은 아니지만, 프로젝트의 `root_asset_id`를 가져오는 데 필요합니다. |
| **Assets:** Read | API를 통해 `asset_ids`를 탐색하는 데 필요합니다. |
| **Comments:** Read | 코멘트 자체를 검색하는 데 필요합니다. |




### 1.앱 준비하기

이 가이드는 [파일 트리 읽기](/workflows-assets/reading-the-file-tree)와 유사한 패턴을 따릅니다 -- 따라서 시작하려면 다음이 필요합니다.
* 크롤링할 프로젝트의 `root_asset_id`
* [개발자 토큰](/authentication/developer-tokens)

또한 Python 앱에 `FrameioClient`와 몇 가지 추가 도우미 라이브러리를 임포트해야 합니다.

**`Python`**

```python title="Python"
from frameioclient import FrameioClient
import requests, json, csv, itertools

ROOT_ASSET_ID = "<ROOT_ASSET_ID>"
TOKEN = "<DEV_TOKEN>"
```





### 2.프로젝트 크롤링




이제 모든 에셋을 재귀적으로 가져오고, 코멘트가 있는지 확인하여, .csv 파일을 구성하는 데 사용할 목록에 코멘트가 있는 에셋을 보관해야 합니다.





프로젝트를 크롤링할 때 각 에셋에 대해 다음 사항을 확인해야 합니다.



* 에셋이 파일인가요? (`&quot;_type&quot;: &quot;file&quot;`).

* 파일인 경우 코멘트가 있나요? * **그렇다면 코멘트를 가져와서 목록에 추가하세요.**
* 에셋이 폴더인가요? (`&quot;_type&quot;: &quot;folder&quot;`)

* **폴더인 경우 하위 항목에 대해 재귀적으로 수행하세요.**
* 에셋이 버전 스택인가요? (`&quot;_type&quot;: &quot;version_stack&quot;`)

* **버전 스택인 경우 모든 하위 항목을 가져와 코멘트가 있는지 확인하세요.**

**`Python`**

```python title="Python"
def all_comments(client, asset_id, comment_list):
    files = client.get_asset_children(asset_id)

    for asset in files:
        if asset['type'] == "file":
            if asset['comment_count'] > 0:
                asset_parent_id = asset['parent_id']
                asset_name = asset['name']
                comments = client.get_comments(asset['id'])
                my_comment_list = [comment for comment in comments.results]
                for object in my_comment_list:
                    object.update({'parent_id':asset_parent_id})
                    object.update({'name':asset_name})
                comment_list.append(my_comment_list)

        if asset['type'] == "folder":
            if asset['item_count'] > 0:
                all_comments(client, asset['id'], comment_list)

        if asset['type'] == "version_stack":
            asset_name = asset['name']
            parent_id = asset['parent_id']
            vfiles = client.get_asset_children(asset['id'])

            for asset in vfiles.results:
                asset_name = asset['name']
                parent_id = asset['parent_id']
                if asset['type'] == "file":
                    if asset['comment_count'] > 0:
                        comments = client.get_comments(asset['id'])
                        my_comment_list = [comment for comment in comments.results]
                        for object in my_comment_list:
                            object.update({'parent_id':parent_id})
                            object.update({'name':asset_name})
                        comment_list.append(my_comment_list)

def get_all_project_comments(root_asset_id, token):
    comment_list = []
    client = FrameioClient(token)

    all_comments(client, root_asset_id, comment_list)

    return comment_list
```




<Info title="페이지 매김을 잊지 마세요">
  위의 예제에서는 페이지 매김을 무시하지만, 대규모 컬렉션을 탐색할 때는 무시해서는 안 됩니다! 참고하려면 [주요 개념](/getting-started/key-concepts#pagination) 가이드를 확인하세요.
</Info>


### 3.코멘트 목록 평탄화하기




크롤링 중에 이 작업을 처리하지 않았다면, 더 쉬운 처리를 위해 목록을 평탄화하는 것이 좋습니다.





**`Python`**

```python title="Python"
# The response list comes back as a list of lists.
# Flatten out responses to a single list so you can build your .csv file.

flat_response_list = list(itertools.chain.from_iterable(responses))
```





### 4.목록을 추려내고 .csv 만들기




목록을 단일 구조로 정리하고 나면, 리스트 컴프리헨션을 사용해 각 코멘트에서 원하는 데이터만 골라내어 .csv 파일로 저장할 수 있습니다. 최소한 다음 항목을 포함하는 것이 좋습니다.



* 코멘트 - `text`
* 상위 ID - `parent_id`
* 에셋 ID - `asset_id`
* 에셋 이름 - `name`
* 소유자 ID - `owner_id`
* 소유자 이메일 - `owner.email`
* 타임스탬프 - `timestamp`
* 업데이트 시간 - `updated_at`




최종 출력을 위해 에셋당 원하는 출력이 포함된 새 목록을 만들었다면, 이제 .csv 파일에 기록할 차례입니다.





**`Python`**

```python title="Python"
list_for_csv = [[o['text'], o['parent_id'], o['asset_id'], o['name'], o['owner_id'], o['owner']['email'], o['timestamp'], o['updated_at']] for o in flat_response_list]

# Let's write our new list out to a .csv file. We'll add a heading.
with open("output.csv", 'w') as myfile:
     wr = csv.writer(myfile, dialect='excel')
     wr.writerow(['Comment', 'Parent ID', 'Asset ID', 'Asset Name', 'Owner ID', 'Email', 'Timestamp', 'Updated At'])
     wr.writerows(list_for_csv)
```





이것으로 끝입니다! 이제 전체 Frame.io 프로젝트의 평탄화된 코멘트가 포함된 .csv 파일이 준비되었습니다.