Skip to content

Repository files navigation

@gurumnyang/dcinside.js

NPM Version Downloads

디시인사이드 갤러리 크롤링을 위한 Node.js 라이브러리입니다.

설치 방법

# NPM
npm install @gurumnyang/dcinside.js

# Yarn
yarn add @gurumnyang/dcinside.js

기능

  • 갤러리 게시판 조회, 게시글 내용 조회
  • 게시글 댓글 조회
  • 게시글 내의 이미지 URL 추출
  • 통합검색 결과 수집
  • 로그인 및 인증 쿠키 수집
  • 게시글 게시, 삭제
  • 댓글 게시, 삭제
  • 실시간 베스트 추천(실베추)

사용 방법

빠른 시작

const dc = require('@gurumnyang/dcinside.js');

(async () => {
  // 1) 페이지별 게시글 목록 (모바일 파서 기본)
  const list = await dc.getPostList({ page: 1, galleryId: 'chatgpt', boardType: 'all' });

  // 2) 단일 게시글 본문/댓글
  const post = await dc.getPost({ galleryId: 'chatgpt', postNo: list[0].id, extractImages: true });

  // 3) 통합검색
  const search = await dc.search('챗지피티');

  console.log(list.length, post?.title, search.posts.length);
})();

레거시(PC) 목록 파서는 다음과 같이 호출할 수 있습니다.

const listPc = await dc.getPostListLegacy({ page: 1, galleryId: 'programming', boardType: 'all' });

타입 상세

// SearchGalleryItem 예시
{
  name: '챗지피티(ChatGPT)ⓜ',
  id: 'chatgpt',
  type: 'mgallery',       // 내부 호환용: 'board'|'mgallery'|'mini'|'person'
  galleryType: 'mgallery',// 구분용: 'main'|'mgallery'|'mini'|'person'
  link: 'https://gall.dcinside.com/mgallery/board/lists/?id=chatgpt',
  rank: 153,
  new_post: 12,
  total_post: 345
}

// SearchPost 예시
{
  title: '첫 번째 게시글',
  content: '요약 내용',
  galleryName: '챗지피티(ChatGPT)ⓜ',
  galleryId: 'chatgpt',
  galleryType: 'mgallery', // 'main'|'mgallery'|'mini'|'person'
  date: '2025.08.11 10:00:00',
  link: 'https://gall.dcinside.com/mgallery/board/view/?id=chatgpt&no=1111'
}

모바일 로그인 & 글쓰기 예시

모바일 로그인 세션을 확보하면 쿠키를 그대로 재사용해 글쓰기/삭제에 활용할 수 있습니다(PC 미지원)

캡차에 걸릴 경우 success:false를 반환합니다

const dc = require('@gurumnyang/dcinside.js');

(async () => {
  const login = await dc.mobileLogin({ code: process.env.DC_ID, password: process.env.DC_PW });
  if (!login.success) {
    throw new Error(`로그인 실패: ${login.reason}`);
  }

  const write = await dc.createPost({
    galleryId: 'dragonlake',
    subject: '테스트 제목',
    content: '테스트 본문입니다.',
    images: [
      {
        data: require('fs').readFileSync('./example.jpg'),
        filename: 'example.jpg',
        contentType: 'image/jpeg',
      },
    ],
    jar: login.jar, // 로그인 시 얻은 쿠키를 그대로 사용
  });

  if (!write.success) {
    console.log(write.message || '글쓰기 실패');
    return;
  }

  console.log('등록된 게시글 번호:', write.postId, '이동 URL:', write.redirectUrl);

  const remove = await dc.deletePost({
    galleryId: 'dragonlake',
    postId: write.postId,
    jar: login.jar,
  });

  console.log('삭제 성공 여부:', remove.success, '메시지:', remove.message);
})();

댓글을 제거하려면 await dc.deleteComment({ galleryId: 'dragonlake', postId: 글번호, commentId: 댓글번호, jar: login.jar }); 형태로 호출하면 됩니다. 댓글을 작성하려면 await dc.createComment({ galleryId: 'dragonlake', postId: 글번호, content: '댓글 내용', jar: login.jar }); 형태로 호출하면 됩니다. 게스트는 nickname, password, captchaCode를 함께 전달하세요.

실시간 베스트 추천(실베추)

실시간 베스트 추천을 수행합니다.

