본문 바로가기
AI

127. 코딩 몰라도 가능한 ChatGPT 활용법: 자동 언팔로우 프로그램 만들기

by 구구 구구 2024. 5. 30.
반응형

7500명 제한이 뭐냐, dall-e

 

 

00. 발단 : 저는 현재 SNS로 Threads를 이용하고 있습니다.

다 좋은데 하나 문제가, Threads는 내가 팔로우 할 수 있는 계정 숫자에 제한이 있더라구요, 약 7500명. 제가 비공개로 지인끼리 SNS를 쓸 때와는 달리, 딱히 생각 없이 오는 팔로우를 다 받았습니다, 고양이 계정도 마구 팔로우 하고.. 그러다 보니 금새 7500명에 도달했고 더 이상 팔로우 버튼을 눌러도 정상 작동하지 않더라구요. 아무래도 팔로잉 계정 정리를 좀 해야겠다는 생각이 뒤늦게 들었습니다. 좋은 정보글을 올려주시는 분들은 늘어나는데 제가 팔로우 할 수가 없더라구요. 근데 7500개를 언제 다 보나 하고 차일피일 미뤘습니다 사실.

 

그러던 어느 날, 좋은 팁을 알게 되었습니다. Meta에서 내 Threads 계정 정보를 이메일로 받아볼 수 있었습니다. 이 정보에는 내가 팔로우한 사람과 나를 팔로우한 사람이 포함되어 있었습니다. 두 가지 정보를 Excel 파일로 정리해서 비교해보니, 나와 맞팔 관계가 아닌 사람을 추려낼 수 있었습니다. 그래서 일단 맞팔이 아닌 계정을 정리해 본 결과, 약 2000개로 확인되었습니다. 7500개 계정 확인기보단 당연히 낫지만! 약 2000개도! 이걸 어느 세월에 봐요... 하루에 계정 20개씩 확인을 해도 100일인데...

 

01. 전개 : 그러다 지피터스에서 아주 좋은 정보글을 봤습니다.

지피터스에서 정확히 어떤 글이었는지는 찾지 못했습니다만, 대강 저와 비슷한 상황이었던 것으로 기억합니다.

[ 1) 반복 작업 싫다, 2) 근데 코딩은 잘 모른다, 3) Claude3이 그렇게 똑똑하다던데 ]

정말 열심히 찾았는데 기억이 잘 안 납니다... 감사합니다 해당 글 작성자님...

 

저도 위에서 말한 대로 2000명 가량의 '언팔 계정 리스트'까진 만들었지만, 이걸 일일히 보는게 너무 귀찮았거든요..

 

그 분의 경우 Claude에게 상황설명을 하니 Claude가 알맞은 Python 코드를 대답해 주고, 이걸 직접 테스트 해보고, 또 다시 Claude에게 수정을 부탁하며 프로그램을 만드신 것 같았습니다. 아 나도 이렇게 하면 되겠다.

 

전 이때까지만 해도, 제가 원하는 게 그냥 정말 단순하게, PC용 앱플레이어에서 자동 클릭 매크로 만드는 수준이라고 생각했습니다. '언팔 계정 리스트.txt' 에서 계정 하나씩 복사 붙여넣기 하고 언팔로우 버튼 누르면 되는 것 아닌가? 

 

1) Claude3을 먼저 켜 봤습니다.

뭔지 모르겠는데 맞는거 같아요. 맞겠죠 뭐.

 

직접 나와 맞팔관계인지 알아보는 방법을 Claude에게 설명해줬습니다. 대충 알아들은 것 같아요!

이 밑으로는 이미지 저장 후 가져오기가 귀찮아서(..) 말로 쓰겠습니다..

 

나:
음 그래서 네 도움이 필요해.
[웹 스크래핑을 통해 내가 팔로우한 모든 계정들의 프로필 페이지를 열어보고, "팔로워 삭제" 옵션이 없는 경우 그 계정을 언팔로우하는 식으로 프로그램을 작성하면 될 것 같습니다. 이 아이디어로 프로그램을 만들어보시는 것이 좋을 것 같네요.]

이를 바탕으로 프로그램을 만들고 싶어. 만드는 방법을 10단계로 알려줄래?

Claude:
물론입니다.
웹 스크래핑을 이용하여 맞팔이 아닌 계정을 자동으로 언팔로우하는 프로그램을 만드는 과정을 10단계로 나누어 설명드리겠습니다.

1. 프로그래밍 언어와 웹 스크래핑 라이브러리 선택
- Python 언어와 requests, beautifulsoup4 라이브러리를 사용하는 것이 일반적입니다.

2. Threads.net 로그인 과정 분석 및 코딩
- 웹 브라우저 개발자 도구를 이용하여 로그인 과정을 분석합니다.
- 로그인 폼 데이터, 쿠키, 세션 등을 처리하는 코드를 작성합니다.

3. 내가 팔로우한 계정 목록 가져오기
- 팔로잉 페이지의 HTML 구조를 분석합니다.
- 웹 스크래핑을 통해 팔로잉 목록의 계정 ID를 추출하는 코드를 작성합니다.

4. 계정 프로필 페이지 접근 및 분석
- 추출한 계정 ID를 이용하여 각 프로필 페이지에 접근합니다.
- 프로필 페이지의 HTML 구조를 분석하여 "팔로워 삭제" 옵션 존재 여부를 확인할 수 있는 위치를 찾습니다.

5. "팔로워 삭제" 옵션 존재 여부 확인
- 프로필 페이지의 HTML에서 "팔로워 삭제" 옵션이 있는지 확인하는 코드를 작성합니다.

6. 언팔로우 기능 구현
- "팔로워 삭제" 옵션이 없는 경우 언팔로우 처리를 하는 코드를 작성합니다.
- 언팔로우 요청을 보내고 응답을 확인하는 로직을 구현합니다.

7. 반복 작업 및 예외 처리
- 전체 팔로잉 목록을 반복하며 5, 6단계를 수행하는 코드를 작성합니다.
- 예외 상황(로그인 실패, 네트워크 오류 등)에 대한 처리를 추가합니다.

8. 프로그램 실행 및 테스트
- 작성한 프로그램을 실행하고 테스트 계정으로 동작을 확인합니다.
- 필요한 경우 코드를 수정하고 재테스트합니다.

9. 로그 및 결과 저장
- 프로그램 실행 로그를 파일에 기록하는 기능을 추가합니다.
- 언팔로우한 계정 목록을 파일로 저장하는 기능을 추가합니다.

10. 예약 작업 설정 (선택 사항)
- 프로그램을 주기적으로 실행하도록 예약 작업을 설정할 수 있습니다.
- Windows 작업 스케줄러나 Linux cron 작업을 활용할 수 있습니다.

이렇게 단계적으로 진행하면 웹 스크래핑을 통해 맞팔이 아닌 계정을 자동으로 언팔로우하는 프로그램을 만들 수 있습니다. 각 단계에서 구체적인 코드 작성에 어려움이 있다면 추가 질문을 해주시기 바랍니다.

 

맞는 것 같아요..? 아마도..?

 

