본문 바로가기
Project/Blog New Post Noti

[New Post Noti] 블로그를 파싱해보자.

by Haren 2021. 9. 4.

지난 포스팅에서는 Python의 패키지인 Tweepy를 활용해 Python으로 트윗을 작성해보았다.

 

>_ 지난 포스팅 보기

 

[Blog New Post Noti] Python으로 트윗을 작성하기

지난 포스팅에서는 파이썬에서 트위터를 제어하기 위한 패키지인 Tweepy에 대해서 알아보았다. 파이썬으로 트윗 봇을 만드려면 Tweepy 설치가 선행되어야 하므로, 아직 설치하지 않았다면 지난 포

heibondk.tistory.com

 

이번 시간에는 블로그의 새 포스팅을 전달해주기 위한 정보를 준비하기 위해서, 나의 블로그를 파싱하고 파싱한 데이터를 트윗을 하기 좋게 가공을 해보는 시간을 가져보도록 하겠다. 하지만 이 카테고리는 프로젝트 진행 과정을 기록하기 위한 것이기 때문에, Python을 통한 웹페이지 파싱에 대한 자세한 설명은 Study 카테고리에서 따로 다룰 예정이며 본 포스팅에서는 단순히 이 프로젝트 상에서 어떻게 블로그를 파싱했고 데이터를 가공했는지만 다룰 것이다.

 


파싱 코드

파싱에 사용된 패키지

  • requests
  • BeautifulSoup4
  • OrderedDict
  • json

이 중 requests와 BeautifulSoup4를 설치하는 방법에 대해서는 예전에 포스팅을 해두었으니 참고하면 좋을 것 같다.

 

>_ requests와 BeautifulSoup4 설치하기

 

[Python3 / Mac ] 웹 크롤링을 위한 준비 - pip, requests, beautifulsoup4 설치

학교 수업 중 도표 혹은 그래프를 이용한 자료를 만들어 발표하는 과제를 받았습니다. 뭔가 참신한 것을 해볼 수는 없을까? 싶은 마음에 이것저것 알아보게 되었고, 파이썬을 이용하여 대표적

heibondk.tistory.com

 

주의사항

이 파싱 코드는 티스토리 블로그 제공 스킨 중 "Book Club" 스킨에서만 원활한 사용이 가능하다.

 

코드

myblogparser.py

import requests
from bs4 import BeautifulSoup
import json
from collections import OrderedDict

myblog = requests.get("https://heibondk.tistory.com/")
soup = BeautifulSoup(myblog.content, "html.parser")

def exiNewPost_file() :
    file_data = OrderedDict()
    file_data["link"] = "https://heibondk.tistory.com"
    file_data["title"] = soup.select(".title")[0].get_text()
    file_data["date"] = soup.select(".date")[0].get_text()
    links = soup.select(".post-item")[0]
    href = links.find('a')
    href_last = href.attrs['href']
    file_data["href"] = href_last

    with open('./POST_JSON/ExiNewPost.json', 'w', encoding="utf-8") as make_file:
        json.dump(file_data, make_file, ensure_ascii=False, indent="\t")

main.py - NewPost_file() 함수

def NewPost_file() :
    file_data = OrderedDict()
    file_data["title"] = soup.select(".title")[0].get_text()
    file_data["date"] = soup.select(".date")[0].get_text()
    links = soup.select(".post-item")[0]
    href = links.find('a')
    href_last = href.attrs['href']
    file_data["href"] = href_last
    with open('./POST_JSON/NewPost.json', 'w', encoding="utf-8") as make_file:
        json.dump(file_data, make_file, ensure_ascii=False, indent="\t")

파싱을 사용한 가장 핵심적인 부분은 myblogparser.py 파일의 코드이다. 코드를 찬찬히 훑어보며 사용 방법을 알아보도록 하겠다.

import requests
from bs4 import BeautifulSoup
import json
from collections import OrderedDict

먼저 최상단에서 사용할 패키지 (혹은 라이브러리, 모듈)을 import 해주어야 한다.

requests는 HTTP에 관한 파이썬 라이브러리이다. BeautifulSoup4는 HTML과 XML 파싱에 관한 패키지이며, collections.OrderedDict는 아이템들의 입력 순서를 기억하기 때문에 정렬된 딕셔너리를 만들기 위해 사용한다.

json은 requests와 BeautifulSoup4로 파싱해온 HTML 데이터를 collections.OrderedDict으로 정돈하여 필요한 정보들을 뽑아 json 파일으로 만들기 위해 사용하였다.

myblog = requests.get("https://heibondk.tistory.com/")
soup = BeautifulSoup(myblog.content, "html.parser")

