NLP와 ML을 활용한 자신의 LinkedIn 게시물 분석하기
요약
LinkedIn 게시물 데이터를 활용하여 콘텐츠의 성과를 분석하고 향후 전략을 제안하는 로컬 인텔리전스 플랫폼 LinkForge 구축 과정을 다룹니다. NLP를 통한 감성 분석과 문장 임베딩을 활용한 데이터 기반의 인사이트 도출 방법을 설명합니다.
핵심 포인트
- LinkedIn API 대신 데이터 내보내기 기능을 활용한 안전한 데이터 수집
- sentence-transformers를 이용한 게시물 문장 임베딩 및 pgvector 저장
- VADER를 확장하여 기술적 깊이와 어조 등 사용자 정의 감성 분석 수행
- 수집, 분석, 프레젠테이션의 3계층 아키텍처 설계
LinkedIn은 사용자에게 많은 것을 제공하지 않습니다. 게시물이 잘 되었을 경우 좋아요 수와 대략적인 인구 통계학적 분석 결과 정도만 볼 수 있습니다. 참여 이력(engagement history)을 유용한 형식으로 내보낼 수도 없고, 자신의 콘텐츠를 프로그래밍 방식으로 쿼리(query)할 수도 없으며, 무엇보다 그 데이터를 기반으로 모델을 학습시킬 수도 없습니다.
저는 단순히 "이 게시물이 잘 되었다"가 아니라, 무엇이 실제로 제 게시물의 참여를 유도하는지, 그리고 그 이유가 무엇인지, 그것이 다음에 무엇을 써야 하는지에 대해 무엇을 시사하는지를 이해하고 싶었습니다. 그래서 저는 LinkedIn 게시물 이력을 가져오고, 콘텐츠와 댓글에 대해 NLP(자연어 처리) 분석을 수행하며, 프로필별 참여 예측 모델(engagement predictor)을 학습시키고, 향후 게시물을 위한 데이터 기반 권장 사항을 생성하는 로컬 콘텐츠 인텔리전스 플랫폼인 LinkForge를 구축했습니다.
이 글에서는 이것이 어떻게 작동하는지, 왜 특정 아키텍처(architecture)를 선택했는지, 그리고 무엇을 배웠는지에 대해 다룹니다.
데이터 문제
첫 번째 본능은 LinkedIn API를 사용하는 것입니다. 문제는 API가 개인용 분석이 아닌 앱 통합을 위해 설계되었다는 점입니다. 자신의 콘텐츠에 대한 엔드포인트(endpoint)는 존재하지만, ML(머신러닝)에 필요한 수준의 세밀한 참여 데이터는 사용할 수 없거나, 승인까지 몇 주가 걸리고 보장되지도 않는 Marketing Developer Platform 검토가 필요합니다.
두 번째 본능은 스크래핑(scraping)입니다. 여기서의 문제는 LinkedIn의 집행 태세입니다. 공격적인 속도 제한(rate limiting), 봇 탐지, 그리고 계정 제한 등이 있습니다.
가장 깔끔한 접근 방식은 LinkedIn 자체의 데이터 내보내기(data export)입니다. 설정(Settings) > 데이터 개인정보 보호(Data Privacy) > 데이터 복사본 받기(Get a copy of your data) 메뉴에서 게시물 이력을 요청할 수 있습니다. 그러면 게시물, 날짜, 참여 수치가 포함된 CSV 파일이 들어 있는 ZIP 파일을 받게 됩니다. 스크래핑도, API 협상도, 위험도 없습니다.
LinkForge를 위해 저는 Playwright 기반의 스크래퍼도 구현했지만, 실제 운영 환경에서 사용한다면 내보내기 경로를 권장합니다. 스크래퍼는 완전성을 위해 코드베이스에 포함되어 있지만, 데이터 내보내기 경로가 더 합리적입니다.
아키텍처
시스템은 수집(ingestion), 분석(analysis), 그리고 프레젠테이션(presentation)의 세 가지 레이어로 구성됩니다.
수집(Ingestion) 레이어는 LinkedIn 내보내기 파일(또는 선택적으로 스크래핑)을 파싱하여 프로필과 게시물을 PostgreSQL에 저장합니다. 각 게시물은 sentence-transformers의 all-MiniLM-L6-v2를 통해 384차원의 문장 임베딩(sentence embedding)을 생성하며, 이는 pgvector 컬럼에 저장됩니다. 이를 통해 나중에 유사도 쿼리(similarity queries)가 가능해집니다. 즉, 특정 입력과 주제적으로 유사한 게시물을 찾거나 주제별로 콘텐츠를 클러스터링(clustering)할 수 있습니다.
분석(Analysis) 레이어는 게시물 코퍼스(corpus)에 대해 다음 네 가지 작업을 수행합니다:
- VADER를 이용한 감성 점수(Sentiment scoring) 산출: 세 가지 사용자 정의 차원인 실용적/균형 잡힌 어조(pragmatic/balanced tone), 부족주의 점수(tribalism score), 기술적 깊이(technical depth)를 추가하여 확장했습니다. 표준 VADER는 기술적인 LinkedIn 콘텐츠에서 중요한 요소를 포착하지 못하기 때문에 이러한 추가 사항이 중요합니다.
- 고정된 분류 체계(taxonomy)를 통한 주제 탐지(Theme detection): 기술적 심층 분석(technical deep dive), 개인적인 이야기(personal story), 비판(critique), 실용적 균형(pragmatic balance) 및 기타 몇 가지 주제로 분류됩니다. 각 게시물에는 주제와 신뢰도 점수(confidence score)가 부여됩니다.
- 댓글 감성 분포에서 도출된 양극화 점수(Polarization scoring): 매우 긍정적이거나 매우 부정적인 댓글이 섞여 있어 양극화된 게시물은 반응이 균일하게 중립적인 게시물과 다른 점수를 받습니다.
- 프로필의 자체 이력을 바탕으로 요청 시마다 학습되는 scikit-learn 랜덤 포레스트(random forest)를 통한 참여도 예측(Engagement prediction): 모델은 글로벌 기준(global baseline)이 아닌, 해당 프로필 자체의 분포와 비교하여 참여도 추정치와 성공 확률을 생성합니다.
프로필별 학습은 의도적인 설계 선택입니다. 보안 연구원에게 효과적인 방식이 프론트엔드 개발자에게 효과적인 방식은 아닙니다. 자신의 분포(distribution)를 바탕으로 학습함으로써 이러한 혼동을 완전히 방지할 수 있습니다.
추천(Recommendations)은 프로필 이력에서 가장 성과가 좋은 콘텐츠 패턴(주제, 어조, 구조, 후크 유형 등)을 식별하고, 해당 패턴들로부터 제안된 다음 게시물 계획을 구축함으로써 생성됩니다.
백엔드(Backend)는 SQLAlchemy 2.0 비동기(async)를 사용하는 FastAPI입니다. 대시보드(Dashboard)는 Streamlit입니다. 모든 데이터 영속성(persistence)은 pgvector가 포함된 PostgreSQL이 처리합니다.
분석을 통해 실제로 드러나는 것들
제가 예상하지 못했던 몇 가지 사항은 다음과 같습니다:
기술적 깊이 (Technical depth)는 비직관적인 방식으로 참여도 (engagement)와 상관관계를 가집니다. 매우 높은 기술적 깊이는 종종 중간 정도의 깊이에 비해 성과가 낮습니다. 기술적인 내용을 설명하면서도 더 넓은 기술적 청중이 이해할 수 있도록 접근성을 유지하는 게시물이, 오직 심층 전문가만을 대상으로 하는 게시물보다 더 높은 성과를 내는 경향이 있습니다.
게시물이 내집단 (in-group)을 외집단 (out-group)에 대항하여 얼마나 설정하는지를 측정하는 부족주의 점수 (tribalism score)는 참여도를 예측하는 강력한 양의 지표입니다. 이것이 부족주의적인 콘텐츠를 작성하라는 권고는 아닙니다. 다만 알아둘 가치가 있는 발견입니다.
논쟁을 불러일으키는 게시물의 경우, 댓글의 양극화 (Comment polarization)가 단순 반응 (reaction) 수보다 더 나은 참여 신호가 됩니다. 40개의 반응과 30개의 양극화된 댓글이 달린 게시물은, 반응이 200개이지만 댓글이 없는 게시물보다 실제 도달 범위 증폭 (reach amplification) 측면에서 종종 더 높은 성과를 냅니다.
실행하기 (Running it)
git clone https://github.com/ChronoCoders/linkforge
cd linkforge
python -m venv .venv
...
데이터 내보내기 경로의 경우, LinkedIn CSV 내보내기 파일을 프로젝트 디렉토리에 배치하고 시드 스크립트 (seed script) 또는 임포트 엔드포인트 (import endpoint)를 사용하세요. 쿠키 (cookies)는 필요하지 않습니다.
백엔드가 실행 중일 때 전체 API는 /docs에 문서화되어 있습니다.
다음 단계 (What's next)
참여도 예측기 (engagement predictor)는 사용자가 보유한 이력에 따라 학습된 랜덤 포레스트 (random forest)입니다. 데이터가 많아질수록 성능이 향상됩니다. 제가 작업 중인 다음 단계는 적절한 시계열 (time-series) 구성 요소를 도입하는 것입니다. 참여 패턴은 시간이 지남에 따라 변화하며, 현재 모델은 게시물이 작성된 시점과 관계없이 모든 과거 게시물을 동일하게 취급합니다.
추천 엔진 (recommendation engine)은 현재 게시물 수준에서 제안을 생성합니다. 저는 이를 콘텐츠 캘린더 (content calendar) 제안으로 확장하고 싶습니다. 사용자의 게시 빈도와 콘텐츠 구성 (content mix)을 고려하여, 향후 2주간의 게시 일정이 어떠해야 하는지를 제안하는 방식입니다.
면책 조항 (Disclaimer)
LinkedIn의 이용 약관(User Agreement) 및 전문 커뮤니티 정책(Professional Community Policies)에 따라 LinkedIn의 자동 스크래핑(Automated scraping)은 금지되어 있습니다. 이 코드베이스에 포함된 스크래핑 구성 요소들은 오직 교육 및 연구 목적으로만 제공됩니다. 이를 사용할 경우, LinkedIn의 서비스 약관, 관련 법률, 그리고 GDPR 및 CCPA를 포함한 데이터 보호 규정(data protection regulations)을 준수할 모든 책임은 사용자 본인에게 있습니다. 계정 제한 또는 해지는 실제로 발생할 수 있는 결과입니다. 권장되는 방식은 이러한 위험이 없는 LinkedIn의 공식 데이터 내보내기(official data export) 기능을 사용하는 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기