사실 제가 코딩은 약 10년 전에 대학교 필수교양으로 대충 들은게 다입니다. hello world 나오게 하기, 카운트다운하기, 트리 그리기 이런 것 했던 거 같은데, claude는 뭔가 어려운 말을 하고 있지만.. 대충 과정은 맞는 거 같아요..?

원래 무식해야 용감하다고 하잖아요 ㅎㅎ

 

문제는 claude 무료판은 메세지 갯수가 좀 많이 적더라구요.

그래서 그대로 chatgpt로 옮겨갔습니다. gpt-4 사용했습니다. gpt-4o가 안 나왔을 때 였어요.

 

02. 절정

1) 제가 Python이 뭔지는 아는데 Selenium을 몰라요.

GPT-4:
안녕하세요! 프로그램 만들기에 관심이 있으시다니 정말 반갑습니다. 말씀하신 것처럼 단순 반복 작업을 자동화하는 매크로를 만드는 것은 효율적인 방법 중 하나입니다. 여기서 필요한 프로그램은 웹 자동화 도구를 사용해서 만들 수 있어요. 예를 들어 Python 언어로 Selenium이나 Puppeteer 같은 도구를 사용할 수 있습니다.

일단 기본적인 접근 방식을 설명드리겠습니다:
1. 환경 설정: Python과 Selenium을 설치하고, 필요한 웹드라이버(크롬 드라이버 등)를 설치합니다.
2. 로그인 자동화: 프로그램이 웹사이트에 자동으로 로그인할 수 있도록 만듭니다.
3. 팔로우 목록 수집: 자신의 팔로우 목록과 팔로워 목록을 수집합니다.
4. 비교 및 해제: 자신이 팔로우하고 있는데 상대방이 팔로우하지 않는 계정을 찾아 팔로우를 해제합니다.

간단한 코드 예제를 보여드릴게요. 아래는 Python과 Selenium을 사용해 로그인하는 예제 코드입니다.
실제로 동작하기 위해서는 웹사이트에 맞게 요소를 선택하고, 사용자 이름과 비밀번호를 입력해야 합니다.
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import time

# 웹드라이버 설정
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()))
driver.get('https://threads.net/login')

# 로그인 과정
username = driver.find_element(By.ID, 'login_id')
username.send_keys('your_username')
password = driver.find_element(By.ID, 'password')
password.send_keys('your_password')
login_button = driver.find_element(By.ID, 'login_button')
login_button.click()

# 팔로잉 목록 접근
driver.get('https://threads.net/your_profile/following')
time.sleep(2)

# 팔로잉 목록에서 사용자 이름 추출 및 프로필 방문
followings = driver.find_elements(By.CSS_SELECTOR, '.user-name-class')
for user in followings:
    user_name = user.text
    driver.get(f'https://threads.net/{user_name}')
    time.sleep(2)
    
    # '팔로워 삭제' 버튼의 유무 확인
    try:
        more_options = driver.find_element(By.CSS_SELECTOR, 'img.profile-menu')
        more_options.click()
        unfollow_button = driver.find_element(By.XPATH, '//button[text()="팔로워 삭제"]')
        unfollow_button.click()  # 상대방이 나를 팔로우하지 않는 경우, 팔로우 해제
        print(f"Unfollowed {user_name} because they do not follow back.")
    except:
        print(f"{user_name} follows back or button not found.")​


이 스크립트는 각 사용자의 프로필 페이지로 이동하여 '팔로워 삭제' 버튼을 찾고, 버튼이 존재할 경우 클릭하여 팔로우를 해제합니다. 이때, 예외 처리를 통해 버튼이 없는 경우 (즉, 상대방이 당신을 팔로우하지 않는 경우) 언팔로우를 진행합니다.

실제 웹사이트의 구조에 따라 CSS 선택자 및 XPath를 조정할 필요가 있으므로 개발자 도구를 활용하여 정확한 요소를 확인하고 코드를 수정하세요. 또한, 자동화 작업은 웹사이트의 이용 약관을 확인한 후 적법하게 사용해야 합니다. 자동화 도구 사용이 계정 정지나 다른 제제를 초래할 수 있으므로 주의 깊게 접근하시기 바랍니다.

 

무서운 말도 하고 알수없는 말도 하고,

10년 전 기억을 잘 떠올려서 for라던지, try-except라던지, 뭐 그런게 있던 것만 기억이 납니다.

 

나:
이를 바탕으로 프로그램을 만들고 싶어. 만드는 방법을 10단계로 알려줄래?

1. 프로그래밍 언어와 웹 스크래핑 라이브러리 선택: Python을 아주 약간 배운 적 있어. 웹 스크래핑 라이브러리는 뭔 지 잘 모르겠어.
2. Threads.net 로그인 과정 분석 및 코딩: 어차피 내 계정이 이미 로그인 된 상태니까 굳이 이 과정이 필요할까?

GPT-4:
프로젝트를 시작하는 좋은 방향을 잡으셨네요! 자동화된 언팔로우 프로그램을 만드는 과정을 10단계로 나눠 설명드리겠습니다. Python을 사용하시길 원하신다고 하셨으니, Selenium 같은 웹 자동화 라이브러리를 사용해 보겠습니다. 각 단계별로 필요한 내용을 설명드리겠습니다:

1. 프로그래밍 언어와 웹 스크래핑 라이브러리 선택 언어: Python 라이브러리: Selenium (웹 브라우저를 자동으로 조작할 수 있어 사용자 인터페이스가 필요한 웹 스크래핑에 적합)

2. Threads.net 로그인 과정 분석 및 코딩 로그인 필요성: 스크립트가 웹 사이트에 자동으로 로그인할 수 있도록 하는 것이 중요합니다. 이미 로그인된 세션을 사용하는 것은 일반적으로 브라우저 환경에 종속적이며, 자동화 스크립트에서 재사용하기 어렵습니다.

3. Selenium 설치 및 환경 설정 Python 환경에 Selenium과 웹드라이버(ChromeDriver 등) 설치
pip install selenium​


( 사족 1. 어디다 입력하는거냐고 물어봤더니, gpt-4가 '명령 프롬프트'에 쓰는 거라고 알려줬습니다 )
( 사족 2. ChromDriver가 뭐냐고 물어봤더니, gpt-4가 이것도 친절하게 다 설명해 줬습니다.. 설치하면 됩니다.. )

4. 로그인 자동화 스크립트 작성
Threads.net에 로그인하는 자동화 코드 작성

5. 팔로잉 목록 수집
로그인 후, 팔로잉 목록 페이지로 이동
팔로잉하는 모든 사용자의 프로필 URL 수집

6. 각 프로필 페이지 접근
수집한 프로필 URL을 순회하면서 각 페이지로 이동

7. 팔로워 삭제 버튼 유무 확인
페이지에서 "팔로워 삭제" 버튼의 유무 확인

8. 조건에 따른 팔로우 해제
"팔로워 삭제" 버튼이 없는 경우, 해당 사용자를 언팔로우

9. 로깅 및 예외 처리
각 단계에서 발생할 수 있는 예외 처리 및 언팔로우 과정 로깅

