본문 바로가기

개드립 댓글 클리너

@Q002024. 12. 29. 11:15

개드립을 하다보면 댓글이 쌓이기 마련, 그게 한 두개도 아니고 수백 수천개가 쌓였을 때는 삭제가 난감할 때가 있습니다.

사실 인터넷을 하면서 내 흔적을 남겨놓기에는 찜찜한 구석이 있는 것도 사실.

어떻게 하면 편하게 자동화 할까 고민하다가 챗지피티의 도움을 받아서 만들었습니다.

 

개드립에 로그인 후, 하단 코드를 콘솔(F12)에 복붙하고 기다리면 끝입니다.

async function deleteComment(postNumber, commentNumber) {
    const token = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
    if (!token) {
        console.error('CSRF 토큰을 찾을 수 없습니다.');
        return;
    }
    const deleteUrl = "https://www.dogdrip.net/";
    const bodyData = new URLSearchParams({
        _filter: 'delete_comment',
        error_return_url: '',
        act: 'procBoardDeleteComment',
        mid: 'free',
        page: 1,
        document_srl: postNumber,  // 글번호
        comment_srl: commentNumber,  // 댓글번호
        module: 'board',
        _rx_ajax_compat: 'XMLRPC',
        _rx_csrf_token: token,  // CSRF 토큰
    });
    try {
        const response = await fetch(deleteUrl, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
                'X-CSRF-Token': token, 
                'X-Requested-With': 'XMLHttpRequest',
                'Accept': 'application/json, text/javascript, */*; q=0.01',
                'Accept-Language': 'ko,en-US;q=0.9,en;q=0.8,ko-KR;q=0.7',
                'Cache-Control': 'no-cache',
                'Pragma': 'no-cache',
                'Sec-Fetch-Dest': 'empty',
                'Sec-Fetch-Mode': 'cors',
                'Sec-Fetch-Site': 'same-origin',
            },
            referrer: `https://www.dogdrip.net/index.php?mid=free&document_srl=${postNumber}&act=dispBoardDeleteComment&comment_srl=${commentNumber}`,
            referrerPolicy: 'no-referrer-when-downgrade',
            body: bodyData.toString(),
            credentials: 'include', 
            mode: 'cors',
        });
        if (!response.ok) {
            return;
        }
        const text = await response.text();
        if (text.includes("삭제가 완료되었습니다")) {
            console.log(`댓글 ${commentNumber} (글번호: ${postNumber}) 삭제 완료`);
        }
    } catch (error) {
        console.error(`댓글 ${commentNumber} (글번호: ${postNumber}) 삭제 요청 중 오류 발생: ${error}`);
    }
}

async function deleteComments() {
    const baseUrl = "https://www.dogdrip.net/index.php?act=dispMemberOwnComment&mid=front&page=";
    let page = 1;
    let allComments = [];  // 모든 댓글을 저장할 배열

    // 페이지를 수집하는 함수
    async function fetchPage(pageNumber) {
        const response = await fetch(`${baseUrl}${pageNumber}`);
        if (!response.ok) {
            console.error(`Failed to fetch page ${pageNumber}`);
            return null;
        }
        const text = await response.text();
        const parser = new DOMParser();
        return parser.parseFromString(text, "text/html");
    }

    // 댓글 정보를 수집하는 함수
    async function getCommentsOnPage(pageNumber) {
        const doc = await fetchPage(pageNumber);
        if (!doc) return [];
        const rows = doc.querySelectorAll("table tbody tr td a");
        const comments = [];
        // 댓글이 없으면 빈 배열 반환
        if (rows.length === 0) {
            return null;
        }
        for (let aTag of rows) {
            const content = aTag.textContent.trim();
            const href = aTag.getAttribute("href");
            if (!href || content === "[삭제 되었습니다]" || content === "삭제 된 글입니다.") {
                continue;
            }
            const match = href.match(/^\/(\d+)\?comment_srl=(\d+)/);
            if (match) {
                const postNumber = match[1];
                const commentNumber = match[2];
                comments.push({ postNumber, commentNumber, content });
            }
        }
        return comments;
    }

    // 모든 페이지에서 댓글을 수집
    while (true) {
        console.log(`Parsing page ${page}...`);
        const comments = await getCommentsOnPage(page);
        // 댓글이 없거나 페이지에 <tbody> 안에 <tr> 요소가 없다면 종료
        if (!comments) {
            console.log(`Page ${page}에는 유효한 댓글이 없거나 더 이상 댓글이 없습니다. 수집을 종료합니다.`);
            break;  // 더 이상 댓글이 없으면 종료
        }
        allComments = allComments.concat(comments);  // 수집한 댓글을 배열에 추가
        console.log(`현재까지 수집된 댓글 수: ${allComments.length}`);  // 수집된 댓글 개수 출력
        page++;  // 다음 페이지로 넘어가기
        await new Promise(resolve => setTimeout(resolve, 1000));  // 페이지 간 이동 딜레이이
    }
    console.log(`모든 댓글 수집이 완료되었습니다. 총 ${allComments.length}개의 댓글 수집됨.`);

    for (let { postNumber, commentNumber, content } of allComments) {
        console.log(`댓글 내용: "${content}" (글번호: ${postNumber}) 삭제 시작...`);
        await deleteComment(postNumber, commentNumber);  // 댓글 삭제 요청 보내기
        await new Promise(resolve => setTimeout(resolve, 3000));  // 댓글 삭제 후 딜레이이
    }

    console.log("모든 댓글 삭제 작업이 완료되었습니다.");
}

deleteComments();  // 시작

 

 

지우개의 원리는 간단합니다.

 

개드립의 내가 작성한 댓글에는 글번호와 댓글번호 정보가 들어있습니다.

ex. www.dogdrip.net/$글번호?comment_srl=$댓글번호#comment_$댓글번호 

 

여기서 글번호와 댓글번호만 가공하여 보관 후 글을 삭제하는 주소에 삽입해 보내주면 끝입니다.

ex. www.dogdrip.net/index.php?document_srl=$글번호&mid=userdog&act=dispBoardDeleteComment&comment_srl=$댓글번호&cpage=1 

 

위 주소로 글번호와 댓글번호를 삽입하여 보내주면 글 삭제 확인창이 나오고 해당 창에 확인반응을 해주면 글삭제가 완료됩니다.

 

이제 내가 작성한 모든 댓글을 모두 수집한 후 필요한 정보만 가공해서 저장해놓습니다.

모든 댓글 수집이 끝나면 순차적으로 삭제URL에 글번호와 댓글번호를 삽입해서 날려주는걸 반복합니다.

 

다만 너무 빠른 속도로 하게되면 서버에 부담이 가고 접속이 차단 될 수 있으니, 수집할 때와 삭제할 때 딜레이를 주어 과부하를 막아줍니다. 흰 화면이 뜨고 접속이 차단된다면 4~5초 정도로 해주시면 될 것 같습니다.

 

그래도 삭제되지 않는 댓글들이 있는데, 그것은 아마 원본 글이 신고되어 보관된 상태로, 해당 페이지에 진입할 권한이 없기에 그런 것이기 때문에 걱정 안하셔도 됩니다.

 

그럼 즐거운 커뮤하세요. ^^

 

※해당 글은 공익적 목적으로 작성되었으며, 문제시 삭제 예정입니다.

 

#개드립 지우개 #개드립 클리너

'Development' 카테고리의 다른 글

[템퍼몽키] 개드립 차단메모  (0) 2025.06.29
[템퍼몽키] 개드립 댓글 클리너 v02  (0) 2025.06.29
목차