웹페이지에서 자동으로 RSS 만들기

지난 달에 봤던 뮤지컬 《헤어스프레이》가 너무 좋아서 마지막 회차 공연 때 또 보려고 3차 티켓 오픈 소식을 들으려고 웹페이지를 감시하고 있었습니다. 아 그런데 예약페이지를 Update Scanner로 감시해 놓으니까, 정작 보고싶은 예약가능일 변경은 잘 안 보이고, 사이트 전체 예약순위 같은 것만 보이고 그래서, 아 이럴 때 RSS가 있었으면! 하고 무척 답답했었는데요. 그래서 결국 뭔가 다른 방법이 없을까 찾다가 인터파크 티켓 공지사항에 티켓오픈 며칠 전에 공지가 올라온다는 것을 알고 저걸 변경사항 보려니 그것도 좀 그래서 예전에 까나리님 블로그에서 본 적 있는 RSS 자동 만들어주기 사이트가 생각났습니다.

게시판같은 것을 RSS로 자동으로 만들어 주는 feedity.com을 써 봤는데, 치명적인 문제가 인터파크에서는 공지사항을 <제목> 이렇게 <>로 감싸서 올리는 와중 < >를 그냥 써버려서 태그로 인식되어 feedity에서 다 잘라버리는 것입니다. 그래서 결국 제목에서 중요한 부분만 다 없어지는 효과가;; 그리고 본문 요약이 잘 안 되는지 글 내용도 이렇게 다 빈걸로 올라오고 광고만 떨렁 올라오더군요.

그래서 아 이거 재미있겠다 갑자기 호기심이 생겨서 직접 만들어보자 하고 마음을 먹었습니다. -ㅇ-; 우선 요구사항은

  • <제목> 같이 개떡같이 HTML을 써도 대충 알아듣자
  • 본문 요약을 어떻게든 만들어서 넣자. (요렇게)
  • 레이아웃이 바뀌어도 동작할 수 있게 DOM이나 HTML 레이아웃은 생각하지 말자.

로 정하고 대략적으로 실행 단계는 이렇게 정했습니다. (아마도 대부분의 자동 RSS 사이트들이 이렇게 동작하지 않을까 예상 -ㅇ-)

  • 게시판 목록이 있는 HTML을 들고 와서 링크를 모두 뽑아낸다.
  • 뽑아낸 링크들을 자기들끼리 비교해서 서로 간의 (차이) 거리를 잼. 예를 들어 숫자 1개 차이는 1점, 알파벳 1개 차이는 2점
  • 링크 간의 거리 행렬(distance matrix)을 가지고 계층적 군집화(hierarchical clustering)를 해서 떼로 만듦.
  • 여러 군집 간에서 적당한 기준으로 “게시판 글 목록” 군집을 골라 냄. (여기서는 군집 내 최대 거리, 군집의 크기, 군집 내 링크들의 본문 길이를 기준으로)
  • 골라낸 군집의 링크들의 문서를 모두 가져옴
  • 링크를 2개씩 짝지어서 HTML을 비교해서 차이점이 각 링크의 본문이라고 가정해서 뽑아냄
  • 뽑아낸 본문들과 제목 등을 이용해서 RSS 생성

그렇게 해서 autorss라는 이름으로 하나 만들었습니다. 처음엔 간단할 것 같아서 스크립트 파일 1개로 50줄 안에 끝내야지 했는데, 하다보니 모듈 import가 17개인 거대 스크립트가 돼 버렸네요 –;;

