http://newspaper.readthedocs.io/en/latest/


각 언론사의 url을 GET하여 부동산뉴스를 보아보고 있습니다.

url만 바꿔서 아주 간단하게 뉴스기사를 가져오고

>>> from newspaper import Article >>> url = 'http://fox13now.com/2013/12/30/new-year-new-laws-obamacare-pot-guns-and-drones/' >>> article = Article(url)
>>> article.download()
>>> article.parse()

 자연어 처리 실행시키고

>>> article.nlp()

키워드를 뽑아주고 요약도 해줍니다.

>>> article.keywords
['New Years', 'resolution', ...]

>>> article.summary
'The study shows that 93% of people ...'

한글도 그럭저럭 해줍니다. (네이버 뉴스 요약해주는 서비스랑 비슷하거나 조금 떨어지는 수준)


12개 정도의 언론사의 오피니언, 부동산을
오늘의 주요 키워드 뽑아서 보는데 일부 키워드 예외처리만 하면 볼만합니다.






Herokuapp을 이용해서 시험삼아 제가 만든 시험 서비스 사이트가 있었습니다.

Django와 웹 스크랩핑을 기법을 이용해서 만들었는데

한동안 잊고 있다가 오랜만에 들어가서 로그인을 시도하니 에러가 발생합니다.

참고로 제가 만든 사이트의 로그인 방식은 로그인 하려는 사용자의 이메일 주소를 입력 받아서

1회용 로그인 URL 링크를 회신해서 보내줍니다.

이 과정에서 일단은 무료로 하려다보니 Gmail을 사용하고 있습니다.


SMTP Authentication Error

딱 봐도 메일 접근 권한 문제 같아 보입니다.

권한 해결하려고 보니 간단합니다.



아래 링크에가서 엑세스 허용만 해주면 문제 해결됩니다.
https://accounts.google.com/DisplayUnlockCaptcha


  1. 팽펑 2019.12.24 16:53 신고

    낮은 보안의 앱 허가만 열어주면 되는 줄 알았는데 이런 과정이 숨어있었네요. 감사합니다.

url 정보를 세팅하고 이에 대해서 request 요청하면 응답 정보를 주는데

http://openapi.molit.go.kr:8081/OpenAPI_ToolInstallPackage/service/rest/RTMSOBJSvc/getRTMSDataSvcAptTrade?LAWD_CD=11440&DEAL_YMD=201801&serviceKey=###SERVICE_KEY###



얼마전에 수정이 있었는지
응답되는 정보가 변경되었습니다.

    req = urllib.request.Request(request_url)
    try:
        res = urllib.request.urlopen(req)
    except UnicodeEncodeError:
        print('[OpenAPI] UnicodeEncodeError')
        return


    data = res.read().decode('utf-8')
    soup = BeautifulSoup(data, 'html.parser')
    if (soup.resultcode.string != '00'):
        print('[OpenAPI] ',  soup.resultmsg.string)
        return

    items = soup.findAll('item')
    print(items)


가져온 정보를 보니 주석과 <, > 정보들이 섞여 있었습니다.

<item>&lt;거래금액&gt;    83,000<!--거래금액-->&lt;
건축년도&gt;2005<!--건축년도-->&lt;년&gt;2018<!--년-->&lt;
법정동&gt; 상암동<!--법정동-->&lt;아파트&gt;상암월드컵파크6단지<!--아파트-->&lt;
월&gt;1<!--월-->&lt;일&gt;11~20<!--일-->&lt;전용면적&gt;104.32<!--전용면적-->&lt;
지번&gt;1689<!--지번-->&lt;지역코드&gt;11440<!--지역코드-->&lt;층&gt;6<!--층--></item>


기존 코드를 수정해서 text 정보만 가져왔습니다.

item = item.text

HTML 태그들이 없어졌습니다.

<거래금액>    83,000<건축년도>2005<년>2018<법정동> 상암동<아파트>상암월드컵파크6단지<월>1<일>11~20<전용면적>104.32<지번>1689<지역코드>11440<층>6


이걸 다시 파싱하려니 정규표현식을 사용해야 했습니다.
결과만 보면 간단합니다.

