본문 바로가기

카테고리 없음

티스토리 포스팅 자동화 2 - 파이썬 코드 작성

728x90
반응형

https://youngnk.tistory.com/entry/티스토리-포스팅-자동화-1-API-엑세스-토큰-구하기

 

 

티스토리 포스팅 자동화 1 - API, 엑세스 토큰 구하기

파이썬을 거의 모르는 초보입니다. 인터넷, chat gpt를 통해서 조금식 티스토리 자동화 블로그를 만들어 봤습니다. 참고로 다른 분 블로그를 기반으로 연습하면서 만들었습니다. 다른 분 것과 비

youngnk.tistory.com

 

 

엑세스 토큰을 구하고 본격적으로 파이썬 코드 작성했다. 다른 분들 블로그를 참고했고 내가 하고 싶은 페이지로 변경하는 작업을 진행했다. 하다 막히는 부분은 ChatGPT를 이용해 수정했다.

 

 

어떤 내용을 자동 포스팅 할 것인가를 먼저 정하기

연합뉴스 영문 사이트의 기사 3개를 램덤으로 가져온 후 한국어로 번역해 포스팅하기

 

 

1. 목표 url

url = 'https://en.yna.co.kr/index'
url_post = "https://www.tistory.com/apis/post/write" 
access_token = "   "  # 전에 받아 둔 엑세스 토큰 값 입력
blog_name = "   "  # 내 블로그 주소

 

2. 해당 페이지에서 랜덤하게 url 3개 뽑아오기

- url이 '//en.yna.co.kr/view/'로 시작하고 있음

- //en.yna.co.kr/view/ 을 가진 모든 URL을 찾아내서 http://url 형태로 변환 해 리스트에 넣기

- 리스트 중 3개 랜덤하게 뽑아내기

 

# 메인페이지에서 랜덤하게 3개 기사 URL 추출해 반환하기

def get_url_of_the_day():
    papers = []
    response = requests.get(url)
    html = response.text
    soup = BeautifulSoup(html, 'html.parser')
    for a in soup.find_all('a', href=True):
        if a['href'].startswith('//en.yna.co.kr/view/'):
            papers.append('https:{}'.format(a['href']))
    return random.choices(papers, k=3)

 

 

3. 다음은 페이지에 가서 제목, 타이틀, 번역할 텍스트 값 구하기

 

def extract_content(url):
    response = requests.get(url)
    html = response.text
    soup = BeautifulSoup(html, 'html.parser')

    title = soup.select_one('h1.tit').text
    abstract = soup.select_one('article.story-news').text   #본문 추출
    abstract = abstract.replace(soup.select_one('p.txt-desc').text, '') #텍스트 중 캡션 부분 제거
    abstract = abstract.split('(END)')[0] #END 부분까지만 크롤링


    parser = PlaintextParser.from_string(abstract, Tokenizer("english"))
    summarizer = LexRankSummarizer()
    summary = summarizer(parser.document, 3)
    summary_text = ' '.join([str(sentence) for sentence in summary])

    translation = translate(summary_text)

 

타이틀과 본문 내용을 추출하는 코드를 작성. 본문 내용 중에는 캡션 텍스트도 있어서 제거해줬다.

연합뉴스 영문페이지의 경우 텍스트 테그에 많은 내용이 있어서 그냥 추추하면 잡다한 텍스트가 다 들어온다.

그런대 다른 페이지들도 살펴보니 기사 마무리가 END로 되어 있어서 END까지 텍스트만 추출하도록 했다.

 

 

 

4. 사진 생성

 


    # openai api 이용, 타이틀 단축, 쿼리에 사용할 단어로 변환
    
    # openai client id and secret
    openai.api_key = "    "
    
    # Define the prompt, Get the summary, openai api 이용해 unsplash에 쿼리 삽입
    prompt = "INFO : you can add images to the reply by Markdown, Write the image in Markdown without backticks and without using a code block. Use the Unsplash API (https://source.unsplash.com/1600x900/?). the query is just some tags that describes the image] ## DO NOT RESPOND TO INFO BLOCK ##\n\nmy Next prompt is give me a blog cover image url fit to this subject {title}"

    # Use the OpenAI API to generate a response
    response = openai.Completion.create(
        engine="text-davinci-003",
        prompt=prompt,
        max_tokens=2048,
        n = 1,
        stop=None,
        temperature=0.5
)
    img_url = response["choices"][0]["text"]

 

블로그에 쓸 사진이 있어야 하는데 연합뉴스 사진은 저작권이 있어 사용할 수 없다.

랜덤하게 저작권 문제 없는 사진 사이트인 unsplash를 이용하기로 했다.

https://source.unsplash.com/1600x900/?{query}를 넣어주면 된다.

쿼리 생성을 OpenAI API를 이용했다. 

프로프트로 앞에서 생성한 타이틀을 입력하고 그와 유사한 단어 3개를 만든 뒤 URL 형태로 반환하도록 했다.

 

OpenAI API는 조금은 무료인데 돈을 받는것 같기도 하다. 그런데 많은 비용이 들지는 않는다. 번역에 이용했던 davinci의 경우 매우 저렴하다. 

 

 

이것저것 실험하고 자동화한다고 상당히 사용했는데 3.88달러가 나왔다. 처음에 준 18달러도 아직 다 사용 못한 것 같다.

 