10. 스크립트 테스트 및 최종 실행
작성된 스크립트의 테스트를 진행하고 문제가 없는지 확인 후 최종 실행

이러한 단계로 프로그램을 진행하시면 됩니다. 각 단계마다 필요한 코드 블록이나 추가적인 설명이 필요하시면 알려주세요. 각 단계를 성공적으로 완료하실 수 있도록 구체적인 도움을 드릴 수 있습니다!

 

 

일단 저 위에, gpt-4가 알려준 예시 코드를 그대로 복사 붙여넣기 해서 .py 파일을 만든 후 실행했습니다.

뭔가 되는거 같기도 한데..?

 

2) Thread 웹페이지가 자동으로 켜지긴 하는데 로그인이 안 된다.

 

Thread 로그인 웹페이지가 자동으로 켜지긴 하는데, 그러고 나서 에러가 바로 나더라구요.

나:
그럼 여기서 어떤 부분을 수정해야 해? 초록색 부분은 다 내가 내 상황에 맞춰서 수정해야 하는거야?

GPT-4:
네, 초록색으로 표시된 부분은 당신의 개인 정보 및 Threads.net 웹사이트에 특정적인 요소를 반영하여 수정해야 하는 부분들입니다. 각 요소에 맞게 수정하는 방법을 상세히 설명드리겠습니다.

웹사이트 URL: driver.get('https://threads.net/login'): 이 부분은 로그인 페이지의 정확한 URL로 수정해야 합니다. 만약 URL이 https://threads.net/login이 맞다면 그대로 두시면 됩니다.

HTML 요소 식별자: By.ID, 'login-id', By.ID, 'password-id', By.ID, 'login-button-id': 이 부분들은 Threads.net 로그인 페이지의 HTML 요소들의 ID입니다. 이 ID들은 실제 웹사이트의 입력 폼과 로그인 버튼에 할당된 실제 ID로 변경해야 합니다. 이 ID들은 웹 페이지의 HTML 코드를 검사(보통 웹 브라우저에서 오른쪽 클릭 후 "검사" 선택)하여 찾을 수 있습니다.

사용자 정보: 'your_username', 'your_password': 여기에는 당신의 Threads.net 계정의 사용자 이름과 비밀번호를 입력합니다. 이는 문자열 형태로 입력되며, 직접 코드에 적어주셔야 합니다.

예시 코드:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

# WebDriver 설정
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)

# Threads.net 로그인 페이지로 이동
driver.get('https://threads.net/login')

# 로그인 정보 입력 및 제출
username = driver.find_element(By.ID, 'actual-login-id')  # 예: 'user-name'
username.send_keys('your_actual_username')
password = driver.find_element(By.ID, 'actual-password-id')  # 예: 'user-password'
password.send_keys('your_actual_password')
login_button = driver.find_element(By.ID, 'actual-login-button-id')  # 예: 'submit'
login_button.click()

# 팔로잉 목록 페이지로 이동
driver.get('https://threads.net/your_profile/following')

# 팔로잉 목록 수집 및 언팔로우 처리
following_links = driver.find_elements(By.CSS_SELECTOR, 'a.profile-link')
for link in following_links:
    driver.get(link)
    try:
        unfollow_button = driver.find_element(By.XPATH, '//button[text()="언팔로우"]')
        unfollow_button.click()
    except:
        print("Already unfollowed or button not found")

# 드라이버 종료
driver.quit()​


위 코드를 사용하기 전에, 실제 HTML 요소의 ID와 텍스트 값을 정확히 확인하고 코드에 반영해 주세요. 또한, 자동화 스크립트를 사용할 때는 계정의 보안을 항상 유념하시고, 비밀번호나 중요한 정보는 안전하게 관리하세요.

 

그렇구나, 초록색 부분은 개인적으로 알아서 적어야 했구나..

# 로그인 정보 입력 및 제출
username = driver.find_element(By.ID, 'actual-login-id')  # 예: 'user-name'
username.send_keys('your_actual_username')
password = driver.find_element(By.ID, 'actual-password-id')  # 예: 'user-password'
password.send_keys('your_actual_password')
login_button = driver.find_element(By.ID, 'actual-login-button-id')  # 예: 'submit'
login_button.click()

 

대충 username이라는 것에 내 아이디를, password에 내 비밀번호를 넣고,

selenium이라는 애가 알아서 아이디, 비밀번호 창에 알아서 이 값들을 넣고 로그인 버튼을 누른다는 것 같아요.

다시 예시코드를 이리저리 수정해 보았습니다.

 

근데 안 되더라구요.

나:
이번엔 뭐가 문젤까 ( 실제로는 스크린샷 캡쳐해서 gpt-4에 직접 올렸습니다 )

GPT-4:
스크린샷을 확인해보니, 코드 실행 중에 "NoSuchElementException" 에러가 발생했습니다. 이 에러는 지정된 요소를 찾을 수 없을 때 발생합니다. 에러 메시지는 사용자 이름 입력 필드를 찾는 데 실패했음을 나타내고 있습니다. 이는 ... (생략)

 

사실 지정된 요소를 어떻게 찾느냐로, 하루정도 css selector가 어쩌구 xpath가 어쩌구 뭔가를 들었습니다.

 

그런데 이 당시에는 이것들을 정말로 못 알아듣겠더라구요.

그래서 아이디랑 비밀번호 넣고 로그인 버튼 누르기는 그냥 제가 직접 한다고 했습니다.

 

나:
아니면 지금 threads.net/login 페이지까지는 들어가지니까,
30초의 대기시간을 주고, 내가 직접 그 30초동안 아이디와 비밀번호를 입력하고 로그인 버튼을 누르는 건 어때.

GPT-4:
직접 로그인 과정을 수동으로 처리하는 것은 스크립트를 테스트하거나 개발하는 초기 단계에서 유용한 방법이 될 수 있습니다. 이 방식은 특히 자동화 프로세스에서 로그인 매커니즘을 디버깅할 때 좋은 임시 해결책이 될 수 있습니다. 또한, 자동화 스크립트가 웹사이트의 보안 조치로 인해 로그인을 수행하지 못하는 경우에도 유용하게 사용할 수 있습니다.

수동 로그인을 위한 Selenium 코드 예시:
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import time  # 시간 대기를 위한 모듈

# WebDriver 설정
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)

# Threads.net 로그인 페이지로 이동
driver.get('https://threads.net/login')

# 30초 동안 사용자가 수동으로 로그인할 수 있도록 대기
time.sleep(30)

# 이후 스크립트를 통해 필요한 작업 수행
# 예: 특정 페이지로 이동 또는 특정 데이터 추출
# 예: driver.get('https://threads.net/some_page')

# 작업 완료 후 드라이버 종료
driver.quit()​

이 방법의 장단점:

1. 장점:
- 간단한 디버깅: 로그인 매커니즘이 복잡하거나 추가 보안 조치가 있을 때 스크립트를 간단히 테스트하고 진행할 수 있습니다.
- 개발 단계에서 유연성 제공: 초기 개발 단계에서 스크립트의 다른 부분이 정상적으로 작동하는지 확인할 수 있습니다.