split_item = re.split('<.*?>', item)


이렇게 하고나니 List형으로 잘 분리합니다.

['', '    83,000', '2005', '2018', ' 상암동', '상암월드컵파크6단지',
'1', '11~20', '104.32', '1689', '11440', '6']


  1. 이재성 2019.10.14 00:11

    비슷한 문제를 겪고 있는데 몇일째 삽질을해도 방법을 못찾겠어요ㅜ.ㅜ 팁 좀 부탁드립니다.

    import requests
    from bs4 import BeautifulSoup
    import pandas as pd

    url = "http://openapi.molit.go.kr:8081/OpenAPI_ToolInstallPackage/service/rest/RTMSOBJSvc/getRTMSDataSvcAptTrade?serviceKey=KrKzQ4sxQDVnTpdt3X3p8Hi9nZPr5KnsS%2FkKe%2FxVPYbY7cK6NfPtsvJ3%2FoSiJNlK7u2Q8geu1UmUmQQKmZ9f3w%3D%3D&LAWD_CD=11110&DEAL_YMD=201812"

    response = requests.get(url)
    soup = BeautifulSoup(response.content, 'html.parser')

    ItemList = soup.findAll('item')
    print(ItemList)



    결과는
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <response>
    <header>
    <resultcode>
    00
    </resultcode>
    <resultmsg>
    NORMAL SERVICE.
    </resultmsg>
    </header>
    <body>
    <items>
    <item>
    &lt;거래금액&gt; 23,500
    <!--거래금액-->
    &lt;건축년도&gt;2003
    <!--건축년도-->
    &lt;년&gt;2018
    <!--년-->
    &lt;법정동&gt; 익선동
    <!--법정동-->
    &lt;아파트&gt;현대뜨레비앙
    <!--아파트-->
    &lt;월&gt;12
    <!--월-->
    &lt;일&gt;8
    <!--일-->
    &lt;전용면적&gt;36.08
    <!--전용면적-->
    &lt;지번&gt;55
    <!--지번-->
    &lt;지역코드&gt;11110
    <!--지역코드-->
    &lt;층&gt;7
    <!--층-->
    </item>
    <item>
    &lt;거래금액&gt; 20,000
    <!--거래금액-->
    &lt;건축년도&gt;2014
    <!--건축년도-->
    &lt;년&gt;2018
    <!--년-->
    &lt;법정동&gt; 연건동
    <!--법정동-->
    &lt;아파트&gt;이화에수풀
    <!--아파트-->
    &lt;월&gt;12
    <!--월-->
    &lt;일&gt;18
    <!--일-->
    &lt;전용면적&gt;16.98
    <!--전용면적-->
    &lt;지번&gt;195-10
    <!--지번-->
    &lt;지역코드&gt;11110
    <!--지역코드-->
    &lt;층&gt;7
    <!--층-->
    </item>
    <item>
    &lt;거래금액&gt; 45,500
    <!--거래금액-->
    &lt;건축년도&gt;2004
    <!--건축년도-->
    &lt;년&gt;2018
    <!--년-->
    &lt;법정동&gt; 혜화동
    <!--법정동-->
    &lt;아파트&gt;혜화훼미리
    <!--아파트-->
    &lt;월&gt;12
    <!--월-->
    &lt;일&gt;3
    <!--일-->
    &lt;전용면적&gt;60.82
    <!--전용면적-->
    &lt;지번&gt;20-12
    <!--지번-->
    &lt;지역코드&gt;11110
    <!--지역코드-->
    &lt;층&gt;7
    <!--층-->
    </item>
    <item>
    &lt;거래금액&gt; 26,800
    <!--거래금액-->
    &lt;건축년도&gt;2002
    <!--건축년도-->
    &lt;년&gt;2018
    <!--년-->
    &lt;법정동&gt; 창신동
    <!--법정동-->
    &lt;아파트&gt;MID그린(4동)
    <!--아파트-->
    &lt;월&gt;12
    <!--월-->
    &lt;일&gt;20
    <!--일-->
    &lt;전용면적&gt;59.55
    <!--전용면적-->
    &lt;지번&gt;601-5
    <!--지번-->
    &lt;지역코드&gt;11110
    <!--지역코드-->
    &lt;층&gt;7
    <!--층-->
    </item>
    <item>
    &lt;거래금액&gt; 78,700
    <!--거래금액-->
    &lt;건축년도&gt;2009
    <!--건축년도-->
    &lt;년&gt;2018
    <!--년-->
    &lt;법정동&gt; 숭인동
    <!--법정동-->
    &lt;아파트&gt;종로청계힐스테이트
    <!--아파트-->
    &lt;월&gt;12
    <!--월-->
    &lt;일&gt;21
    <!--일-->
    &lt;전용면적&gt;84.9478
    <!--전용면적-->
    &lt;지번&gt;766
    <!--지번-->
    &lt;지역코드&gt;11110
    <!--지역코드-->
    &lt;층&gt;9
    <!--층-->
    </item>
    <item>
    &lt;거래금액&gt; 65,000
    <!--거래금액-->
    &lt;건축년도&gt;2009
    <!--건축년도-->
    &lt;년&gt;2018
    <!--년-->
    &lt;법정동&gt; 숭인동
    <!--법정동-->
    &lt;아파트&gt;종로청계힐스테이트
    <!--아파트-->
    &lt;월&gt;12
    <!--월-->
    &lt;일&gt;26
    <!--일-->
    &lt;전용면적&gt;59.9426
    <!--전용면적-->
    &lt;지번&gt;766
    <!--지번-->
    &lt;지역코드&gt;11110
    <!--지역코드-->
    &lt;층&gt;2
    <!--층-->
    </item>
    <item>
    &lt;거래금액&gt; 24,300
    <!--거래금액-->
    &lt;건축년도&gt;1997
    <!--건축년도-->
    &lt;년&gt;2018
    <!--년-->
    &lt;법정동&gt; 숭인동
    <!--법정동-->
    &lt;아파트&gt;도시그린빌라트19
    <!--아파트-->
    &lt;월&gt;12
    <!--월-->
    &lt;일&gt;29
    <!--일-->
    &lt;전용면적&gt;57.45
    <!--전용면적-->
    &lt;지번&gt;181-121
    <!--지번-->
    &lt;지역코드&gt;11110
    <!--지역코드-->
    &lt;층&gt;3
    <!--층-->
    </item>
    <item>
    &lt;거래금액&gt; 135,500
    <!--거래금액-->
    &lt;건축년도&gt;2009
    <!--건축년도-->
    &lt;년&gt;2018
    <!--년-->
    &lt;법정동&gt; 평창동
    <!--법정동-->
    &lt;아파트&gt;롯데캐슬 로잔
    <!--아파트-->
    &lt;월&gt;12
    <!--월-->
    &lt;일&gt;15
    <!--일-->
    &lt;전용면적&gt;190.743
    <!--전용면적-->
    &lt;지번&gt;108
    <!--지번-->
    &lt;지역코드&gt;11110
    <!--지역코드-->
    &lt;층&gt;4
    <!--층-->
    </item>
    <item>
    &lt;거래금액&gt; 90,000
    <!--거래금액-->
    &lt;건축년도&gt;2003
    <!--건축년도-->
    &lt;년&gt;2018
    <!--년-->
    &lt;법정동&gt; 평창동
    <!--법정동-->
    &lt;아파트&gt;크래스빌
    <!--아파트-->
    &lt;월&gt;12
    <!--월-->
    &lt;일&gt;15
    <!--일-->
    &lt;전용면적&gt;187.9
    <!--전용면적-->
    &lt;지번&gt;46-1
    <!--지번-->
    &lt;지역코드&gt;11110
    <!--지역코드-->
    &lt;층&gt;4
    <!--층-->
    </item>
    <item>
    &lt;거래금액&gt; 41,500
    <!--거래금액-->
    &lt;건축년도&gt;2004
    <!--건축년도-->
    &lt;년&gt;2018
    <!--년-->
    &lt;법정동&gt; 평창동
    <!--법정동-->
    &lt;아파트&gt;에지앙빌
    <!--아파트-->
    &lt;월&gt;12
    <!--월-->
    &lt;일&gt;20
    <!--일-->
    &lt;전용면적&gt;110.61
    <!--전용면적-->
    &lt;지번&gt;179-5
    <!--지번-->
    &lt;지역코드&gt;11110
    <!--지역코드-->
    &lt;층&gt;2
    <!--층-->
    </item>
    <item>
    &lt;거래금액&gt; 133,000
    <!--거래금액-->
    &lt;건축년도&gt;2009
    <!--건축년도-->
    &lt;년&gt;2018
    <!--년-->
    &lt;법정동&gt; 평창동
    <!--법정동-->
    &lt;아파트&gt;롯데캐슬 로잔
    <!--아파트-->
    &lt;월&gt;12
    <!--월-->
    &lt;일&gt;28
    <!--일-->
    &lt;전용면적&gt;190.743
    <!--전용면적-->
    &lt;지번&gt;108
    <!--지번-->
    &lt;지역코드&gt;11110
    <!--지역코드-->
    &lt;층&gt;1
    <!--층-->
    </item>
    </items>
    <numofrows>
    10
    </numofrows>
    <pageno>
    1
    </pageno>
    <totalcount>
    11
    </totalcount>
    </body>
    </response>
    [<item>&lt;거래금액&gt; 23,500<!--거래금액-->&lt;건축년도&gt;2003<!--건축년도-->&lt;년&gt;2018<!--년-->&lt;법정동&gt; 익선동<!--법정동-->&lt;아파트&gt;현대뜨레비앙<!--아파트-->&lt;월&gt;12<!--월-->&lt;일&gt;8<!--일-->&lt;전용면적&gt;36.08<!--전용면적-->&lt;지번&gt;55<!--지번-->&lt;지역코드&gt;11110<!--지역코드-->&lt;층&gt;7<!--층--></item>, <item>&lt;거래금액&gt; 20,000<!--거래금액-->&lt;건축년도&gt;2014<!--건축년도-->&lt;년&gt;2018<!--년-->&lt;법정동&gt; 연건동<!--법정동-->&lt;아파트&gt;이화에수풀<!--아파트-->&lt;월&gt;12<!--월-->&lt;일&gt;18<!--일-->&lt;전용면적&gt;16.98<!--전용면적-->&lt;지번&gt;195-10<!--지번-->&lt;지역코드&gt;11110<!--지역코드-->&lt;층&gt;7<!--층--></item>, <item>&lt;거래금액&gt; 45,500<!--거래금액-->&lt;건축년도&gt;2004<!--건축년도-->&lt;년&gt;2018<!--년-->&lt;법정동&gt; 혜화동<!--법정동-->&lt;아파트&gt;혜화훼미리<!--아파트-->&lt;월&gt;12<!--월-->&lt;일&gt;3<!--일-->&lt;전용면적&gt;60.82<!--전용면적-->&lt;지번&gt;20-12<!--지번-->&lt;지역코드&gt;11110<!--지역코드-->&lt;층&gt;7<!--층--></item>, <item>&lt;거래금액&gt; 26,800<!--거래금액-->&lt;건축년도&gt;2002<!--건축년도-->&lt;년&gt;2018<!--년-->&lt;법정동&gt; 창신동<!--법정동-->&lt;아파트&gt;MID그린(4동)<!--아파트-->&lt;월&gt;12<!--월-->&lt;일&gt;20<!--일-->&lt;전용면적&gt;59.55<!--전용면적-->&lt;지번&gt;601-5<!--지번-->&lt;지역코드&gt;11110<!--지역코드-->&lt;층&gt;7<!--층--></item>, <item>&lt;거래금액&gt; 78,700<!--거래금액-->&lt;건축년도&gt;2009<!--건축년도-->&lt;년&gt;2018<!--년-->&lt;법정동&gt; 숭인동<!--법정동-->&lt;아파트&gt;종로청계힐스테이트<!--아파트-->&lt;월&gt;12<!--월-->&lt;일&gt;21<!--일-->&lt;전용면적&gt;84.9478<!--전용면적-->&lt;지번&gt;766<!--지번-->&lt;지역코드&gt;11110<!--지역코드-->&lt;층&gt;9<!--층--></item>, <item>&lt;거래금액&gt; 65,000<!--거래금액-->&lt;건축년도&gt;2009<!--건축년도-->&lt;년&gt;2018<!--년-->&lt;법정동&gt; 숭인동<!--법정동-->&lt;아파트&gt;종로청계힐스테이트<!--아파트-->&lt;월&gt;12<!--월-->&lt;일&gt;26<!--일-->&lt;전용면적&gt;59.9426<!--전용면적-->&lt;지번&gt;766<!--지번-->&lt;지역코드&gt;11110<!--지역코드-->&lt;층&gt;2<!--층--></item>, <item>&lt;거래금액&gt; 24,300<!--거래금액-->&lt;건축년도&gt;1997<!--건축년도-->&lt;년&gt;2018<!--년-->&lt;법정동&gt; 숭인동<!--법정동-->&lt;아파트&gt;도시그린빌라트19<!--아파트-->&lt;월&gt;12<!--월-->&lt;일&gt;29<!--일-->&lt;전용면적&gt;57.45<!--전용면적-->&lt;지번&gt;181-121<!--지번-->&lt;지역코드&gt;11110<!--지역코드-->&lt;층&gt;3<!--층--></item>, <item>&lt;거래금액&gt; 135,500<!--거래금액-->&lt;건축년도&gt;2009<!--건축년도-->&lt;년&gt;2018<!--년-->&lt;법정동&gt; 평창동<!--법정동-->&lt;아파트&gt;롯데캐슬 로잔<!--아파트-->&lt;월&gt;12<!--월-->&lt;일&gt;15<!--일-->&lt;전용면적&gt;190.743<!--전용면적-->&lt;지번&gt;108<!--지번-->&lt;지역코드&gt;11110<!--지역코드-->&lt;층&gt;4<!--층--></item>, <item>&lt;거래금액&gt; 90,000<!--거래금액-->&lt;건축년도&gt;2003<!--건축년도-->&lt;년&gt;2018<!--년-->&lt;법정동&gt; 평창동<!--법정동-->&lt;아파트&gt;크래스빌<!--아파트-->&lt;월&gt;12<!--월-->&lt;일&gt;15<!--일-->&lt;전용면적&gt;187.9<!--전용면적-->&lt;지번&gt;46-1<!--지번-->&lt;지역코드&gt;11110<!--지역코드-->&lt;층&gt;4<!--층--></item>, <item>&lt;거래금액&gt; 41,500<!--거래금액-->&lt;건축년도&gt;2004<!--건축년도-->&lt;년&gt;2018<!--년-->&lt;법정동&gt; 평창동<!--법정동-->&lt;아파트&gt;에지앙빌<!--아파트-->&lt;월&gt;12<!--월-->&lt;일&gt;20<!--일-->&lt;전용면적&gt;110.61<!--전용면적-->&lt;지번&gt;179-5<!--지번-->&lt;지역코드&gt;11110<!--지역코드-->&lt;층&gt;2<!--층--></item>, <item>&lt;거래금액&gt; 133,000<!--거래금액-->&lt;건축년도&gt;2009<!--건축년도-->&lt;년&gt;2018<!--년-->&lt;법정동&gt; 평창동<!--법정동-->&lt;아파트&gt;롯데캐슬 로잔<!--아파트-->&lt;월&gt;12<!--월-->&lt;일&gt;28<!--일-->&lt;전용면적&gt;190.743<!--전용면적-->&lt;지번&gt;108<!--지번-->&lt;지역코드&gt;11110<!--지역코드-->&lt;층&gt;1<!--층--></item>]

    Process finished with exit code 0