const dc = require('@gurumnyang/dcinside.js');

(async () => {
  // (optional) 로그인 세션이 있다면 jar을 전달할 수 있습니다.
  // const login = await dc.mobileLogin({ code: process.env.DC_ID, password: process.env.DC_PW });
  // const jar = login.success ? login.jar : undefined;

  // (optional) 프록시 사용 예시 (Axios ProxyConfig 형식)
  const proxy = process.env.HTTP_PROXY
    ? (() => {
        const u = new URL(process.env.HTTP_PROXY);
        return {
          protocol: u.protocol.replace(':', ''),
          host: u.hostname,
          port: u.port ? Number(u.port) : undefined,
          auth: u.username ? { username: u.username, password: u.password } : undefined,
        };
      })()
    : undefined;

  const result = await dc.recommendBest({
    galleryId: 'chatgpt',
    postId: 68960,
    // jar,
    userAgent: process.env.DC_UA,
    proxy,
  });

  console.log('성공 여부:', result.success);
  console.log('메시지:', result.message);
  console.log('HTTP Status:', result.responseStatus);
})();

관리자 게시글 끌올

mobileLogin()으로 로그인한 해당 갤러리 관리자 세션을 사용해 특정 게시글을 끌어올립니다. 관리자 권한이 없는 계정에는 끌올 UI가 노출되지 않으며, bumpPost()도 요청을 보내기 전에 이를 확인하고 중단합니다.

const dc = require('@gurumnyang/dcinside.js');

(async () => {
  const login = await dc.mobileLogin({
    code: process.env.DC_ID,
    password: process.env.DC_PW,
    returnUrl: 'https://gall.dcinside.com/mgallery/board/lists/?id=chatgpt',
  });
  if (!login.success) throw new Error(login.reason || '로그인 실패');

  const result = await dc.bumpPost({
    galleryId: 'chatgpt',
    postId: 12345,
    jar: login.jar,
  });

  console.log(result);
})();

기본 galleryType은 마이너 갤러리인 minor입니다. 미니 갤러리는 mini, 인물 갤러리는 person을 지정할 수 있습니다. 고정글이나 공지는 DCInside 정책상 끌올할 수 없습니다.

갤러리 말머리 조회 및 관리자 변경

const headTexts = await dc.getGalleryHeadTexts({ galleryId: 'chatgpt' });
// [{ id: '0', name: '잡담' }, { id: '120', name: '❓질문' }, ...]

const changed = await dc.changePostHeadText({
  galleryId: 'chatgpt',
  postId: 115586,
  headTextId: 10,
  jar: login.jar,
});

getGalleryHeadTexts()는 공개 목록에서 조회하므로 로그인 없이 사용할 수 있습니다. changePostHeadText()는 관리자 전용 단일 필드 변경 API를 사용하므로 해당 갤러리 관리자 세션이 필요하며, 자기 글과 타인 글 모두 같은 방식으로 처리합니다. 일반 작성자가 자기 글을 바꾸는 PC 게시물 수정은 제목·본문·첨부를 함께 재제출하는 별도 흐름이므로 이 함수에 포함하지 않습니다.

관리자 검색 필터에만 나타나는 특수 ID 999(매니저)는 타인 글 말머리 변경 API가 지원하지 않으므로 조회 결과에서 제외됩니다.

터미널 브라우저(TUI)

간단한 터미널 UI로 게시판 열람, 글 조회, 검색을 사용할 수 있습니다.

npm run tui

메뉴에서 게시판 목록 열람(페이지 이동), 통합검색(정확도/최신), 글 바로 조회(갤ID/번호)를 지원합니다.

User-Agent 관련 유틸리티 함수

const { getRandomUserAgent } = require('@gurumnyang/dcinside.js');

console.log(getRandomUserAgent()); // 무작위 User-Agent 문자열 반환

응답 데이터 형식

게시글 객체

{
  postNo: "1234567",
  title: "게시글 제목",
  author: "작성자 닉네임",
  date: "2025.01.01 12:34:56", 
  content: "게시글 내용...",
  viewCount: "123",
  recommendCount: "10",
  dislikeCount: "2",
  comments: {
    totalCount: 5,
    items: [
      {
        parent: "0", 
        id: "comment_id",
        author: {
          userId: "user_id",
          nickname: "댓글 작성자",
          ip: "1.2.3.*" // IP 표시가 된 경우에만
        },
        regDate: "01.01 12:34:56",
        memo: "댓글 내용"
      }
      // ...
    ]
  },
  // 이미지 URL 추출 옵션을 활성화한 경우에만 포함됨
  images: [
    "https://example.com/image1.jpg",
    "https://example.com/image2.jpg"
  ]
}