생각보다 잘 돌아네요.. ^.^;; 이제 편하게 티켓 오픈 소식을;;;
다른 RSS 제공해 주지 않는 답답한 사이트를 보고 싶을 때 한번
적용해보세요~ (아직 그렇게 소스가 일반화돼 있지 않아서 좀
고칠 부분이 많을 수도 있습니다. 다른 사이트에는 적용해 보니까 DC인사이드 갤러리에도 그런대로 잘 동작하네요. 🙂

자주 바뀌는 흩어져 있는 여러 변수를 다루는 여러 방법

파이썬 마을에 올라온 질문을 읽다가
답변을 하려고보니, 파이썬을 처음 접하는 분들이 빈번하게 궁금해 하시는 문제인 것 같아서,
좀 더 깊게 후벼파서 글로 만들어 봅니다.

질문의 요지는 아래 소스에서 a~f까지 딕셔너리를 임의로 섞고 싶은데 목록이 많을 수도 있고
자주 바뀌기도 하니까 좀 더 좋은 방법이 없을까 하는 것입니다.

이거랑 완전히 똑같은 상황이 자주 일어나지는 않겠지만, 그래도 종종 처음엔 네임스페이스에
변수를 왕창 넣어놓고 이걸 어떻게 해보고 싶은 경우가 있긴 하니까 그래도 파이썬 프로그램들이
자주 사용하는 패턴들로 해결해 보겠습니다.

[1] 정면승부! 네임스페이스 직접 접근해서 거시기하기

첫 번째로는 원래 프로그램 자체는 전혀 안 건드리고 그냥 원하는 작업만 하는 방법입니다.
(변수 개수는 소스코드 길이를 줄이려고 3개로 줄였습니다.)
shufflelocaldicts()를 호출하면 바깥 프레임에 접근해서 바깥 네임스페이스의 딕셔너리를 모두
가져다가 섞은 다음에 다시 넣어줍니다.
이건 고칠 부분이 줄기는 하지만, 모든 하이테크 방법들이 그렇듯
깨지기도 쉽고 사용하는 사람들이 제대로 알지 않으면 엉뚱하게 흘러갈 수도 있는 잠재적 위험성이 있습니다.

[2] 구차하더라도 열심히 고치기

두 번째 방법으로 바깥 네임스페이스를 검색하는 흑마법을 쓰지 않고 일일이 등록해주는 것이
있습니다. 이 방법은 일일이 등록해야한다는 것이 약간 중복의 냄새도 있긴 하지만, 단순하고
잘 작동하고 명시적이라서 잘 보인다는 점에서 상당히 자주 사용되는 패턴입니다. 그렇지만 역시
이 경우에는 그다지 썩 좋지는 않네요.

[3] 좀 머리를 굴려보자

이번에는 노장 프로그래머들이 동적 언어들이 그렇게 활발하기 전에 예전에 자주 사용했던 방법으로,
태그를 보고 코드를 자동생성하는 방법입니다. 요새도 전혀 사용되지 않는 것은 아닌데, 프로그램이
변경될 때마다 스크립트를 한 번씩 실행해 주면 자동으로 소스의 주석을 보고 [] 사이의 빈칸을 채워줍니다.
이 기법은 파이썬 프로그램보다는 C프로그램에서 보통 유용하게 쓰이는데요,
cog
같은 툴들을 쓰면 좀 더 간편하게 할 수 있습니다. 이건 뭐 대체로 잘 작동하기는 하지만, 어쩌다
소스코드 업데이트가 빠지면 재앙이 생기기도 하고, 그다지 멋지지 않다는게 좀 흠입니다. 주석에 의존한다는게
특히 좀 찝찝하죠. -o-

[4] 객체지향 좀 배운 사람인 척 티내보기

앞에서 썼던 방법들은 직관적이고 단순하기는 해도
역시 너무 무식한 방법같은 냄새가 납니다.
이번엔 파이썬에서 객체 꽁수를 배우고 한참 기분낼 때 아주 재미있게 하는 객체 오버라이딩으로
위임(proxy) 객체 만들어주기입니다. 대형 프로젝트에서는 이런 스타일을 종종 사용하기도 하지만,
짧은 스크립트에서 쓰면 좀 격에 안 맞기는 하죠. 직접 딕셔너리를 만들어서 그걸 어쩌고 저쩌고하는
대신에 리스트에 원래 걸 넣어두고 그 첫번째, 두번째~ 등을 간접적으로 작업을 지원해 주도록 하는 방법입니다.
이 방법은 shuffle이 매우 빠른 게 장점이고, 참조가 리스트 하나 안에 모여서 깔끔하게 정리가 돼 있는게
좋습니다. 그런데 문제는 역시 위임이 중간에 거치기 때문에 속도상 불이익이 있고, 위임을 제대로 하려면
위 소스보다 훨씬 길게 짜야 한다는 거겠죠.

[5] 딕셔너리들을 모두 관리하는 오버마인드

이번엔 딕셔너리 자체를 상속받아서, 2번에서처럼 따로 등록하는 대신 딕셔너리 초기화 도중에
자동으로 등록되게 하고, 4번처럼 위임을 구질구질하게 하지 않고도 자체가 그냥 딕셔너리가 되게 했습니다.
요것도 어느 정도 장점이 있긴 하지만, 역시 딕셔너리를 만들 때 마다 일일이 캐스팅을 해 줘야하고,
원래 객체의 참조를 건드리려면 역시 이름 없이는 할 수 없기 때문에, 참조를 놔둔채로 내용을 바꾸기 위해서
내용을 싹 비워서 다른데 옮겼다가 다시 부어주는 좀 심각하게 비싼 작업이 들어가는게 단점입니다.

[6] 억지로 구겨넣지 말고 원래 모양을 바꿔보자

앞에서 썼던 여러 구질구질한 방법들은 결국 네임스페이스에 흩어져 있는 것들을 어떻게든
관리를 하려다보니 생기는 문제입니다. 그냥 네임스페이스에 흩어지지 않게 따로 모아두면
결국 그렇게 고생 안 해도 간단하게 해결됩니다. 굳이 __dict__를 쓰지 않더라도 그냥 리스트에
번호붙여서 넣어서 쓰거나, 다양한 깔끔한 방법이 네임스페이스에 흩어놓는 것만 포기하면
마구 생겨납니다.

결국은!

이 경우에 우선 문제를 해결하려다보면 앞에서 소개해 드렸던 다양한 방법으로 억지로 해결할 수도 있습니다.
다 만들어 놓은 프로그램을 막판에 약간 어떻게든 고쳐서 출시를 해야하는 경우나, 당장 여자친구가
얼른 안 오면 삐진다고 문자를 수십통을 보내고 있는데 과장님은 얼른 고쳐내라고 옆에서 1분마다 보채고 있을 때
뭐 이런 극한 상황에서나 얼른 쓰고 도망갈 때 쓸만한 방법이겠죠;

역시 이 문제의 경우에는 질문 자체의 요구사항을
파이썬에서 쉽게 해결할 수 있는 방법으로 바꾸는 게 중요합니다. 딕셔너리 여러개를 마구 섞는 문제라고 최종 문제를
보면 상상력의 한계가 있지만, 그것보다 원초적으로 다뤄야하는 문제를 보면 딕셔너리를 여러개 마구 섞는게
아니라 간단하게 해결할 수 있는 다른 자료구조가 반드시 있을 것 같은 예감이 강렬하게 드는군요. -O-; (그리고 마지막으로 하나 덧붙이고 싶은 것은, 생각보다 원래 질문의 코드도 보기에는 좀 그렇더라도 복잡한 방법을 안 썼다는 점에서 그런대로 쓸만한 코드입니다. 물론 문제 자체를 바꾸는게 더 좋을 것 같긴 하지만요;)