네이버에서 제공해주는 openapi를 이용해서 카페에 글쓰기를 할 수 있다.

관련예제는 여기링크를 클릭하면 볼 수는 있다.

글쓰는 순서

1. login api를 이용해서 접근 토큰 정보를 가져온다.

2. 포스팅한다.


아래의 내용을 따라하기전에 우선 Naver openapi를 사용하기 위한

사전 준비사항을 완료해야한다. --> 링크

특히 사용 API에 카페를 반드시 추가해야한다.


순서는 간단하지만 막상 따라해보려는데 첫줄에서 막힌다.

token = "YOUR_ACCESS_TOKEN"

어떻게 받아와야되나 ??

이를 확인하기 위해서 로그인 API 명세를 찾아본다.

 

아... 나는 파이썬으로 다 하려고 했는데 없다.

하지만 뒤져보면 다 나온다.

Selenium을 이용하면 받아올 수 있다.

이와 관련된 기본적인 세팅은 이준범님의 블로그에 가면 잘 나와있으니 따라하면됨
(https://beomi.github.io/2017/02/27/HowToMakeWebCrawler-With-Selenium/)


이 정보들을 바탕으로 로그인을 한다.

아래의 코드에서 로그인 관련, OAUTH관련 중요 정보는 설정에서 가져오거나 직접 입력하거나 알아서 한다.


# Token 정보 가져오는 코드

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import json
import os
import re
import urllib.request

from bs4 import BeautifulSoup
from requests import get
from selenium import webdriver
from urllib.error import HTTPError
from urllib.parse import urlencode


def get_naver_token(): chromedriver_path = os.environ.get('CHROMEDRIVER_PATH') naver_id = os.environ.get('NAVER_ID') naver_pw = os.environ.get('NAVER_PW') naver_cid = os.environ.get('NAVER_CLIENT_ID') naver_csec = os.environ.get('NAVER_CLIENT_SECRET') naver_redirect = os.environ.get('NAVER_BLOG_REDIRECT') driver = webdriver.Chrome(chromedriver_path) # driver = webdriver.PhantomJS() driver.implicitly_wait(3) driver.get('https://nid.naver.com/nidlogin.login') driver.find_element_by_name('id').send_keys(naver_id) driver.find_element_by_name('pw').send_keys(naver_pw) driver.find_element_by_xpath('//*[@id="frmNIDLogin"]/fieldset/input').click() state = "REWERWERTATE" req_url = 'https://nid.naver.com/oauth2.0/authorize?response_type=code&client_id=%s&redirect_uri=%s&state=%s' % (naver_cid, naver_redirect, state) driver.get(req_url) ########################## # XXX: 최초 1회만 반드시 필요하고 이후엔 불필요함 driver.find_element_by_xpath('//*[@id="confirm_terms"]/a[2]').click() ########################## redirect_url = driver.current_url temp = re.split('code=', redirect_url) code = re.split('&state=', temp[1])[0] driver.quit()

print(redirect_url)

url = 'https://nid.naver.com/oauth2.0/token?'
data = 'grant_type=authorization_code' + '&client_id=' + naver_cid + '&client_secret=' + naver_csec + '&redirect_uri=' + naver_redirect + '&code=' + code + '&state=' + state

request = urllib.request.Request(url, data=data.encode("utf-8"))
request.add_header('X-Naver-Client-Id', naver_cid)
request.add_header('X-Naver-Client-Secret', naver_redirect)
response = urllib.request.urlopen(request)
rescode = response.getcode()
token = ''
if rescode == 200:
response_body = response.read()
js = json.loads(response_body.decode('utf 8'))
token = js['access_token']
else:
print("Error Code:", rescode)
return None

if len(token) == 0:
return None
print(token)
return token

Access token 정보를 가져왔다.

잠시 숨을 고르고 아래에 이어서 카페 글쓰기를 시도하면 된다. (스크롤을 내려야함)




위의 코드를 이용해서 토큰을 가져왔다면 그 다음에는 카페 글쓰기 api를 사용하면 된다.

반가운 Python 예제 코드다.


그런데 또 막힌다.

    clubid = 'xxxxxx'    
    menuid = 'x'


이건 직접 찾아봐야한다.

Chrome의 검사 기능을 이용해서 찾을 수 있다. (다른 웹브라우저에서도 알아서 찾아볼 수 있음)

아래 같이 카페에 로그인해서 게시판에 들어가고

마우스 우클릭해서 '검사' 기능을 사용하면

오른쪽에 정보를 찾을 수 있다.