파이썬으로 인스타그램 포스팅

주로 링크와 생각을 남기는 포스팅을 하기 때문에 주로 페이스북을 중심으로 운영을 하고, 인스타그램은 거의 생각하고 있지 않았다. 그래도 가끔 검색을 통해 들어와 좋아요를 누르는 사람들이 있어서 인스타그램을 조금 신경써야 겠다는 생각이 들었다.

그러나 아직 페이스북도 정착이 안되었는데, 인스타그램을 위해서 콘텐츠를 따로 만들거나 편집을 하는 것은 손이 많이 가는 작업이다. 따라서 기존 페이스북 포스팅을 캡쳐하여 자동으로 업로드 하는 스크립트를 작성해 보기로 하였다.

  1. 페이스북 포스팅 스크린캡쳐
  2. 이미지 수정
  3. 인스타그램 업로드
  4. 작업스케쥴러로 자동실행

순으로 설명해 보겠다. 간단한 코드이지만, 페이스북과 인스타그램을 selenium 으로 제어할 때 참고할 수 있을 것이다.

먼저 업로드를 위한 인스타그램 API 사용이 가능한지를 찾아보았으나, 아래와 같이 업로드를 위한 API 사용은, 현재 미공개 베타 진행중이고, 비즈니스 계정이 아니면 쓰지 못하는 것으로 보인다. 어차피 페이스북 포스팅 스크린샷을 위해서 파이썬 Selenium을 이용할 것이기 때문에 Selenium을 이용하여 포스팅하기로 했다.

출처 : https://developers.facebook.com/docs/instagram-api/?locale=ko_KR

  • 사진과 동영상 게시(현재 미공개 베타 진행 중)
  • 이 API는 Instagram 소비자 계정(예: 비즈니스나 크리에이터가 아닌 Instagram 계정)에 액세스하는 데 사용할 수 없습니다. 소비자 사용자를 위한 앱을 빌드하고 있다면 대신 Instagram 기본 디스플레이 API를 사용하세요.콘텐츠 게시는 Instagram Business 사용자에게만 제공됩니다.

페이스북 포스팅은 https://www.facebook.com/data.triviaz/posts/[포스팅 id] 를 통해 접속이 가능하다.
각 포스팅의 id를 가져오기 위해서, 이전에 포스팅했던

를 이용하였다.

페이스북 포스팅 가져오기

import pandas as pd

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options

import requests
import datetime
from utils import *

url = f"https://graph.facebook.com/v6.0/100300361542753/posts?fields=created_time%2Cid%2Cmessage%2Cmessage_tags%2Ctitle&limit=10&pretty=0&access_token={token}"
resp = requests.get(url=url)
json_out = resp.json()
anchor_time = datetime.date.today() - datetime.timedelta(days=1)
fb_df = nested_json(json_out)

  • utils 는 nested_join 함수를 포함하고 있는, 직접 만든 라이브러리 파일. 이전 포스팅 참고.
  • anchor_time 은 바로 전 날의 포스팅만을 필터링하기 위해 어제 날짜로 선언

접속 및 스크린샷

User-Agent 를 설정해서 모바일 모드로 인식되게 한다.

chrome_driver = "c:\\chromedriver.exe" # Your Chrome Driver path
chrome_options = Options()
chrome_options.add_argument('--user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e Safari/602.1')
driver = webdriver.Chrome(chrome_driver,options=chrome_options)

어제 날짜만 필터링해서, 페이스북에 접속한다.

up_list = []
for idx in range(0,10):
    # 전날 이전이면 끝
    if UTCtoKST(fb_df.loc[idx,'created_time']) < anchor_time.strftime('%Y-%m-%d %H:%M:%S') :
        break
    # 오늘이면 skip
    elif UTCtoKST(fb_df.loc[idx,'created_time'])[:10] == datetime.date.today().strftime('%Y-%m-%d'):
        continue
    else:
        up_list = up_list + [idx]
    fb_url = 'https://www.facebook.com/data.triviaz/posts/'+fb_df.loc[idx,'id'].split('_')[1]
    print(idx)

    driver.get(fb_url)

이제 스크린샷을 위해서 웹페이지 창을 정리하도록 한다.

    driver.set_window_size(500,10000)
    
    content_body = driver.find_element_by_class_name('story_body_container')
    
    driver.execute_script("arguments[0].style.zoom=1.3", content_body)
    driver.execute_script("arguments[0].style.fontFamily='NanumGothic'", content_body)
    driver.execute_script("arguments[0].style.lineHeight=1.3", content_body)
    driver.execute_script('scroll(0,200)')
    driver.find_element_by_id('m_story_permalink_view').screenshot(f'insta_img_temp\\img{idx}.png')
driver.quit()

  • line 1: 크롬 윈도우 크기를 width 500 으로 설정
  • line 3: 'story_body_container' 클래스가 포스팅 영역이다.
  • line 5-9: 그냥 보면 글씨가 작고, 폰트가 예쁘지 않다.
    • 그래서 스크립트를 실행해서, 폰트 크기를 키우고, 폰트를 바꾸고, 줄간격을 조절해서 인스타그램에서 예쁘게 보일 수 있도록 하였다.
    • 포스팅 영역만 screenshot 함수로 이미지파일로 저장할 수 있다.