2. 단점:
- 자동화의 목적 상실: 자동화의 주된 목적은 인간의 개입 없이 작업을 수행하는 것입니다. 이 방법을 사용하면 자동화의 이점을 일부 상실하게 됩니다.
- 비효율적: 매번 수동으로 로그인을 해야 하므로, 반복적인 작업에는 적합하지 않습니다. 이 방법을 사용하여 원하는 결과를 얻을 수 있으면, 나중에 로그인 과정을 자동화할 방법을 추가로 모색하는 것이 좋습니다. 예를 들어, 로그인 토큰을 사용하거나, 쿠키를 활용하여 세션을 유지하는 방법 등이 있습니다. 이렇게 하면 전체 프로세스의 자동화를 완성할 수 있습니다.

 

그냥 프로그램아 나한테 30초를 줘, 알아서 내가 로그인 하고 검색 페이지까지 열어줄게,

비효율은 뭐... 뭐라하는지 잘 모르겠고...

 

 

3) 근데 생각해보니 로그인도 힘든 애가 이걸 일일히 눌러볼 수 있을지

스크롤 내려가면서 계정을 확인할 수 있겠냐고

 

좀 걱정이 되어서 다시 물어봤습니다.

나:
그리고 지금 로그인 이후의 python 코드가 이렇게 되어 있는데,
이러면 최초 1번만 수행하고 끝나는 거 아니야?

# 팔로잉 목록 페이지로 이동
driver.get('https://threads.net/your_profile/following')

# 팔로잉 목록 수집 및 언팔로우 처리
following_links = driver.find_elements(By.CSS_SELECTOR, 'a.profile-link')
for link in following_links:
    driver.get(link)
    try:
        unfollow_button = driver.find_element(By.XPATH, '//button[text()="언팔로우"]')
        unfollow_button.click()
    except:
        print("Already unfollowed or button not found")

# 드라이버 종료
driver.quit()


왜냐하면 내가 현재 Follow한 사람 숫자가 약 7500명이 넘어.
이중에서 나를 Follow하지 않는 사람을 걸러내는 작업이 되야 하잖아.
그러면 적어도 약 7500번의 반복을 해야 하는데, 뭔가 잘못된거 아니야?

GPT-4:
맞습니다, 제시해주신 코드는 현재 구조에서 팔로잉 목록 페이지로 한 번 이동하여 페이지에 나타난 모든 링크에 대해서만 반복을 수행하고, 각 링크에 대해 한 번씩만 접근하여 '언팔로우' 버튼을 클릭하는 방식입니다. 이렇게 되면 전체 팔로잉 목록 중 현재 페이지에 보이는 목록에 대해서만 작업을 수행하고 종료됩니다. 7500명의 팔로잉 목록을 처리하려면, 페이지를 넘기면서 반복적으로 목록을 수집하고 처리하는 로직이 필요합니다.

나:
그럼 생각을 잠깐 해보자.

어차피 나만 쓸 프로그램이잖아.
프로그램이 일일히 약 7500명을 다 검사하게 하지 말자.

내가 나와 '맞팔'이 아닌 계정만 찾아서, 이걸 메모장에 그 계정만 적어서 txt 파일로 줄 수 있어. 
그럼 그 계정들만 검색해서 언팔로우 하면 더 간단하겠지?

0. 내가 너한테 언팔로우 할 계정들의 목록(txt 파일)을 준다.
1. python 코드에서, threads.net/login을 열고, 60초를 기다려.
2. 내가 직접 60초 동안 직접 아이디와 비밀번호를 입력하고 로그인 버튼을 눌러.
3. 내가 직접 계정 검색 페이지까지 들어가 줄 수 있어.
4. 그럼 60초가 지난 후, 계정 검색 페이지부터 프로그램이 자동 작업을 시작해.
5. 자동 작업1: txt파일에서 목록의 첫 번째 계정을 복사 붙여넣기 해서 찾아낸 다음 언팔로우한다.
6. 자동 작업2: 언팔로우 했으면, 다시 txt파일로 돌아가 두 번째 계정을 복사 붙여넣기 해서 찾아낸 다음 언팔로우한다.
7. 자동 작업 3: 이 작업을 목록 n번째 계정을 언팔로우할때까지 반복한다.
8. 마지막 n번째 작업이 끝나면 프로그램을 종료한다

어때?

GPT-4:
지금 말씀하신 방법은 특정 부분에서 사용자의 개입을 통해 보안 기능을 우회하고, 그 이후에 자동화를 진행하는 혼합 접근 방식을 사용하는 것입니다. 이 방식은 프로그램을 통한 대량의 언팔로우 과정을 간소화하면서도 로그인과 초기 단계에서 발생할 수 있는 보안 문제를 효과적으로 회피할 수 있습니다. 사용자가 직접 로그인하고 초기 설정을 수행한 후에 자동화 스크립트가 나머지 작업을 처리하는 방식은 특히 개인적으로 사용하기에 적합합니다.

Python 코드 구현 제안
1. 텍스트 파일 읽기: 언팔로우할 계정 목록이 저장된 텍스트 파일을 읽어서 리스트에 저장합니다.
2. 사용자 로그인 대기: 사용자가 로그인하고 필요한 페이지에 도달할 때까지 기다립니다.
3. 자동 언팔로우 수행: 텍스트 파일에 있는 계정 목록을 순차적으로 검색하고, 각 계정에 대해 언팔로우 작업을 수행합니다.

from selenium import webdriver
import time

# 드라이버 설정
driver = webdriver.Chrome()

# 파일에서 계정 목록 읽기
with open('unfollow_list.txt', 'r') as file:
    accounts = file.readlines()

# 로그인 페이지로 이동
driver.get('https://threads.net/login')

# 사용자가 로그인하고 계정 검색 페이지에 접근할 시간을 주기
time.sleep(60)  # 60초 동안 대기

# 계정 목록을 순회하며 언팔로우
for account in accounts:
    account = account.strip()  # 줄바꿈 문자 제거
    # 계정 검색 페이지에 계정 이름 입력
    search_input = driver.find_element_by_css_selector('input.search')
    search_input.clear()
    search_input.send_keys(account)
    search_input.send_keys(Keys.ENTER)

    time.sleep(5)  # 검색 결과 로드 시간 대기

    # 언팔로우 버튼 클릭
    try:
        unfollow_button = driver.find_element_by_xpath('//button[text()="언팔로우"]')
        unfollow_button.click()
        print(f"Unfollowed {account}")
    except:
        print(f"Could not unfollow {account} or button not found")

# 모든 작업 완료 후 드라이버 종료
driver.quit()


나:

# 파일에서 계정 목록 읽기
with open('unfollow_list.txt', 'r') as file:
    accounts = file.readlines()


그럼 위에 코드를 이용한다면,
내가 '언팔 계정 리스트'를 메모장에 옮겨적고 'unfollow_list.txt' 라고 저장만 하면,
내가 특정 경로를 지정하지 않아도, 컴퓨터 내 저장장치에 unfollow_list.txt를 자동으로 열어서
그 안의 정보를 한 줄 한 줄 차례대로 읽을 수 있어?

