안녕하세요 코드사기꾼입니다. 저번 강의에 이어서오늘은 다른 사이트를 크롤링해보는 시간을 갖도록 하겠습니다. 오늘의 대상 사이트는 각종 대회 및 공모전이 등록되는 사이트인 씽굿(ThinkGood)입니다.항상 공모전은 하고 싶은데 매일 찾아보기는 귀찮잖아요? 하지만 공모전은 타이밍이라 자주 모니터링 하지 않으면 적절한 타이밍에 등록을 하지 못할 수도 있습니다. 공모전의 내용을 크롤링해서 띄워주는 프로그램이 있다면 굉장히 유요하게 쓰일 수 있겠죠?
1. 사이트 구조파악
크롤링을 하기에 앞서 가장먼저 선행되어야 할 것이 무엇이냐고 물어보면 저는 사이트 구조파악이라고 말할 것입니다. 사이트에 관한 구조를 모르면 원하는 url을 순환하면서 크롤링을 할 수 없을 뿐만 아니라 원하는 div에서원하는 콘텐츠를 크롤링해올 수 없기 때문이죠 씽굿에 접속해서게임/소프트웨어공모전으로 들어가 봅니다. 사이트 링크: https://www.thinkcontest.com/Contest/CateField.html?c=12
오늘은 간단하게 크롤링 봇을 만들거라서게임/소프트웨어 공모전1페이지에 노출되어있는 공모전만 파싱하도록 하겠습니다. 공모전 분류별, 페이지별로 파싱해오고 링크 및 이미지를 파싱하는 방법에 대해서는 다음에 다시 업로드하도록하겠습니다.
개발자도구(f12)를 켜서 가장 첫번째 공모전의 태그를 확인하겠습니다. a태그로 감싸져 있는데요 이 div의 하위 태그로 구성되어 있는 것을 확인 할 수 있습니다. div클래스는contest-title special이네요 그런데 special이라는 것은 special 아이콘이 붙은 공모전에만 들어가는 클래스이기 때문에 모든 공모전을 파싱하려면 저대로 파싱하면 아래와 같은 결과가 나옵니다.
그러면 모든 공모전을 파싱하려면 어떻게 해야할까요? 일반적인 공모전이 담겨있는 div의 클래스명을 확인해보겠습니다.
일반 공모전
일반공모전은 contest-title이라고 되어있습니다. 그러면 클래스 이름에 contest-title이라고 적으면 될까요?
네 그것도 됩니다.왜냐하면 BeautifulSoup은 정규표현식처럼 일정부분 맞게 들어가는 클래스명은 참이라고 판단하기 때문입니다. 하지만 오늘은 다른 방법을 알려드리고자 하기 때문에 새로운 방식으로 시도해보도록 하겠습니다. 먼저 정규표현식 라이브러리인 re를 import할것입니다. 그리고 정규식을 컴파일 하기위해 re.compile함수를 사용하겠습니다. 그러면 정규표현식은 어떻게 구성하면 될까요? contest-title을 포함하고 뒤에 스페셜을 있어도 되고 없어도 된다고 명시하면 될 것 같습니다.
상속은 사전적 정의에 따르면 부모나 친족적 관계에 있는 사람의 유산을 물려 받는 제도입니다. 클래스에서의 상속은 부모의 유산을 자식이물려 받듯이 부모 클래스의 멤버와 메소드를 자식 클래스가 물려받을 수 있습니다. 이런 경우는 흔히 있습니다. 예를 들어 라이브러리를 제작할 때 특정 자료구조를 만들어서 모든 클래스가 이 자료구조를 이용하게 하고 싶다면 클래스의 상속을 이용하게 하면 됩니다. 추가적으로 파이썬에서 기본 제공되는 자료형 또한 클래스이기 때문에 자신만의 독특한 자료형을 만들 수 도 있겠죠.
상속을 이해하고자 할 때 가장 쉬운방법은 기존의 클래스를 이용하되, 내가 원하는 멤버와 메소드를 추가하는 것으로 이해 하는 것입니다.
클래스의 상속
먼저 총이라는 간단한 클래스가 있다고 가정해 보겠습니다. 클래스라는 것은 유형, 무형으로 존재하는 어떤 것을 코드로 나타내는 것입니다. 그러면 총(Rifle)이라는 객체는 파괴력, 탄창, 현재 남은 총알 등의 속성을 가지고 있을 테고, 기능으로는 장전이나 발사가 있을 수 있습니다.
이 클래스는 Rifle입니다. 제가 앞서 언급한 대로 생성자에 탄창, 남은 총알, 파괴력등의 요소를 만들었습니다. 또한 상속을위해 각 클래스멤버의 property와 setter를 작성하여 직접 멤버변수에는 접근하지 못하지만, 메소드를 통하여 가능하게 구현하였습니다. 탄창(Mag)은 처음 인스턴스 생성 이후 오염을 방지하기위해 setter에서 제외했습니다. Rifle클래스의 메소드로는 총이 실제로 가지고있는 기능인 발사(Shoot), 장전(Reload) 등을 포함 시켰습니다. 같은 클래스 안에서는 property나 setter를 이용하여 멤버에 접근할 필요가 없기때문에 직접접근하는 방식으로 구현하였습니다.(장전과 발사에 있는 self.__leftMag)
만약 총이라는 클래스를 상속받아 저격총이라는 클래스를 만들고자 하면 총이 가지고 있는 속성은 그대로 유지할 것입니다. 하지만 총이라는 클래스에는 망원경이라는 요소가 없기 때문에 속성을 하나 추가하고 망원경 조준이라는 기능을 추가해야겠죠. 그런 의미에서 멤버 변수에 Zoom을 추가하였고 메소드로는 increaseAtk을 넣어 Zoom과 파괴력을 곱해 다시 파괴력에 저장하는 코드를 작성하였습니다.
Rifle 클래스에 정의되어 있는 내용은 잘 동작하는 것을 확인하였습니다. rifle을 상속받은 sniper도 잘 동작하는 것을 확인 할 수 있습니다.
이번에는 sniper클래스의 고유 기능을 테스트 해보도록 하겠습니다.
제가 의도한 대로 잘 동작하고 있습니다. atk는 부모클래스의 멤버이면서 property지만 setter를 같이 작성했기 때문에 sniper에서 접근하고 같을 변경시킬 수 있었습니다. public 하게 구현하면 사실 이런 고생은 안해도 됩니다. 하지만 객체지향 프로그래밍에서는 getter setter를 제외하고는 클래스 멤버에대한 외부 클래스의 접근을 금하고 있기때문에 property 설정을 꼭 하셔야 합니다.
2. 오버라이딩
총과 저격총 사이에는 명확하지 않지만 가끔씩 상속받은 클래스가 부모의 기능을 똑같이 가지고 있지만 구현 방법이 다를 때가 존재합니다. 이런 경우에는 같은 이름의 메소드를 작성하고 다른 기능을 수행하게 해야합니다. 예를 들어 산탄총의 경우를 생각해보겠습니다. 일반 총은 발사당 1개의 총알이 소비되지만 산탄총은 3발이 나간다고 칩시다. 산탄총도Shoot이라는 메소드가 당연히 필요하지만 부모 클래스의 Shoot과 다르게 동작해야 되겠죠? 파이썬에서는 부모 클래스의 메소드와 같은 이름의 메소드를 자식 클래스에 작성하여 부모 클래스의 메소드를 덮어버리는 방법이 있습니다. 이를 우리는 오버라이딩이라고 합니다.