게시글 정보 객체 (PostInfo)

{
  id: "1234567",               // 게시글 번호
  type: "picture",              // 게시글 유형 ('notice', 'picture', 'text', 'recommended', 'unknown')
  subject: "일반",              // 말머리
  title: "게시글 제목입니다",    // 게시글 제목
  link: "https://gall.dcinside.com/mgallery/board/view/?id=programming&no=1234567", // 게시글 링크
  author: {
    nickname: "작성자닉네임",    // 작성자 닉네임
    userId: "writer_id",        // 작성자 ID (있는 경우만)
    ip: "1.2.3.*"              // 작성자 IP (표시된 경우만)
  },
  date: "2025.04.21 12:34:56",  // 작성 날짜
  count: 123,                   // 조회수
  recommend: 10,                // 추천수
  replyCount: 5                 // 댓글 수
}

통합검색 결과 객체 (SearchResult)

{
  query: '지피티',
  galleries: [
    {
      name: '챗지피티(ChatGPT)ⓜ',
      id: 'chatgpt',
      type: 'mgallery',
      link: 'https://gall.dcinside.com/mgallery/board/lists/?id=chatgpt',
      rank: 153,
      new_post: 615,
      total_post: 52041
    }
  ],
  posts: [
    {
      title: '지피티 수준이 어마어마하긴 함 3(feat.갤럼)',
      content: '비슷한 결과물 나오길 기대하면서 갤럼 그림 빌려서 같은 요청 해봤음 ????? 왜 나만??? - dc official App',
      galleryName: '챗지피티(ChatGPT) 갤러리',
      galleryId: 'chatgpt',
      date: '2025.08.12 21:57',
      link: 'https://gall.dcinside.com/mgallery/board/view/?id=chatgpt&no=52384'
    }
  ]
}

에러 처리와 재시도

라이브러리는 요청 실패 시 자동으로 재시도합니다. 기본 설정은 다음과 같습니다:

  • 최대 재시도 횟수: 3회
  • 재시도 간 지연 시간: 1000ms (지수 백오프 적용)

개별 호출 단위로 재시도 횟수를 바꾸려면 다음처럼 retryCount를 지정하세요. 공개 API에서는 재시도 간 지연 시간을 별도로 변경할 수 없습니다.

await dc.getPost({ galleryId: 'chatgpt', postNo: 12345, retryCount: 5 });
await dc.getPosts({ galleryId: 'chatgpt', postNumbers: [111, 222], retryCount: 5 });

API 레퍼런스

핵심 함수

getPostList(options)

갤러리 페이지에서 게시글 목록을 수집합니다. 기본은 모바일 파서입니다.

매개변수:

  • options (GetPostListOptions)
    • page (number): 페이지 번호
    • galleryId (string): 갤러리 ID
    • boardType ('all' | 'recommend' | 'notice', optional): 게시판 유형 (기본값: 'all')
    • delayMs (number, optional): 요청 간 지연 시간(ms)

반환값:

  • Promise<PostInfo[]>: 게시글 정보 객체의 배열

getPostListLegacy(options)

PC(레거시) 파서로 갤러리 페이지에서 게시글 목록을 수집합니다. 인터페이스는 getPostList와 동일합니다.


getPost(options)

게시글 번호로 게시글 내용을 가져옵니다. 기본은 모바일 파서입니다

매개변수:

  • options (GetPostOptions)
    • galleryId (string): 갤러리 ID
    • postNo (string | number): 게시글 번호
    • extractImages (boolean, optional): 이미지 URL 추출 여부 (기본값: true)
    • includeImageSource (boolean, optional): 본문에 이미지 URL 포함 여부 (기본값: false)
    • retryCount (number, optional): 이 호출에서 사용할 재시도 횟수 (전역 기본값을 덮어씀)

반환값:

  • Promise<Post | null>: 게시글 객체 또는 실패 시 null

getPostLegacy(options)