여기서 만들어준 URL은 본문에 태그 형태로 삽입된다. 사진은 새로고침을 할때마다 새로운 사진이나온다. 아쉽게도 대표사진을 자동으로 설정하는 법은 모르겠다.

 

 

 

5. 파파고 API를 이용해서 번역하기

 

# 영어 텍스트 한국어로 번역하기 (파파고 API 사용 )
def translate(eng_abs):
    try:
        text = urllib.parse.quote(eng_abs)
        data = "source=en&target=ko&text=" + text
        url = "https://openapi.naver.com/v1/papago/n2mt"
        request = urllib.request.Request(url)
        request.add_header("X-Naver-Client-Id",client_id)
        request.add_header("X-Naver-Client-Secret",client_secret)
        response = urllib.request.urlopen(request, data=data.encode("utf-8"))
        rescode = response.getcode()
        if(rescode==200):
            response_body = response.read()
            res = response_body.decode('utf-8')
            res = json.loads(res)
            result = res['message']['result']['translatedText']
            return result
    except:
        return ''

 

파파고 API를 신청해야 한다. 무료로 이용하고 있는데 하루에 사용할 수있는 양이 있는 것 같다. 양을 초과하면 번역이 되지 않는다.

파파고 API 신청은 아래 URL에서 하면 된다.

 

https://developers.naver.com/docs/papago/README.md

 

파파고 - Papago API

파파고 파파고는 다국어 언어 처리에 대한 네이버의 기술과 경험을 번역 엔진에 적용해 보다 정확한 번역 결과를 제공하는 서비스입니다. 파파고가 제공하는 RESTful 형태의 API를 사용하면 서비

developers.naver.com

 

 

6. 지금까지 만든 정보를 이용해 글쓰기

 

코드는 아마도 짜집기를 여러번 하다보니 불필요한 변수도 있다. 그런데 특별히 문제를 일으키지 않아 그냥 넣어뒀다. 

하다보니 뭔가 살짝 만지면 예상하지 못한 오류가 나와서 별 문제 없으면 그냥 두기로 했다.

광고도 자동으로 삽입하고 싶었는데 iframe 형태로 삽이되는 게 아니라 텍스트 형태로 들어간다. 

 

성공하면 ok라고 나오고 실패하면 무자비한 빨간줄이 나온다.

실패하는 경우를 보니 URL을 뽑아낼때 카드뉴스 같은게 나올때가 있다. 여기에는 텍스트가 없어서 텍스트 뽑아오는 쪽에서 오류가 난다.

예외를 두고 다시 랜덤하게 URL을 뽑으려 했더니 잘 안되 포기했다.

오류가 나면 몇번 더 실행하면 된다.

이상 끝!!

 

# 글 쓰기 
def write_post():
    
    post = ''
    titles = []
    abstracts = []
    summary_texts = []
    translations = []
    summarys =[]
    img_urls = []
    prompts = []

    urls = get_url_of_the_day()
    for url in urls:
        title, abstract, summary_text, translation, summary, prompt, img_url = extract_content(url)
        titles.append(title)
        abstracts.append(abstract)
        summary_texts.append(summary_text)
        translations.append(translation)
        summarys.append(summary)
        img_urls.append(img_url)
        prompts.append(prompt)
    
    
    for ti, ab, st, tr, sm, pr, iu in zip(titles, abstracts, summary_texts, translations, summarys, prompts, img_urls):
        post += "<p data-ke-size='size14'><span style='font-family: 'Noto Sans Demilight', 'Noto Sans KR';'><img src ='{}'></span></p>".format(iu)
        post += "<h3 data-ke-size='size23'><b><span style='font-family: 'Noto Sans Demilight', 'Noto Sans KR';'>{}</span></b><span style='font-family: 'Noto Sans Demilight', 'Noto Sans KR';'></span></h3>".format(ti)
        post += "<p data-ke-size='size18'><span style='font-family: 'Noto Sans Demilight', 'Noto Sans KR';'>{}</span></p>".format(st)
        post += "<p data-ke-size='size18'><span style='font-family: 'Noto Sans Demilight', 'Noto Sans KR';'>{}&nbsp;</span></p>".format(tr)

    html_file = open('../post.html', 'w+')
    html_file.write(post)
    html_file.close()



if __name__ == '__main__':
	
    # 글 제목 
    title = '[{}] 영문 뉴스 자동 요약, 번역 by papago '.format(datetime.today().strftime("%Y-%m-%d, %H:%M:%S")) 

    write_post()
    f = open('../post.html', 'rt', encoding='utf-8')
    # 글 내용 
    content = f.read()

    visibility = 3 #(0: 비공개 - 기본값, 1: 보호, 3: 발행) 
    category = '' # 글을 올리고 싶은 카테고리 번호 
    publish_time = '' 
    slogan = '' 
    tag = 'news,English,papago,자동 번역, 자동 포스팅, 파이썬' # 글 태그 
    acceptComment = 1 # 댓글허용 
    password = '' # 보호글 비밀번호 

    headers = {'Content-Type': 'application/json; charset=utf-8'} 
    params = {'access_token': access_token, 'output': 'json', 'blogName': blog_name, 'title': title, 'content': content, 'visibility': visibility, 'category': category, 'published': publish_time, 'slogan': slogan, 'tag': tag, 'acceptComment': acceptComment, 'password': password } 
    data = json.dumps(params) 
    rw = requests.post(url_post, headers=headers, data=data) 

    if rw.status_code == 200: 
        print('ok') 
    else: 
        print('fail')


 

반응형