네이버 웹툰 크롤러를 만들었는데 로그인 된 세션이 아니다보니 나이제한 걸린 웹툰 접근이 안됐다.

네이버 로그인 구현을 하려고 검색을 해보니 역시 선구자가 있었다.

 

원리는 잘 모르겠으나 일단 잘 읽어보고 시도. 옛날 소스라 특히 encode, decode를 좀 수정해줘야 한다.

파이썬 문법도 잘 모르는데 옛날 소스 포팅하려고 하니 이건 뭐 장님 코끼리 만지는 격이다.

 

다 수정해서 돌렸는데 로그인을 하니 status code는 200 OK가 나오는데 자꾸 캡차가 나온다.

여기서 requests 대신 selenium을 써볼까 했는데 속도가 너무 느려서 포기했다.

좀 더 찾아보니 또 역시나 선구자가 있었다.

 

요약하면 bvsd.js 파일에서 브라우저 정상/비정상 여부를 감지해 캡차를 띄운다는 것. 어짜피 클라이언트에서 감지하는 것이니 우회할 수 있는데 위 소스들이 vb.net, c#이라 베끼는 데 좀 애를 먹었다 ㅠ

그리고 보니까 public key 주소도 변경됐다.

이전
http://static.nid.naver.com/enclogin/keys.nhn

현재(2020. 3. 16 기준)
https://nid.naver.com/login/ext/keys.nhn

 

import re
import uuid
import requests
import rsa
import lzstring
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter


def encrypt(key_str, uid, upw):
    def naver_style_join(l):
        return ''.join([chr(len(s)) + s for s in l])

    sessionkey, keyname, e_str, n_str = key_str.split(',')
    e, n = int(e_str, 16), int(n_str, 16)

    message = naver_style_join([sessionkey, uid, upw]).encode()

    pubkey = rsa.PublicKey(e, n)
    encrypted = rsa.encrypt(message, pubkey)

    return keyname, encrypted.hex()


def encrypt_account(uid, upw):
    key_str = requests.get('https://nid.naver.com/login/ext/keys.nhn').content.decode("utf-8")
    return encrypt(key_str, uid, upw)


def naver_session(nid, npw):
    encnm, encpw = encrypt_account(nid, npw)

    s = requests.Session()
    retries = Retry(
        total=5,
        backoff_factor=0.1,
        status_forcelist=[500, 502, 503, 504]
    )
    s.mount('https://', HTTPAdapter(max_retries=retries))
    request_headers = {
        'User-agent': 'Mozilla/5.0'
    }

    bvsd_uuid = uuid.uuid4()
    encData = '{"a":"%s-4","b":"1.3.4","d":[{"i":"id","b":{"a":["0,%s"]},"d":"%s","e":false,"f":false},{"i":"%s","e":true,"f":false}],"h":"1f","i":{"a":"Mozilla/5.0"}}' % (bvsd_uuid, nid, nid, npw)
    bvsd = '{"uuid":"%s","encData":"%s"}' % (bvsd_uuid, lzstring.LZString.compressToEncodedURIComponent(encData))

    resp = s.post('https://nid.naver.com/nidlogin.login', data={
        'svctype': '0',
        'enctp': '1',
        'encnm': encnm,
        'enc_url': 'http0X0.0000000000001P-10220.0000000.000000www.naver.com',
        'url': 'www.naver.com',
        'smart_level': '1',
        'encpw': encpw,
        'bvsd': bvsd
    }, headers=request_headers)

    finalize_url = re.search(r'location\.replace\("([^"]+)"\)', resp.content.decode("utf-8")).group(1)
    s.get(finalize_url)

    return s



if __name__ == "__main__":
    s = naver_session('idid', 'pwpw')
    print(1)
    pp = s.get('https://comic.naver.com/webtoon/detail.nhn?titleId=726095&no=42')
    print(pp)

완성한 소스 예제. 아이디랑 비밀번호 하드코딩돼있다.

naver_session 함수 중간에 Retry가 들어가있는데 크롤링할 때 쓰려고 한거라 빼도 된다. 로그인 후에는 네이버 웹툰에서 성인 만화 한 화에 접속해 로그인이 됐는지 확인한다.

 

위 소스로 로그인이 잘 안될 수 있는데, 이때는 response 확인해봐야한다. 아이디 보호모드? 그런게 나오면 해제를 해줘야 한다.

위 소스로 로그인했을 때 캡차가 나오면 로그인 루틴이 바뀐 것일 확률이 높다.

 

 

+ 2020. 06. 11

프로젝트를 깃허브에 올려놨습니다 (링크)

일단 동작은 잘 합니다. 문서화가 겁나 부실하고 리팩토링이 하나도 안돼있는데.. 동작은 합니다. 코딩테스트 준비한답시고 손도 못댔네요.

후우~ 이번주 안에 시간내서 프로젝트를 다듬어야겠습니다. 혹시 사용법이 궁금하면 댓글 달아주세요

반응형
  1. program1472@naver.com 2020.09.24 11:54 댓글주소 수정/삭제 댓글쓰기

    파이썬은 더 간결하네요 ㅎㅎ
    제 블로그로 자꾸 유입이 되서 무언가 했더니 링크가 있었네요...ㅎㅎ

  2. 감사한마음 2020.11.01 05:14 댓글주소 수정/삭제 댓글쓰기

    너무 좋은 소스와 내용 감사드립니다.

    질문이 있어서요
    다른 사이트 같은 경우는 public key 주소를 어떻게 알고 소스에 넣어야 할까요?

    def encrypt_account(uid, upw):
    key_str = requests.get('https://nid.naver.com/login/ext/keys.nhn').content.decode("utf-8")
    return encrypt(key_str, uid, upw)

    이 부분이 이해가 잘 안됩니다

    혹시 시간 되실때 가능하시다면 답변 부탁드리겠습니다.
    감사합니다

    kskworld0@gmail.com

    • vince joe 2020.11.01 13:20 신고 댓글주소 수정/삭제

      글쎄요 제가 100% 이해를 갖고 짠 게 아니고 이곳저곳 참고하면서 만든거라... 공개키는 네트워크탭에서 recording해서 보시면 될 것같고 해당 소스 부분은 맨 위에 있는 티스토리 링크에서 확인하시면 될 것 같습니다

  3. 익명 2020.12.28 17:45 댓글주소 수정/삭제 댓글쓰기

    비밀댓글입니다

    • vince joe 2020.12.28 19:44 신고 댓글주소 수정/삭제

      글쎄요... 이 플젝 흥미가 떨어져서 안건드린지 꽤 됐는데... 디버깅을 잘 해보시라고밖엔 조언을 못해드리겠네요.