PC(레거시) 파서로 게시글 내용을 가져옵니다. 인터페이스는 getPost와 동일합니다.


getPosts(options)

여러 게시글 번호로 게시글 내용을 가져옵니다.

매개변수:

  • options (object)
    • galleryId (string): 갤러리 ID
    • postNumbers (Array<string | number>): 게시글 번호 배열
    • delayMs (number, optional): 요청 간 지연 시간(ms) (기본값: 100)
    • extractImages (boolean, optional): 이미지 URL 추출 여부 (기본값: true)
    • includeImageSource (boolean, optional): 본문에 이미지 URL 포함 여부 (기본값: false)
    • onProgress ((current: number, total: number) => void, optional): 진행 상황 콜백 함수 (current, total)
    • retryCount (number, optional): 각 게시글 요청에서 사용할 재시도 횟수 (전역 기본값을 덮어씀)

반환값:

  • Promise<Post[]>: 수집된 게시글 객체 배열

getAutocomplete(query)

검색어를 입력하면 DCInside 자동완성 결과(JSON)를 반환한다.

매개변수:

  • query (string): 검색어

반환값:

  • Promise<object>: 자동완성 결과 객체

search(query, options)

통합검색을 수행하고 결과를 반환한다.

매개변수:

  • query (string): 검색어
  • options (object, optional)
    • sort ('latest' | 'accuracy', optional): 정렬 기준

반환값:

  • Promise<SearchResult>: 검색 결과 객체 { query?, galleries, posts }

mobileLogin(options)

모바일 로그인 페이지를 통해 인증 쿠키를 획득합니다.

매개변수:

  • options (MobileLoginOptions)
    • code (string): 디시인사이드 식별 코드(ID)
    • password (string): 비밀번호
    • keepLoggedIn (boolean, optional): 자동 로그인 여부 (기본값: true)
    • userAgent (string, optional): 커스텀 User-Agent
    • jar (CookieJar, optional): 외부에서 생성한 쿠키 저장소를 재사용할 때 전달

반환값:

  • Promise<MobileLoginResult>: 성공 여부, 쿠키 목록, CookieJar, 리다이렉트 정보 등을 포함한 객체

createPost(options)

모바일 글쓰기 폼을 사용해 게시글을 등록합니다.

매개변수:

  • options (MobileCreatePostOptions)
    • galleryId (string): 갤러리 ID (required)
    • subject (string): 말머리/제목 (required)
    • content (string): 본문 (required)
    • headText (string | number, optional): 말머리 코드
    • nickname (string, optional): 비로그인 글쓰기용 닉네임
    • password (string, optional): 비로그인 글쓰기용 비밀번호
    • useGallNickname (boolean, optional): 갤러리 닉네임 사용 여부
    • jar (CookieJar, optional): 로그인으로 확보한 쿠키를 전달할 때 사용
    • userAgent (string, optional): 커스텀 User-Agent
    • extraFields (object, optional): 추가 폼 필드 강제 입력
    • images (MobilePostImage[], optional): 모바일 이미지 업로드 엔드포인트에 순서대로 전송해 본문 끝에 삽입할 이미지
      • data (Buffer): 이미지 원본 바이트
      • filename (string): DCInside에 전달할 파일명
      • contentType (string): image/jpeg, image/png 같은 MIME 타입
    • signmark (boolean, optional): true일 때만 첨부 이미지에 디시 로고와 작성자 닉네임을 표기 (기본값: false)

반환값:

  • Promise<MobileCreatePostResult>: 성공 여부, 게시글 번호, 리다이렉트 URL, 업로드된 imageUrls, 서버 메시지 등을 담은 객체

deletePost(options)

모바일 게시글 삭제 엔드포인트를 호출합니다.

매개변수:

  • options (MobileDeletePostOptions)
    • galleryId (string): 갤러리 ID (required)
    • postId (string | number): 삭제할 게시글 번호 (required)
    • jar (CookieJar, optional): 로그인 쿠키가 담긴 저장소
    • password (string, optional): 비로그인 삭제 시 사용하는 비밀번호
    • userAgent (string, optional): 커스텀 User-Agent

반환값:

  • Promise<MobileDeletePostResult>: 성공 여부와 서버 메시지를 담은 객체

deleteComment(options)

모바일 댓글 삭제 엔드포인트를 호출합니다.