Fig. 1: 스크롤로 윗부분을 숨기고, 폰트를 조정해서 오른쪽 처럼 좀 더 예쁘게 만들 수 있다.

위 이미지에서 게시자 및 'Share 버튼'을 지워주는 부분이다.

from PIL import Image, ImageOps
for idx in up_list:
    im = Image.open(f'insta_img_temp\\img{idx}.png')
    width, height = im.size
    im_crop = im.crop((0,65,width,height-50))
    if width > height:
        im_crop = ImageOps.expand(im_crop, (0,int((width-height)/2),0,int((width-height)/2)), fill='white')
    #im_crop.show()
    new_img = f"insta_img_temp\\img{idx}_2.png"
    im_crop.save(new_img)

  • line 5: 기존 이미지에는 게시자명 및 'Share' 버튼이 있기 때문에 이 부분을 잘라주어야 한다
    • 상단 65, 하단 50 픽셀만큼 잘라주면 딱 맞다
  • line 7: 인스타그램은 정사각형 이미지가 기본이기 때문에, 포스팅 길이가 짧으면 이미지가 깨지기 때문에 이미지 크기를 1×1 로 맞추어 주어야 한다.
    • 길이가 넓이보다 작으면, 흰색으로 아래 위에 padding을 추가하였다.

접속, 로그인

인스타그램은 모바일 기반으로 운영되고 있다. 따라서 PC 버전으로 사이트에 접속하게 되면, 업로드 버튼이 보이지 않는다.
모바일 버전으로 들어가기 위해서 user-agent와 크롬의 Mobile Emulation 옵션을 통해서 모바일 버전으로 들어가야 한다.


chrome_options = Options()
chrome_options.add_argument('--user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e Safari/602.1')

mobile_emulation = { "deviceName": "Galaxy S5" }

chrome_options.add_experimental_option("mobileEmulation", mobile_emulation)
driver = webdriver.Chrome(chrome_driver,options=chrome_options)

아래 이미지 순서대로 인스타그램 페이지에 접속하여 로그인을 한다.
로그인을 하면 3번째 그림과 같이 '로그인 정보를 저장할 것인가'를 묻는데, 여기서 Not Now를 클릭하도록 한다.

driver.get('https://www.instagram.com/')

#1번 그림
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//*[contains(text(), 'Log In')]")))
driver.find_element_by_xpath("//*[contains(text(), 'Log In')]").click()

import time

#2번 그림
time.sleep(2)
driver.find_element_by_name('username').send_keys('아이디')
driver.find_element_by_name('password').send_keys('비밀번호')

WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//*[contains(text(), 'Log In')]")))
driver.find_element_by_xpath("//*[contains(text(), 'Log In')]").click()

#3번 그림
driver.implicitly_wait(3)
driver.find_element_by_xpath("//*[contains(text(), 'Not Now')]").click()

driver.get('https://www.instagram.com/data.triviaz/')

업로드

업로드 버튼(+)은 아래와 같이 크롬에서 '검사' 버튼을 눌러 찾을 수 있다. <div data-testid='new-pos-button' 을 찾아서 클릭하도록 한다.

for idx in up_list:

    driver.get('https://www.instagram.com/data.triviaz/')

    new_img = f"insta_img_temp\\img{idx}_2.png"

    print(idx)

    import pyautogui

    time.sleep(5)
    WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[@data-testid='new-post-button']")))
    driver.find_element_by_xpath("//div[@data-testid='new-post-button']").click()
    

이미지 업로드 버튼을 누르면, 파일 업로드 창이 뜬다. 여기서는 pyautogui 패키지를 이용해서, 파일 경로를 입력하도록 했다.
input type='file' 에 send_key 를 하는 방법도 있는데, 어떤 input에 넣는 것이 맞는지 찾기가 힘들어서 간단하게 구현하였다.

    time.sleep(5)
    pyautogui.write(f'c:\\이미지경로\\{new_img}')
    pyautogui.press('enter')

Fig. 1: pyautogui를 이용해서 이 화면에 이미지가 있는 경로를 입력하게 한다.

    
    driver.implicitly_wait(5)

    driver.find_element_by_class_name('pHnkA').click()
    driver.find_element_by_class_name('UP43G').click()
    driver.find_element_by_tag_name('textarea').send_keys('페이스북 @Data.triviaz #triviaz .net #데이터분석 #통계 #빅데이터 #데이터사이언스 #일잘러 #인공지능 #기획 #데이터마케팅 #엑셀 #마케팅 #비즈니스 #IT #서평 #')
    driver.find_element_by_class_name('UP43G').click()
    driver.implicitly_wait(5)

time.sleep(5)
driver.quit()

  • 클래스 이름으로 찾아서 click 하는 부분들은 아래 그림과 같은 버튼들이다
    • pHnkA : expand 버튼 (「 」)
    • UP43G : Next 버튼
    • UP43G : Share 버튼