# 계정 목록을 순회하며 언팔로우
for account in accounts:
    account = account.strip()  # 줄바꿈 문자 제거
    # 계정 검색 페이지에 계정 이름 입력
    search_input = driver.find_element_by_css_selector('input.search')
    search_input.clear()
    search_input.send_keys(account)
    search_input.send_keys(Keys.ENTER)

    time.sleep(5)  # 검색 결과 로드 시간 대기


GPT-4:
네, 그렇습니다. 하지만 open('unfollow_list.txt', 'r') 부분에서 unfollow_list.txt 파일을 열 때 파일의 위치는 현재 파이썬 스크립트가 실행되는 디렉토리(작업 디렉토리)를 기준으로 합니다. 
즉, 이 코드가 정상적으로 작동하려면 unfollow_list.txt 파일이 파이썬 스크립트와 같은 폴더에 있어야 합니다.

 

그래서 !

 

.py랑 .txt랑 같은 폴더에 넣어줬습니다.

계정은 대충 저렇게 한줄 한줄 써 놨습니다.

 

4) 근데 계속해서 NoSuchElementException이 나옵니다.

 

얘가 unfollow_list.txt에서 각 계정을 읽어오긴 하는데

아까 전 로그인 버튼 못 찾을 때랑 비슷하게, 이번에는 언팔로우 버튼을 못 찾는 것 같더라구요.

나:
(스크린샷) 안되잖아

GPT-4:
에러 로그를 확인해 보니 "NoSuchElementException"이 발생하고 있어, 여전히 Selenium 스크립트가 요소를 찾지 못하고 있습니다. 이 문제는 여러 원인으로 발생할 수 있지만, 가장 흔한 원인은 다음과 같습니다:
1. 요소의 로드 시간: 페이지의 요소가 로드되기 전에 Selenium이 요소를 찾으려고 시도할 수 있습니다. 페이지가 완전히 로드될 때까지 기다리도록 스크립트에 명시적인 대기 로직을 추가해야 할 수 있습니다.
2. 잘못된 선택자: 선택자가 페이지의 요소와 정확히 일치하지 않을 경우 발생합니다. CSS 선택자를 다시 확인해야 합니다.
3. 동적 요소: 페이지에 자바스크립트에 의해 동적으로 로드되는 요소가 있을 수 있습니다. 이 경우, 요소가 DOM에 완전히 로드되고 나타날 때까지 대기해야 합니다.

나:
(스크린샷) 시간 더 늘려도 안되잖아

GPT-4:
요소의 선택자가 정확하게 설정되어 있고, 요소가 페이지에 존재하는지 다시 한 번 확인하세요. 필요하면 개발자 도구를 사용하여 페이지의 요소를 다시 검사하고, 사용 중인 선택자가 실제 요소와 일치하는지 확인해 보세요.

정확한 선택자 찾기
1. 개발자 도구 사용: 다시 한 번 개발자 도구를 열고, 로그인 버튼을 직접 클릭하거나 탐색하여 그 속성을 확인합니다.
2. 다른 속성으로 선택자 구성: 버튼에 고유한 class가 있거나, 특정 텍스트를 포함하고 있다면, 그 속성을 기반으로 선택자를 구성할 수 있습니다.
3. XPath로 시도: CSS 선택자로 요소를 찾는 데 어려움이 있다면, XPath를 사용해 볼 수 있습니다. 예를 들어, 버튼의 텍스트나 다른 특징을 기반으로 한 XPath를 사용할 수 있습니다

 

개발자 도구.. CSS.. XPath.. 결국 제가 이걸 이해해야 하나 봅니다..

 

개발자 도구는, 왼쪽 클릭 후 맨 밑에 '검사'를 누르면 된다고 합니다..

 

무시무시한게 나왔습니다. 왜 일이 이렇게 커졌나..? 

그만 해야 하나.. ? 게임 매크로처럼 대충 찍고 누르고 하는거 아니였나 ..?

보통 이런 창은 막 엄청난 사람들만 보는 거 아닌가 ..? 그만할까 ..?

 

근데 그만하기에는 제가 하루 이상 날려서 좀 아까웠습니다.

 

 

어피치 손가락 끝 위치처럼, 한 줄 한 줄 위에 커서를 대 보니까

그 줄에 써 있는 <...>이것에 대응하는 부분이, 왼쪽 실제 화면에 파랗게 표시가 되는 거 같아요.

 

해당 줄을 자세히 보면 중간에 "..." 이라고 생략 된 곳이 있습니다. 

그걸 클릭해보면 다음과 같이 더 세부적으로 나오는 모양입니다.

 

 

차근히 "..."으로 생략된 부분을 열어서 파고들어보니,

드디어 [팔로잉] 버튼을 찾았습니다.

 

 

CSS selector나 XPath가 정확히 뭔지는 모르겠는데, 대충 웹 사이트 요소의 주소같은건가 봐요.

찾아낸 <...> 부분에 왼쪽 클릭을 하면 selector 복사 혹은 XPath 복사가 있습니다. 

 # 언팔로우 버튼 클릭
    try:
        unfollow_button = driver.find_element_by_xpath('//button[text()="언팔로우"]')
        unfollow_button.click()
        print(f"Unfollowed {account}")
    except:
        print(f"Could not unfollow {account} or button not found")

 

gpt-4가 준 코드에서 by_xpath(초록색글씨)이 부분에

xpath든 selector든 복사 붙여넣기 해서, 써 넣으면 되겠죠? 제발 !!!

 

5) 문제가 좀 더 있었습니다.

 

1. 언팔로우를 위한 [팔로잉] 버튼 위치만 찾을게 아니었습니다.

- 일단 검색 창을 클릭해야 한다.

- 그 다음 unfollow_list.txt에서 읽어온 계정명을 입력해야 한다.

- 로딩될때까지 잠깐 기다린다.

- 검색되어 나온 첫 번째 계정명과 unfollow_list.txt에서 읽어온 계정명이 동일한지 확인한다.

- 동일하면 [팔로잉] 버튼을 눌러서 언팔로우 수행, 동일하지 않으면 건너뛰기.

- 검색 창에 입력해놨던 계정명을 지운다.

- 대충 2000번 반복한다

즉, 검색 창 위치, 검색되어 나온 첫 번째 계정 이름 위치, [팔로잉] 버튼 위치, 지우기 버튼 위치를 전부 알아야 한다.

 

2. 사실 저렇게 해서, 분명히 값이 맞는 것 같은데도 NoSuchElementException가 계속 나오더라구요.

제 생각에는, 저 검색 창 자체가 내가 클릭하면 스르륵 나오고, 클릭하지 않으면 스르륵 들어가는(?) 것이어서가 아닐까..

즉, 저 모든 위치가 나타났다 사라졌다 할 때도 있고, selector나 xpath가 계속 변경될 수도 있다?

 

다시 gpt-4에게 물어봤습니다. 어차피 전 지금 아는게 없으니, 얘가 다 해야 하잖아요.

나:
그리고 너는 이제,
<div class="x6s0dn4 x78zum5"><span class="x6s0dn4 x78zum5 x1q0g3np"><div class=""><div><object type="nested/pressable"><a class="x1i10hfl xjbqb8w x1ejq31n xd10rxx x1sy0etr x17r0tee x972fbf xcfux6l x1qhh985 xm0m39n x9f619 x1ypdohk xt0psk2 xe8uvvx xdj266r x11i5rnm xat24cr x1mh8g0r xexx8yu x4uap5 x18d9i69 xkhd6sd x16tdsg8 x1hl2dhg xggy1nq x1a2a7pz xp07o12 xzmqwrg x1citr7e x1kdxza xt0b8zv" href="/@개인아이디" role="link" tabindex="0"><span class="x1lliihq x1plvlek xryxfnj x1n2onr6 x193iq5w xeuugli x1fj9vlw x13faqbe x1vvkbs x1s928wv xhkezso x1gmr53x x1cpjm7i x1fgarty x1943h6x x1i0vuye xjohtrz x1s688f xp07o12 x1yc453h" dir="auto" style="line-height: var(--base-line-clamp-line-height); --base-line-clamp-line-height: calc(1.4 * 1em);">개인아이디</span></a></object></div></div></span></div>
이걸 찾아낼 검색자를 나한테 알려줘야 한다.

GPT-4:
제가 본문에서 언급된 정보를 바탕으로 유추하자면, "개인아이디"는 특정 소셜 미디어 플랫폼의 사용자 이름일 가능성이 높습니다. 이 링크는 해당 사용자의 프로필 페이지로 이동하는 하이퍼링크 역할을 하며, 웹 페이지의 사용자와의 상호작용을 위해 설정된 요소 중 하나입니다. 이 링크를 통해 사용자는 "개인아이디"의 프로필을 볼 수 있으며, 여기에는 아마도 사진, 게시물, 팔로워 수, 팔로잉 수 등의 정보가 포함될 것입니다. 이와 같은 링크는 사용자들이 서로를 더 쉽게 찾고 소통할 수 있게 해주는 중요한 도구 중 하나입니다. 링크에 사용된 CSS 클래스와 구조는 웹 개발자가 스타일과 기능을 정의하기 위해 사용하는 것으로, 이러한 코드를 통해 웹 페이지의 시각적인 부분과 상호작용적인 부분을 제어합니다.

나:
근데 "개인아이디"는 unfollow_list.txt에서 읽어올 때마다 그때그때 바뀌는 이름이다.
그러니까 다른 검색자가 필요하다

GPT-4:
아하, 이해했습니다! “개인아이디”와 같이 동적으로 변하는 사용자 이름을 다룰 때는 일반적인 검색자보다는 더 구체적인 방식이 필요하겠네요. 웹 스크래핑이나 자동화된 브라우저 작업을 할 때는 클래스 이름, ID, 또는 특정 HTML 구조를 기반으로 하는 것이 일반적입니다. 예를 들어, CSS 클래스나 상위 요소를 활용하여 고유한 패턴을 식별할 수 있습니다.

정확한 선택자를 만들기 위해서는 해당 웹페이지의 전체적인 HTML 구조를 더 자세히 분석할 필요가 있습니다. 만약 정적인 페이지가 아니라면, 동적으로 로딩되는 컨텐츠에 접근하기 위해 JavaScript를 실행할 수 있는 환경에서 스크래핑해야 할 수도 있습니다.

나:
너한테 어떻게 하면 이 웹페이지의 전체적인 HTML 구조를 알려줄 수 있을까????

GPT-4:
Selenium을 사용하여 웹 페이지의 전체 HTML 구조를 확인하는 방법은 간단합니다. 페이지의 전체 HTML을 가져오려면, Selenium WebDriver를 통해 페이지를 로드한 후 page_source 속성을 사용하여 페이지의 소스 코드를 얻을 수 있습니다. 여기에 Python을 사용한 간단한 예시를 들어 보겠습니다:
from selenium import webdriver

# 웹드라이버 초기화 (Chrome을 예로 들었습니다)
driver = webdriver.Chrome()

# 원하는 웹 페이지로 이동
driver.get("https://www.example.com")

# 페이지의 전체 HTML 소스 가져오기
html_source = driver.page_source

# HTML 소스 출력
print(html_source)

# 드라이버 종료
driver.quit()​

 

이 스크립트는 지정된 URL의 웹 페이지를 불러오고, 해당 페이지의 전체 HTML 소스를 출력합니다. 웹드라이버는 여러분의 시스템에 설치된 브라우저에 따라 webdriver.Chrome(), webdriver.Firefox() 등으로 변경할 수 있습니다. 또한, WebDriver를 사용하기 전에 해당 브라우저의 드라이버를 시스템에 설치해야 합니다. 위 코드를 실행하면, 웹 페이지의 전체 HTML 구조를 볼 수 있고, 이를 통해 필요한 요소를 찾기 위한 적절한 선택자를 개발할 수 있습니다.

 

저 코드를 따로 .py로 저장해서 실행한 후,

뭔가 나온 것을 전부 다 복사 붙여넣기로 gpt-4에 써 넣으려니까, 말이 너무 길어서 안 된다고 하더라구요.

 

 

그래서 다시 txt 파일로 만들어 줬습니다. 그리고 gpt-4에게 전해줬습니다.

 

나:
자 내가 첨부한 remember.txt가 웹 페이지의 전체 HTML 구조야.

너는 그 중에서 나타났다 사라졌다 하는,
<div class="x6s0dn4 x78zum5"><span class="x6s0dn4 x78zum5 x1q0g3np"><div class=""><div><object type="nested/pressable"><a class="x1i10hfl xjbqb8w x1ejq31n xd10rxx x1sy0etr x17r0tee x972fbf xcfux6l x1qhh985 xm0m39n x9f619 x1ypdohk xt0psk2 xe8uvvx xdj266r x11i5rnm xat24cr x1mh8g0r xexx8yu x4uap5 x18d9i69 xkhd6sd x16tdsg8 x1hl2dhg xggy1nq x1a2a7pz xp07o12 xzmqwrg x1citr7e x1kdxza xt0b8zv" href="/@개인아이디" role="link" tabindex="0"><span class="x1lliihq x1plvlek xryxfnj x1n2onr6 x193iq5w xeuugli x1fj9vlw x13faqbe x1vvkbs x1s928wv xhkezso x1gmr53x x1cpjm7i x1fgarty x1943h6x x1i0vuye xjohtrz x1s688f xp07o12 x1yc453h" dir="auto" style="line-height: var(--base-line-clamp-line-height); --base-line-clamp-line-height: calc(1.4 * 1em);">개인아이디</span></a></object></div></div></span></div>
이 요소를 찾아내야 한다!!!!!!!!!!

근데 "개인아이디"같은 특정한 이름은 동적으로 바뀌기 때문에 소용이없다!!!

이거를 찾아낼 검색자를 만들어봐!!!!!!!!!!!!!!!!!!!!!!!!!

GPT-4:
그 웹페이지 HTML 내에서 동적으로 변하는 사용자 이름을 가진 링크 요소를 찾으려면 다음과 같이 CSS 선택자를 구성하여 검색할 수 있습니다:
div.x6s0dn4.x78zum5 > span.x6s0dn4.x78zum5.x1q0g3np > div > div > object[type="nested/pressable"] > a[href^="/@"]​


이 선택자는 클래스 x6s0dn4와 x78zum5를 포함하는 <div> 태그 내부에 위치한 <a> 태그를 타겟으로 하며, href 속성 값이 "/@"로 시작하는 요소를 찾습니다. 이 방식은 동적으로 변하는 사용자 이름을 가진 링크를 찾는데 유용하며, href의 기본 구조가 변하지 않는 한 유효합니다 .

 

이후로 NoSuchElementException이 나올 때마다, 계속 위의 방법으로 선택자인지 뭔지를 찾으라고 시켰습니다.

스크린샷 찍어서 보여주면 바로 알아듣는건 좋았습니다.

 

 

와중에 CSS selector를 사용하도록, 코드도 한번 다시 수정한 결과 !! 드디어 !!

 

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

import time

# 드라이버 설정
driver = webdriver.Chrome()

# 파일에서 계정 목록 읽기
with open('unfollow_list.txt', 'r') as file:
    accounts = file.readlines()

# 로그인 페이지로 이동
driver.get('https://threads.net/login')

# 사용자가 로그인하고 계정 검색 페이지에 접근할 시간을 주기
time.sleep(30)  # 60초 동안 대기
print(f"30 seconds")
time.sleep(20)
print(f"after 10 seconds, start")
time.sleep(10)

# 계정 목록을 순회하며 언팔로우
for account in accounts:
    account = account.strip()  # 줄바꿈 문자 제거

    
    # 검색 입력 필드 선택
    selector = "input.x1i10hfl.x9f619.xggy1nq.x1s07b3s.x1kdt53j.x1a2a7pz.x1ggkfyp.x972fbf.xcfux6l.x1qhh985.xm0m39n.xp07o12.x1i0vuye.xjohtrz.x5yr21d.x1yc453h.xh8yej3.x1e899rk.x1bn1fsv.xo6swyp.x1ad04t7.x1glnyev.x1ix68h3.x19gujb8[type='search']"
    search_input = driver.find_element(By.CSS_SELECTOR, selector)
    search_input.clear()
    
    search_input.send_keys(account)

    time.sleep(10)  # 검색 결과 로드 시간 대기
    print(f"after 5seconds, start")
    

    # 언팔로우 버튼 클릭
    try:

        # 검색 결과 텍스트와 입력한 계정 이름이 일치하는지 확인
        result_text = driver.find_element(By.CSS_SELECTOR, 'div.x6s0dn4.x78zum5 > span.x6s0dn4.x78zum5.x1q0g3np > div > div > object[type="nested/pressable"] > a[role="link"]').text

        if account == result_text:

            # 계정 이름과 검색 결과 텍스트가 완전히 같을 경우 실행되는 코드
            print("계정과 검색 결과가 정확히 일치합니다.")
            
            profile_link = driver.find_element(By.CSS_SELECTOR, 'div.x1i10hfl.xjbqb8w.x1ypdohk.xdl72j9.x2lah0s.xe8uvvx.xdj266r.x11i5rnm.xat24cr.x1mh8g0r.x2lwn1j.xexx8yu.x18d9i69.x1n2onr6.x16tdsg8.x1hl2dhg.xggy1nq.x1ja2u2z.x1t137rt.x1q0g3np.x1lku1pv.x1a2a7pz.x6s0dn4.x1a2cdl4.xnhgr82.x1qt0ttw.xgk8upj.x9f619.x3nfvp2.x1s688f.x90ne7k.xl56j7k.x193iq5w.x1swvt13.x1pi30zi.x12w9bfk.x1g2r6go.x11xpdln.xz4gly6.x87ps6o.xuxw1ft.x19kf12q.x6bh95i.x1re03b8.x1hvtcl2.x3ug3ww.x13fuv20.xu3j5b3.x1q0q8m5.x26u7qi.x178xt8z.xm81vs4.xso031l.xy80clv.xu0ddkp.xwsj4vy[role="button"][tabindex="0"]')
            profile_link.click()

            time.sleep(10)

            try:
                # CSS 선택자를 사용하여 요소 찾기
                re_check = driver.find_element(By.CSS_SELECTOR, 'div.x1i10hfl.xjbqb8w.xjqpnuy.xa49m3k.xqeqjp1.x2hbi6w.x13fuv20.xu3j5b3.x1q0q8m5.x26u7qi.x972fbf.xcfux6l.x1qhh985.xm0m39n.x9f619.x1ypdohk.x2lah0s.xe8uvvx.xdj266r.x11i5rnm.xat24cr.x1mh8g0r.x2lwn1j.xeuugli.xexx8yu.x4uap5.x18d9i69.xkhd6sd.x1n2onr6.x16tdsg8.x1hl2dhg.xggy1nq.x1ja2u2z.x1t137rt.x1o1ewxj.x3x9cwd.x13rtm0m.x1q0g3np.x87ps6o.x1lku1pv.x1a2a7pz.x6s0dn4.x78zum5.x1iyjqo2.x1dnml7z.xl56j7k.x18xmwgd.x12v9rci[role="button"]')

                # 요소가 있으면 클릭
                re_check.click()
                print("비공계 계정과의 팔로우가 삭제되었습니다")

                search_field = driver.find_element(By.CSS_SELECTOR, 'div.x78zum5 > div.x1i10hfl.x1qjc9v5.xjbqb8w.xjqpnuy.xa49m3k.xqeqjp1.x2hbi6w.x13fuv20.xu3j5b3.x1q0q8m5.x26u7qi.x972fbf.xcfux6l.x1qhh985.xm0m39n.x9f619.x1ypdohk.xdl72j9.x2lah0s.xe8uvvx.xdj266r.x11i5rnm.xat24cr.x1mh8g0r.x2lwn1j.xeuugli.xexx8yu.x4uap5.x18d9i69.xkhd6sd.x1n2onr6.x16tdsg8.x1hl2dhg.xggy1nq.x1ja2u2z.x1t137rt.x1o1ewxj.x3x9cwd.x1e5q0jg.x13rtm0m.x3nfvp2.x1q0g3np.x87ps6o.x1lku1pv.x1a2a7pz#typeahead-clear-button')
                search_field.click()

            except Exception:
                # 요소가 없으면 메시지 출력
                print("이상없습니다. 진행합니다")

                print(f"Unfollowed {account}")
            
                search_field = driver.find_element(By.CSS_SELECTOR, 'div.x78zum5 > div.x1i10hfl.x1qjc9v5.xjbqb8w.xjqpnuy.xa49m3k.xqeqjp1.x2hbi6w.x13fuv20.xu3j5b3.x1q0q8m5.x26u7qi.x972fbf.xcfux6l.x1qhh985.xm0m39n.x9f619.x1ypdohk.xdl72j9.x2lah0s.xe8uvvx.xdj266r.x11i5rnm.xat24cr.x1mh8g0r.x2lwn1j.xeuugli.xexx8yu.x4uap5.x18d9i69.xkhd6sd.x1n2onr6.x16tdsg8.x1hl2dhg.xggy1nq.x1ja2u2z.x1t137rt.x1o1ewxj.x3x9cwd.x1e5q0jg.x13rtm0m.x3nfvp2.x1q0g3np.x87ps6o.x1lku1pv.x1a2a7pz#typeahead-clear-button')
                search_field.click()

            
        else:
            print(f"Account {account} not found or has left Threads.")
            
            search_field = driver.find_element(By.CSS_SELECTOR, 'div.x78zum5 > div.x1i10hfl.x1qjc9v5.xjbqb8w.xjqpnuy.xa49m3k.xqeqjp1.x2hbi6w.x13fuv20.xu3j5b3.x1q0q8m5.x26u7qi.x972fbf.xcfux6l.x1qhh985.xm0m39n.x9f619.x1ypdohk.xdl72j9.x2lah0s.xe8uvvx.xdj266r.x11i5rnm.xat24cr.x1mh8g0r.x2lwn1j.xeuugli.xexx8yu.x4uap5.x18d9i69.xkhd6sd.x1n2onr6.x16tdsg8.x1hl2dhg.xggy1nq.x1ja2u2z.x1t137rt.x1o1ewxj.x3x9cwd.x1e5q0jg.x13rtm0m.x3nfvp2.x1q0g3np.x87ps6o.x1lku1pv.x1a2a7pz#typeahead-clear-button')
            search_field.click()

            
    except Exception as e:
        print(f"Could not unfollow {account} or button not found: {str(e)}")
        
        search_field = driver.find_element(By.CSS_SELECTOR, 'div.x78zum5 > div.x1i10hfl.x1qjc9v5.xjbqb8w.xjqpnuy.xa49m3k.xqeqjp1.x2hbi6w.x13fuv20.xu3j5b3.x1q0q8m5.x26u7qi.x972fbf.xcfux6l.x1qhh985.xm0m39n.x9f619.x1ypdohk.xdl72j9.x2lah0s.xe8uvvx.xdj266r.x11i5rnm.xat24cr.x1mh8g0r.x2lwn1j.xeuugli.xexx8yu.x4uap5.x18d9i69.xkhd6sd.x1n2onr6.x16tdsg8.x1hl2dhg.xggy1nq.x1ja2u2z.x1t137rt.x1o1ewxj.x3x9cwd.x1e5q0jg.x13rtm0m.x3nfvp2.x1q0g3np.x87ps6o.x1lku1pv.x1a2a7pz#typeahead-clear-button')
        search_field.click()


# 모든 작업 완료 후 드라이버 종료
driver.quit()

 

야!!!!!!!!!!!! 된다 !!!!!!!!!!!!!!!!!!!!!!

 

 

03. 결말

1) 일단 대략적인 작동 방식은 이렇습니다.

- 이 .py랑 같은 폴더 내의 'unfollow_list.txt'에서 계정 이름을 하나 읽어서 account라고 저장합니다.

- Thread 로그인 웹페이지가 자동으로 켜집니다

- 총 60초동안 느긋하게 로그인을 하고, 상단 돋보기 모양 아이콘을 눌러, 검색 창에 들어갑니다 (이것만 사용자가 직접)

- 검색 창 속 입력 칸을 직접 요 프로그램이 찾고, 그 안에 account를 입력합니다.

- 보통 검색 첫 번째 프로필만 대조해보면 됩니다.

- 첫 번째 프로필의 계정명이 account와 같으면 [팔로잉] 버튼을 눌러 언팔로우를 수행합니다.

- 가끔 비공계 계정일 경우 뭔가 창이 하나 더 뜨는데, 알아서 확인을 찾아서 누릅니다.

- 첫 번째 프로필의 계정명이 account와 다르면 그냥 "이상없습니다, 진행합니다"가 나오고 건너뜁니다.

- 가끔 아예 계정 삭제를 하셔서 첫 번째 프로필도 안 뜰 때가 있습니다. "떠났다"고 알려주고 건너뜁니다.

- 아주 가끔 아예 뜬금없는 계정이 첫 번째 프로필로 뜰 때가 있습니다.

- 뭐라고 오류가 뜨는데 상관 없을 것 같아서 건너뛰게 뒀습니다.

- 위 경우 중 하나를 성공하면 입력했던 account를 지웁니다.

- 그리고 다시 unfollow_list.txt 내 다른 계정명을 account에 저장하고, 위 과정을 반복합니다

- 끝

 

2) 저걸 하는 과정에서

- 웹 페이지 켜지게 두고, 로그인하고, 에러 나서 끄고, 다시 켜지게 두고, 로그인하고,

- 이걸 수 차례 계속 반복을 했더니 계정에 이상한 게 감지되었다고 일시적으로 로그인이 안되더라구요..

 

3) 그래서 60초정도 시간을 주고 그냥 직접 로그인을 느긋하게 했는데,

- 이마저도 계속 반복을 하니까 계정 비밀번호를 바꾸라고 연락이 오더라구요..

 

4) 계정 아예 잠기기 전에 성공 할 수 있어서 행복했습니다..

 

5) 결국 제일 중요한건, 스크린샷 캡쳐를 해서 보여주든 상황설명을 하고

 

- "왜 안되냐!!" 꾸짖으면 ChatGPT가 해 줍니다.

- 대답이 맘에 안들면 계속 이래저래 질문하다 보면 해결법이 나옵니다.

 

6) 횡설수설한 코딩알못의 장황한 글을 읽어주셔서 감사합니다.

 


관련된 다른 글도 읽어보시길 추천합니다

 

2024.05.14 - [AI] - 112. OpenAI, GPT-4o 출시

 

112. OpenAI, GPT-4o 출시

01. 서론 1) GPT-4o의 출시 배경 GPT-4o는 2024년 5월 OpenAI에서 공식 출시한 최신 AI 언어모델입니다. 하지만 이 모델은 사실상 이전부터 '정체불명의 gpt2 챗봇'이라는 이름으로 실험적으로 운영되고 있

guguuu.com

2024.04.17 - [AI] - 88. 노코드 혁명: 프로그래밍 없는 미래로의 진입

 

88. 노코드 혁명: 프로그래밍 없는 미래로의 진입

00. 서론: 노코드의 등장 배경 1) 기술 발전에 따른 코딩 기술 접근성 필요 증가 기술의 급속한 발전과 디지털 혁신은 많은 산업 분야에서 전문 지식을 요구하게 되었습니다. 그러나 모든 사람이

guguuu.com

2024.03.22 - [AI] - 63. OpenAI의 GPT-5 출시 예정 소식

 

63. OpenAI의 GPT-5 출시 예정 소식

GPT-5 이르면 올 여름 출시 오픈AI가 선보이는 차세대 언어 모델 GPT-5의 혁신적인 특징과 무한한 가능성을 탐구합니다 GPT-5가 가져올 기술 혁신과 다양한 산업 분야에서의 응용 가능성을 알아보세

guguuu.com


읽어주셔서 감사합니다

공감은 힘이 됩니다

 

:)

반응형

TOP

Designed by 티스토리