myblog 변수에는 requests.get을 이용하여 내 블로그에 HTTP 요청을 보내 소스를 가져오고, soup 변수에서 html 파서를 이용해 HTML 데이터를 담는다.

def exiNewPost_file() :
    file_data = OrderedDict()
    file_data["link"] = "https://heibondk.tistory.com"
    file_data["title"] = soup.select(".title")[0].get_text()
    file_data["date"] = soup.select(".date")[0].get_text()
    links = soup.select(".post-item")[0]
    href = links.find('a')
    href_last = href.attrs['href']
    file_data["href"] = href_last

    with open('./POST_JSON/ExiNewPost.json', 'w', encoding="utf-8") as make_file:
        json.dump(file_data, make_file, ensure_ascii=False, indent="\t")

위의 exiNewPost_file() 함수는 '기존의 최신 포스팅' 정보를 다듬고 json 파일로저장하는 함수이다. 

포스팅의 정보만을 저장하기 위해서 필요한 것들만 뽑아오는 과정을 확인할 수 있다.

 

file_date["link"]의 경우, 각 포스팅에는 블로그 주소 뒤에 번호가 붙는다. 따라서 링크 + (포스팅번호)를 하면 포스팅의 URL이 나오므로, 문자열을 붙여 포스팅의 URL을 제공하기 위해 따로 고정시켜준다.

 

file_data["title"]과 ["date"]을 보면 클래스가 "title", "date"인 HTML 태그 중 가장 첫 번째 (인덱스 0을 주었으므로.) 의 텍스트만을 취한다. 포스팅을 작성하며 생각난건데, 이 부분은 && 연산자를 사용해서 더 짧은 코드를 만들 수 있지 않았을까 싶다. 시간이 나면 수정해보아야겠다.

 

포스팅 주소에서 맨 뒤의 숫자만을 취하는 부분이 조금 길어졌는데, 다음과 같은 과정을 거친다.

links = soup.select(".post-item")[0] #클래스명이 "post-item"인 HTML 태그중 가장 첫번째를 가져온다.
href = links.find('a') #첫번째로 클래스명이 "post-item"인 HTML 태그 중에서도 <a> 태그를 찾는다.
href_last = href.attrs['href'] #<a>태그에서 href 속성을 꺼내온다. (BeautifulSoup의 스크래핑)
file_data["href"] = href_last #json "href" = " " 형식으로 넣는다.

위 과정은 BeautifulSoup4를 사용하여 스크래핑을 하는 과정이다. 위의 과정을 얘기하기 전에 짚고 넘어가야 할 것이 티스토리 블로그의 HTML 구조이다. 포스트 아이템 안에 포스팅의 번호를 href 속성으로 지정해주어서 블로그 주소 + 포스팅 번호로 URL을 만들어주는 것 같았다. 

with open('./POST_JSON/ExiNewPost.json', 'w', encoding="utf-8") as make_file:
        json.dump(file_data, make_file, ensure_ascii=False, indent="\t")

마지막으로 이것들을 json 파일에 저장을 해준다.

 

main.py에서 최신 포스팅을 파싱해오는 과정은 위와 동일하다.

 

발생할 수 있는 문제

이 포스팅을 작성하기 전에 블로그의 스킨을 변경했었었다. 그러자 HTML 구조가 파싱을 할 때와 달라져서 위처럼 파싱을 할 수가 없었고, HTML 태그들의 클래스 등의 이름을 바꿔주어야 하는 문제가 생겼다. 따라서 자신의 블로그 스킨에 따라서 다르게 파싱을 해야 할 필요가 있다.

 


이 포스팅을 작성하며 내가 짰던 코드를 다시 한 번 살펴보고, 보완해야 할 점과 발생할 수 있는 문제점을 파악할 수 있었다.

단순히 내 블로그에 맞춰 작성했다보니 티스토리 블로그 스킨이 다른 블로그에서는 정상적으로 적용이 안되는 문제는 코드 상에서 수정을 해야하는 문제인 것 같다. 일단은 블로그 스킨 설정을 코딩을 할 당시의 스킨으로 다시 변경해두긴 했지만, 다시금 코드를 수정하며 스킨을 바꿔보아야겠다.

 

다음 포스팅에서는 블로그를 파싱해서 저장한 두 json 파일을 가지고 비교하여 트윗을 올려주는 과정을 다룰 것이다. 이제 트윗을 올려주는 과정과 crontab을 이용해서 서버에서 실시간으로 구동할 수 있게 한 부분만 남았다. 어느덧 이 프로젝트 시리즈의 끝도 보인다.