ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Azure Functions로 네이버 인기 검색어 주기적으로 크롤링하기
    IT/딥러닝(기타) 2017. 11. 20. 23:05


    Azure Functions이란 Microsoft에서 선보인 Serverless Architecture이다. 여기서 말하는 Serverless Architecture란 응용프로그램이 third-party 서비스(Baas or Faas)에 의존하여 구동되는 것을 의미한다. 그러나 Serveless라고 해서 정말로 서버가 없는 것은 아니다. "Serverless Computing"은 back-end 코드를 돌리기 위해서 서버를 구매하거나 빌리지 않고도 서버를 구동할 수 있도록 하기 위해 만든 것이다.


    나는 이 포스팅에서 Azure Functions를 활용하여 매분마다 네이버를 클롤링해 DB에 저장하는 함수를 만들어 볼 것이다.


    Azure Functions는 C#코드를 원활하게 구동시키는 반면, 파이썬은 Experimental로 아직 성능이 엄청 뛰어나진 않다. 기본 파이썬은 파이썬2이며, 파이썬3도 손쉽게 설치하여 사용할 수 있다.

    파이썬 실행도 3초 정도 소요될 뿐이어서, 쓸만한 편에 속한다고 볼 수 있다. 

    또한, Azure는 GUI를 제공해서 모니터링하고 스케쥴링하는 데에 아주 간편하다.


    Azure 가입

    Azure를 사용은 원래 유료지만, 첫 가입시 12개월 동안 제품들을 무료로 사용할 수 있고, 첫 달에 24만원 상당의 크레딧을 제공한다.(AWS의 Free Tier와 유사)

    https://azure.microsoft.com/ko-kr/free/

    가입시에 신용카드 정보를 입력하지만 이는 확인을 위한 것일 뿐이라고 한다. 유로회원 등록과정은 아니다. 유료회원은 구독란에 "종량제"라고 표시된다고 한다.



    계정을 만들었다면, 기능 앱(Function App)을 만들어야한다. 기능 앱은 아래의 그림에서 보이는 것과 같이 '새로 만들기'를 클릭한 후, 검색란에 '기능'을 입력하면 나오는 '기능 앱'을 클릭하여 만들 수 있다.



    '기능 앱'을 클릭을 하면, 아래의 그림과 같은 기능 앱의 스펙을 결정할 수 있다.

    1. '앱 이름'에 원하는 앱 이름을 입력한다.

    2. '구독'에 무료 체험을 선택한다.

    3. '리소스 그룹'은 관리 목적의 논리적 그룹으로 앱 이름과 같은 이름을 지정한다.

    4. '호스팅 계획'

      • 사용 계획: 쓴 만큼 과금 (월 1백만번까지 무료) -> 대신 조금 느리다. 

      • App Service계획 ->이걸 선택

        • 기존에 사용 중인 App Service 플랜 공유가 가능하다. 추가 과금이 없다.

        • 성능을 올릴 수 있다.

    5. 'App Service 계획/위치'

      • 새로 만들기

      • 위치: 데이터센터 위치. Korea Center(서울) 혹은 Korea South(부산)을 선택한다.

      • 가격 책정 계층: S1 표준 선택

    6. 위치: Korea가 없다면, 차선책으로 Japan East를 선택한다.

    7. 저장소: Azure Storage는 단순 정적 파일 저장소(Blob) 뿐만 아니라, NoSQL저장소 역할도 한다. Function App을 위한 각종 세팅/스케줄링 정보를 담는다.

      • 앱 이름과 유사하게, 새로 만들어 보도록 한다. 이름에 소문자/숫자만 사용가능하다.

    8. Application Insights: Application Insight는 App에 대한 여러 metric 등의 정보를 흭득 가능하다.

      • 위치: 아무 곳이나 괜찮다.

    9. 대시보드에 고정: 체크

    10. 만들기: 클릭



    기능 앱을 무사히 만들었다!!

    이제 이 기능 앱에서 새 함수를 만들어 보겠다.

    1. '함수' 클릭
    2. '새 함수' 클릭



    1. '언어'를 Python으로 선택한다.

    2. 'HttpTrigger - Python'을 선택

    3. '함수 지정 이름'에 Crawler(원하는 이름 아무거나)를 입력

    4. 만들기



    만들기를 완료하면, Crawler라는 함수 안에 기본적으로 다음 과 같은 코드가 작성되어 있는 것을 볼 수 있다.

    import os
    import json

    postreqdata = json.loads(open(os.environ['req']).read())
    response = open(os.environ['res'], 'w')
    response.write("hello world from "+postreqdata['name'])
    response.close()

    이 코드는 http의 POST에 대한 response관련 코드이다. '실행'버튼을 누른다.
    HTTPie를 통해 새로 생성된 함수를 호출해 볼 수 있다.(httpie.org에서 프로그램 다운로드 or Try Online으로 test가능)


    그러나, 우리는 http POST에 대한 반환 값을 주는 포그램을 만드련는 것이 아니다. 우리는 일정 시간마다 네이버 인기 검색어를 크롤링할 것이다.
    이를 위해서는, '통합'을 선택해서, 기존의 'HttpTrigger'를 삭제하고 Timer Trigger를 새로 생성한다. 여기서 Trigger란 기능 앱의 실행 주체를 의미한다.
    Azure Function은 Trigger외에도 Binding을 제공하는데, 여기서의 Binding이란 Azure 서비스에 대한 읽기/쓰기로 별도의 라이브러리 설치 없이도,
    File-like I/O로 읽기/쓰기 지원을 한다는 이야기이다.



    타이머 Trigger를 만들면 아래와 같은 타이머 Trigger에 대한 정보가 보인다.

    여기서 '일정'이란 리눅스의 cron 포맷과 유사하다.

    • 초 분 시 일 월 day-of-week
      • 0 0 */2 * * *: 매일 두시간마다
      • 0 0 9-18 * * *: 매일 9시 부터 18시까지의 매 정시
      • 0 30 9 * * 1-5: 매 주중 9시 30분마다
    • UTC 시간이 기준으로 사용된다. 다른 시간대를 사용하려면, App Settings에 WEBSITE_TIME_ZONE 환경변수를 설정한다.



    타이머 설정이 완료되면, 이제 앞서 작성된 코드가 매분마다 실행된다. 하지만, 기존의 코드는 http request에 응답하는 코드이므로 무의미해졌다.
    그래서, 코드를 다 지우고 print("hello world")를 작성하여 실행해 보면, 매 분마다 hello world가 로그로 출력되는 것을 확인할 수 있게된다.
    2017-11-20T12:53:38  Welcome, you are now connected to log-streaming service.
    2017-11-20T12:53:49.934 Function started (Id=ffab910e-a2ed-4f75-8a33-c191e3fccca7)
    2017-11-20T12:53:50.122 hello world
    2017-11-20T12:53:50.142 Function completed (Success, Id=ffab910e-a2ed-4f75-8a33-c191e3fccca7, Duration=207ms)
    2017-11-20T12:54:00.006 Function started (Id=4e04efb2-a7b9-46a5-a079-4da52101cc9e)
    2017-11-20T12:54:00.100 hello world
    2017-11-20T12:54:00.136 Function completed (Success, Id=4e04efb2-a7b9-46a5-a079-4da52101cc9e, Duration=131ms)
    2017-11-20T12:55:00.022 Function started (Id=8c4a47a9-c7b1-4056-984d-11a7050308ef)
    2017-11-20T12:55:00.117 hello world
    2017-11-20T12:55:00.132 Function completed (Success, Id=8c4a47a9-c7b1-4056-984d-11a7050308ef, Duration=117ms) 
    


    타이머가 잘 작동하니, 이제는 크롤링한 데이터를 저장할 데이터베이스를 만들어볼 것이다.

    화면의 좌측에서 '저장소 계정'을 클릭한 후, 초기에 생성했던 저장소를 클릭한다.



    다음 이런 화면이 나오면, 테이블을 클릭하도록 한다.



    새로운 테이블을 추가하기 위해여 '+테이블'을 클릭한 후, 테이블 이름을 입력한 후 '확인'버튼을 클릭한다.



    DB를 만들었으니 Crawler 함수의 출력이 DB에 연결되도록 출력관련 설정을 아래의 그림과 같이 변경한다.



    • 테이블 매개변수 이름: tablePath(파이썬 코드 내에서 참조할 환경변수 명)
    • 테이블 이름: crawlerTable(생성한 테이블명)
    • 저장소 계정연결: AzureWebJobDashboard와 AzureWebJobStorage는 동일한 저장소 설정이다. 후자를 선택해보도록 한다.



    이렇게 새로운 DB(NoSQL)가 만들어 졌다. 

    Azure Table에 Insert하기 위해서는 아래와 같은 형태의 코드를 사용할 수 있다.(예시)

    import os
    import json

    partition_key = 'my_partition_key'
    row_key = 'my_row_key'
    custom_column1 = ''
    custom_column2 = []

    doc = {
    'PartitionKey': partition_key,
    'RowKey': row_key,
    'custom_column1': custom_column1,
    'custom_column2': custom_column2,
    }

    tablePath = os.environ['tablePath']
    with open(tablePath, 'wb') as f:
    json.dump(doc, f)

    • 모든 레코드는 다음 3가지를 가진다.
      • PartitionKey: 최대 1KB 문자열(필수)
      • RowKey: 최대 1KB크기의 문자열(필수)
      • Timestamp: 자동 지정
    • PartitionKey와 RowKey를 조합하여, 각 레코드를 식별한다.
    • 지원 타입: byte[], bool, DateTime, double, Guid, Int32, Int64, String


    DB까지 완성했으니, 우리는 크롤링 코드를 작성하여 매분 마다 인기 검색어를 크롤링해, DB에 저장하도록 하겠다.
    다시 함수의 코드 부분에 돌아가, 다음과 같은 코드를 작성한다.
    import os
    import json
    import time
    import requests
    from bs4 import BeautifulSoup


    def get_realtime_keywords():
    html = requests.get('https://www.naver.com/').text
    soup = BeautifulSoup(html, 'html.parser')

    tags = soup.select('.PM_CL_realtimeKeyword_rolling_base .ah_k')
    keywords = [tag.text for tag in tags]

    return keywords


    def insert(partition_key, row_key, **kwargs):
    doc = dict(
    PartitionKey=partition_key,
    RowKey=row_key,
    **kwargs)

    tablePath = os.environ['tablePath']
    with open(tablePath, 'wt', encoding='utf8') as f:
    json.dump(doc, f)


    if __name__ == '__main__':
    keywords = get_realtime_keywords()
    insert('naver_realtime_keywords', int(time.time()),
    keywords=keywords)


    위 코드를 실행하면, 아래와 같은 에러가 발생한다. 그 이유는 requests/BeautifulSoup4 라이브러리가 설치되어있지 않기 때문이다.
    2017-11-20T13:41:08.784 Function started (Id=930cb6dd-02b3-44c4-8344-f50537dab8a1)
    2017-11-20T13:41:09.081 Exception while executing function: Functions.Crawler. Microsoft.Azure.WebJobs.Script: Traceback (most recent call last):
      File "D:\home\site\wwwroot\Crawler\run.py", line 4, in <module>
        import requests
    ImportError: No module named requests
    .
    2017-11-20T13:41:09.096 Function completed (Failure, Id=930cb6dd-02b3-44c4-8344-f50537dab8a1, Duration=298ms)


    이러한 문제를 해결하기 위해, 파이썬3(3.5)을 설지하고 필요한 패키지를 설치해야한다.
    우선 '플랫폼 기능'에서 'KUDU'를 클릭한다.



    그 다음, 'debug console'에서 'CMD'를 클릭한다.



    nutget에서 지원하는 파이썬3.5를 설치한다.
    아래의 2가지 명령어를 하나씩 CMD에 입력하면 모든 Function App은 d:\home\site\tools\python을 통해 실행된다.
    nuget.exe install -Source https://www.siteextensions.net/api/v2/ -OutputDirectory D:\home\site\tools python352x64
    mv /d/home/site/tools/python352x64.3.5.2.6/content/python35/* /d/home/site/tools/

    파이썬3을 설치하였으므로, 파이썬3을 활용해 필요한 패키지를 설치하도록 한다. 참고로 beatifulsoup4는 크레이핑(크롤링)에 유용한 모듈이다.
    d:/home/site/tools/python -m pip install requests beautifulsoup4

    설치과정이 끝났으면 KUDU를 닫도록 한다.

    다시 아까의 코드로 돌아와 실행을해보면, 다음과 같이 정상실행 되는 모습을 볼 수 있다. 아래의 로그를 보고있으면, 타이머에 의해 함수가 호출된다는 것을 확인할 수 있다.
    2017-11-20T13:57:53.667 Function started (Id=bfb48b60-12fa-4b87-90fb-baa55fc7b6d4)
    2017-11-20T13:57:55.883 Function completed (Success, Id=bfb48b60-12fa-4b87-90fb-baa55fc7b6d4, Duration=2220ms)
    2017-11-20T13:58:00.027 Function started (Id=4bb7ca0f-008f-4d06-8e8c-5578643d39b6)
    2017-11-20T13:58:01.926 Function completed (Success, Id=4bb7ca0f-008f-4d06-8e8c-5578643d39b6, Duration=1904ms)
    2017-11-20T13:59:00.020 Function started (Id=bc8506b2-cd41-4564-af9a-200dc8ca1a82)
    2017-11-20T13:59:02.461 Function completed (Success, Id=bc8506b2-cd41-4564-af9a-200dc8ca1a82, Duration=2448ms)

    DB에 결과가 잘 저장되는지 확인하고 싶다면, 아래의 주소에서 저장소 탐색기를 다운받아서, Azure 계정으로 로그인 하면 DB를 확인할 수 있다.





    'IT > 딥러닝(기타)' 카테고리의 다른 글

    Content-based Filtering과 Collaborative Filtering  (0) 2017.11.12

    댓글

Designed by Tistory.