만든 이 스크립트를 윈도에서 작업스케쥴러를 사용해서 매일 새벽에 자동실행하기로 했다. 작업스케쥴러를 처음 사용해봐서 이것저것 옵션을 설정하는데 애를 먹었다.

먼저 python 스크립트를 실행하도록 윈도 배치파일부터 만들도록 하자.

배치파일 만들기

메모장을 열어서 다음과 같은 명령어들을 입력하고 .cmd 파일로 저장하자.

@ECHO off
ECHO Instagram_upload
cd C:\경로\PycharmProjects\facebook\  
ECHO ---------------------------------
python instagram.py
ECHO ---------------------------------
ECHO THANK YOU
ECHO ---------------------------------
PAUSE

  • @echo off 를 하면 명령어를 치는 장면을 출력하지 않게 한다. (ex. c:> cd dir 같은 명령어가 화면에 보이지 않는다)
  • ECHO : cmd 창에 문자를 출력해주는 파이썬의 print 와 같은 명령어
  • line 5: python instagram.py 를 실행는 부분
  • PAUSE : '아무키나 누르세요..' 를 출력하고 기다리게 하는 부분

작업스케쥴러 설정

윈도 시작메뉴에서 '스케쥴러'를 검색해서 작업스케쥴러 설정으로 들어가자.
상단 메뉴 또는 오른쪽 버튼에서 기본 Task 만들기를 통해서 일정을 만들도록 하자.

이름을 정하고, 아래와 같이 시간과 반복 일정을 택하도록 한다.

해야할 작업으로, 위에서 만든 cmd 파일을 실행하도록 하고, 마무리하도록 하자.

속성 수정

아마, 이것만으로는 실행이 되지 않을 것이다. 좀 더 속성에 대한 수정이 필요하다.

아래의 작업 리스트에서 우리가 만든 작업을 우클릭해서 속성 창을 들어가자

일반 설정에서 '사용자가 로그인되어 있을 때 실행'이 체크되도록 하자. 우리가 만든 스크립트는 웹페이지 제어, 스크린샷, autogui 등을 이용하였기 때문에 background가 아닌 foreground에서 실행이 되어야 한다.

조건Condition 탭에서 '작업을 실행하기 위해서 컴퓨터를 깨우게 함' 을 선택하여, 절전모드 등에 있을 때도 실행이 되도록 한다.

또한, 윈도우 제어판의 전원 옵션 > 고급설정 에서 아래와 같이 타이머가 컴퓨터를 절전옵션에서 나올 수 있도록 설정을 해준다.

지금까지 작업을 통해서, 하루동안 포스팅한 페이스북 게시글들을

  1. 자고 있을 동안 스크린캡쳐해서
  2. 인스타그램에 자동으로 업로드 하게 된다.

좀 더 추가해볼 수 있을 만한 아이디어는,

  1. 포스팅 게시물의 텍스트에서 단어를 추출해서 해시태그(#) 달기
  2. 링크나 텍스트 위주 게시글이 아닌 경우, 스크린샷이 아닌 이미지만 가져와서 인스타그램에 업로드 하기

등이 있을 것 같다.


* 페이스북에 주로 포스팅을 하고, 인스타그램을 거의 관리 안함 - 인스타그램 자동화를 하자
* 그럼에도 불구하고 해시태그로 검색해서 좋아요를 누르는 사람이 있네
* 페이스북도 안착이 안되었는데, 인스타그램을 위해서 따로 컨텐츠 제작은 손이 많이 간다
* 그래서 페이스북 페이지 캡쳐 + 인스타그램 업로드 해주는 스크립트 짜기로 결정
* 인스타그램 API 사용은 힘든듯?
* [링크] 페이스북 포스팅 가져오기는 API로 간단히 되었는데, 인스타그램은 그렇지 않은 듯
* 인스타그램 정책 설명
* Selenium 으로 업로드 하는 것. 간단하지만 시행착오를 많이 겪어서 도움이될지도
* 페이스북 켄텐츠를 캡쳐해서 인스타에 업로드 하는 것까지 만들어보기로
* 페이스북 포스팅 접속 : ID로 접속할 수 있음
* 캡쳐 : 모바일 화면에 적합하게 하기 위해
* 모바일 모드로 크롬 접속
* 포스팅 부분만 캡쳐
* 글씨크기와 폰트가 마음에 안들어서 변화
* 이미지 정리
* Crop : 게시자와 아래 Share 지우기
* 그림판에서 position 구할 수 있음
* Expand : 1×1 로 들어가는 인스타 특성상 짧은 글은 퍼지게 된다
* 인스타 업로드
* 모바일 모드 접속 : 업로드 기능은 모바일모드에서만 된다
* 로그인 : 기다리는 지점
* 파일 업로드 : input sendkeys는 잘 안먹혀서 pyautogui 로 해결
* Expand, Next, Share ..

Enter your comment:
L X G F L