매개변수:

  • options (MobileDeleteCommentOptions)
    • galleryId (string): 갤러리 ID (required)
    • postId (string | number): 댓글이 달린 게시글 번호 (required)
    • commentId (string | number): 삭제할 댓글 번호 (required)
    • jar (CookieJar, optional): 로그인 쿠키가 담긴 저장소
    • password (string, optional): 비로그인 댓글 삭제 시 사용하는 비밀번호
    • userAgent (string, optional): 커스텀 User-Agent

반환값:

  • Promise<MobileDeleteCommentResult>: 성공 여부와 서버 메시지를 담은 객체

recommendBest(options)

모바일 페이지에서 해당 게시글을 조회해 CSRF 토큰을 얻은 뒤 실시간 베스트 추천(실베추) 엔드포인트로 요청을 전송합니다.

매개변수:

  • options (BestRecommendOptions)
    • galleryId (string): 갤러리 ID (required)
    • postId (string | number): 추천할 게시글 번호 (required)
    • jar (CookieJar, optional): 로그인(세션) 쿠키 저장소
    • userAgent (string, optional): 커스텀 User-Agent
    • proxy (ProxyConfig, optional): Axios 프록시 설정 객체 또는 false

반환값:

  • Promise<BestRecommendResult>
    • success (boolean): 성공 여부
    • message (string, optional): 서버가 전달한 메시지(예: 이미 추천함 등)
    • responseStatus (number): HTTP 상태 코드
    • raw (any, optional): 서버 원본 응답 객체

bumpPost(options)

관리자 PC 화면과 같은 계약으로 특정 게시글을 끌어올립니다. mobileLogin()에서 받은 해당 갤러리 관리자 jar가 필수입니다.

매개변수:

  • options (ManagerBumpOptions)
    • galleryId (string): 갤러리 ID (required)
    • postId (string | number): 끌어올릴 게시글 번호 (required)
    • jar (CookieJar): 관리자 로그인 세션 (required)
    • galleryType (minor | mini | person, optional): 기본값 minor
    • userAgent (string, optional): 커스텀 User-Agent
    • proxy (ProxyConfig, optional): Axios 프록시 설정 객체 또는 false

반환값:

  • Promise<ManagerBumpResult>: 성공 여부, 서버 메시지, HTTP 상태와 원본 응답

getGalleryHeadTexts(options)

갤러리에서 사용할 수 있는 말머리를 { id, name } 배열로 반환합니다. jar는 optional입니다.

changePostHeadText(options)

관리자 세션으로 특정 게시글의 말머리만 변경합니다. galleryId, postId, headTextId, 관리자 jar가 필요합니다. 관리자 권한과 말머리 ID 유효성을 확인한 후 요청합니다.


유틸리티 함수

delay(ms)

지정된 시간(밀리초) 동안 실행을 지연시킵니다.

매개변수:

  • ms (number): 지연할 시간(밀리초)

반환값:

  • Promise<void>

getRandomUserAgent()

무작위 User-Agent 문자열을 반환합니다.

매개변수:

  • 없음

반환값:

  • string: 무작위 User-Agent 문자열

TypeScript 타입

  • AutocompleteResponse, AutocompleteGalleryItem, AutocompleteWikiItem
  • getAutocomplete(query: string): Promise<AutocompleteResponse>
  • raw.getAutocomplete(query: string): Promise<AutocompleteResponse>

TODO

  • 게시판 페이지 크롤링
  • 게시글 본문 가져오기
  • 댓글 가져오기
  • 모든 댓글 페이지 수집
  • 재시도 메커니즘 추가
  • 게시글 이미지 URL 추출
  • 검색 기능 지원
  • 이미지 다운로드 기능
  • 모바일 로그인/쿠키 수집
  • 모바일 게시글 작성/삭제
  • 모바일 댓글 삭제
  • 게시글 수정
  • 댓글 작성
  • 추천/비추천
  • 실시간 베스트 추천(실베추)

주의사항

  • 디시인사이드의 이용약관을 준수해주세요.
  • 과도한 요청은 IP 차단을 유발할 수 있으니 적절한 딜레이(delayMs)를 설정하세요.
  • 수집한 데이터는 개인 연구, 분석 등의 비상업적 용도로만 사용해주세요.

라이선스

MIT

About

No description, website, or topics provided.

Resources

Stars

6 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages