2018/05/13 - [노트정리/파이썬 Python] - 트위터에서 특정 트윗을 RT 한 사용자 목록 수집하기 (1)


위 링크의 이전 글에 이어서 이번에는 트위터에서 특정 트윗을 리트윗 한 사용자 목록을 파이썬 라이브러리인 selenium과 구글 크롬 드라이버를 통해 크롤링하는 방법을 보이고자 한다. 이 때 우리가 수집하고자 하는 트윗에 접근하기 위해 트윗을 올린 사용자와 트윗 메시지 아이디를 알아야 한다. 이 정보는 데이터베이스에 갖고 있다고 가정한다.


이 글의 예시 코드는 파이썬 3, pymysql, selenium (파이썬 라이브러리), 구글 크롬드라이버를 썼고 ubuntu 16에서 수행했다. 파이썬 버전이 다르거나 윈도우, 맥에서 수행하더라도 selenium을 설치해서 사용가능하고 크롬 웹브라우저가 작동하는 환경이면 어디서든 아래 코드를 따라 크롤러를 만들 수 있으리라 본다.


첫 문단에서 가정한 것 처럼 먼저 데이터베이스에 접근해서 리트윗 하려는 메시지를 특정하기 위해 사용자 아이디, 메시지 아이디를 가져온다.


필요한 라이브러리를 import 한다.


import pymysql
from selenium import webdriver
import time


위에서 트윗에 접근하기 위해 필요한 사용자 아이디와 트윗 메시지 아이디는 데이터베이스에서 얻어올 수 있다고 했다. 이를 불러오는 코드 예제는 아래와 같다. 데이터베이스에 연결해서 SQL 문으로 필요한 정보를 가져온다.


db_host, db_user, db_pass, db_name은 자신의 환경에 맞게 수정한다. SQL 문도 데이터베이스 환경에 맞추서 수정한다.


# MYSQL CONNECTION conn = pymysql.connect(host=db_host, user=db_user, password=db_pass, db=db_name, charset='utf8') # DICTIONARY CURSOR curs = conn.cursor(pymysql.cursors.DictCursor) # GET: msg_id, user_id sql = 'SELECT user_id, msg_id FROM msgs' curs.execute(sql) rows = curs.fetchall() print('rows',len(rows))


위 코드로 rows에 데이터베이스에서 필요한 사용자 아이디와 트윗 아이디를 가져왔다. 이제 크롬을 실행한다.


# INITIALIZE WEB DRIVER driver_path = './lib/chromedriver' driver = webdriver.Chrome(driver_path) driver.implicitly_wait(3) # or bigger seconds


driver_path에는 크롬 드라이버가 있는 위치를 써준다.


크롬을 열었으면, 이전 글에서 본 것처럼 트위터에 로그인해야 한다. 그러려면 로그인 정보를 입력할 곳의 위치와 로그인 버튼을 알아야 한다. 크롬에서는 F12 키를 누르면 개발자 도구를 열 수 있다. 개발자 도구에서 이 위치를 확인하는 방법을 알아보자.


아래 그림은 개발자 모드에서 Elements를 선택하면 나오는 화면이다. 오른쪽 상단에 Elements가 나타나있다. 이곳에서 방향키를 누르면 왼쪽의 실제 보이는 화면에 대응되는 element를 알아낼 수 있다. 이 방법으로 xpath를 알아내면 트위터 아이디, 비밀번호를 입력할 수 있고, 로그인 버튼을 누를 수 있다.





오른쪽 element가 있는 곳에서 찾고자하는 element가 왼쪽에 파란색으로 강조될 때 까지 돌아다니자. 아래 그림은 아이디 입력 element를 찾은 화면이다. 해당 element에 해당하는 곳에 마우스를 올리면 그림처럼 파란색으로 강조가 된다. 거기에서 마우스 오른쪽 버튼을 눌러 Copy Xpath로 xpath를 가져오자.



이런식으로 아이디와 비밀번호 텍스트 박스 그리고 로그인 버튼의 xpath 각각을 가져와 아래 처럼 변수로 선언하자.


# CONSTANT: TWITTER LOGIN
url_login = 'https://mobile.twitter.com/login'
xpath_user_account = '//*[@id="react-root"]/div[1]/main/div/div/form/div/div[1]/div/input'
xpath_user_passwd = '//*[@id="react-root"]/div[1]/main/div/div/form/div/div[2]/div/input'
btn_login = '//*[@id="react-root"]/div[1]/main/div/div/form/div/div[3]/div'


다음으로 드라이버로 열었던 크롬에서 로그인 웹 페이지로 이동한 후 로그인하는 코드를 아래처럼 만든다. 웹 페이지가 열릴 때 로딩 시간이 오래걸릴 수 있다는 점을 고려해서 2초를 강제로 쉬게 만들었다.


# TWITTER LOGIN
driver.get(url_login)
time.sleep(2)
driver.find_element_by_xpath(xpath_user_account).send_keys(user_account)
driver.find_element_by_xpath(xpath_user_passwd).send_keys(user_password)
driver.find_element_by_xpath(btn_login).click()

위에서 데이터베이스로부터 rows에 사용자 아이디와 메시지 아이디를 가져왔다. 커서를 dictionary로 선언했기 때문에 rows는 파이썬 dictionary로 데이터가 저장되어있다. 커서 인덱스를 처음부터 끝까지 돌며 사용자 아이디, 메시지 아이디를 가져오면 리트윗 사용자 목록을 볼 수 있는 웹페이지 접근할 수 있다.


사용자 목록에서 사용자 아이디는 유일한 값이므로 set에 저장하기로 하자. 그리고 사용자 목록은 한번에 모두 불러오는 것이 아니라 스크롤을 내리면 화면 크기만큼 불러오게 된다. 그래서 스크롤을 조금씩 내려가며 사용자 목록을 set에 저장해서 스크롤이 끝나면 종료하게 코드를 작성한다. 그리고 가져온 사용자 목록은 데이터베이스에 저장하도록 한다.


for row in rows: user_id = str(row['user_id']) msg_id = str(row['msg_id']) rt_users = set() url_retweet = 'https://mobile.twitter.com/'+user_id+'/status/'+msg_id+'/retweets' print(url_retweet) driver.get(url_retweet) time.sleep(2) # GET SCROLL HEIGHT last_height = driver.execute_script('return document.body.scrollHeight') while True: elem = driver.find_element_by_xpath('//*[@id="react-root"]/div/main/div/div/div[2]/div/section/div') arr = elem.text.split('\n') for i in range(1, len(arr), 3): rt_users.add(arr[i][1:]) # SCROLL THE WEB PAGE # IF It doesn't crawl all rt users, change second number smaller. # EX: 1080 -> 720 driver.execute_script('window.scrollBy(0, 1080);') # Wait to load page time.sleep(0.5) # Calculate new scroll height and compare with last scroll height new_height = driver.execute_script('return document.body.scrollHeight') # print(last_height, new_height, len(rt_users)) if new_height == last_height: break last_height = new_height for user in rt_users: sql = "INSERT IGNORE INTO users (user_id) VALUES (%s)" curs.execute(sql, (user)) conn.commit()


마지막으로 드라이버로 열었던 크롬을 닫아주고, 데이터베이스 접속도 끊어준다.


# CLOSE WEB DRIVER
driver.close()

# MYSQL CLOSE
conn.close()


Posted by 공돌이pooh
,