ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Docucentre-V C2263 작업기록 파싱기
    Python/web scraping 2019. 1. 26. 15:22

    이 글은 2018.04.08에 github pages를 이용해 만들어진 블로그에서 작성 된 글입니다


    부제: 나는 latin-1이 싫다

    최근 하는 일 때문에 후지 제록스사의 Docucentre-V C2263 모델의 관리 페이지를 파싱할 일이 생겼다. 해당 복합기는 연결되어있는 IP 주소로 접속하면 사용자 인증 후에 프린터의 소모품, 용지 상태, 작업 기록을 확인할 수 있고, 해당 웹서비스로 바로 인쇄요청도 보낼 수 있게 되어있다.


    사용자 인증

    앞서 말했듯이 프린터의 정보 뿐만 아니라 직접 인쇄 요청까지 보낼 수 있으므로 관리 페이지는 인증을 요구한다

    파이썬의 requests 모듈은 인증을 쉽게 할 수 있도록 도와준다.

    1

    response = requests.get(PRINTER_MANAGE_URL, auth=REQUEST_AUTH)

    response는 후에 cookie를 같이 넘겨주기 위해서 저장한다.


    한글 인코딩 문제

    페이지를 요청하는데 한글만 인코딩이 깨져서 왔다.

    사실 이 당시만 하더라도 헤더 없이 요청을 보냈기 떄문에 영어로 응답이 와서 그런 줄 알았다. 그래서 http request header에 accept-language 속성을 같이 담아서 보냈다

    1
    2
    3
    4
    5
    6
    7
    headers = {
    'accept-language': 'ko-kr,ko;q=0.8,en-us;q=0.5,en;q=0.3',
    'accept-charset': 'utf-8'
    }

    response = requests.get(PRINTER_MANAGE_URL, auth=REQUEST_AUTH)
    job_response = requests.get(PRINTER_MANAGE_URL+'/jbhist.htm', cookies=response.cookies, headers=headers)

    이렇게 쉽게 끝났으면 이 글을 쓰지도 않았을 것이다.

    우선 원본 인코딩을 찾기 위해 온갖 삽질을 했다. 인터넷에서 파이썬에서 지원되는 인코딩 방식에 대해 모두 검사를 돌려봤지만 일치하는 것을 찾지 못했다. (심지어는 지원하지 않는 인코딩도 있었다!)

    그러던 중 requests 응답 객체의 속성 중 encoding 속성이 있는 것을 알았고 콘솔에 찍어봤더니

    ISO-8859-1로 나왔다.

    아직도 accept-charset에 utf-8을 넣고 요청했는데 왜 이렇게 나오는지를 모르겠다.

    일단 범인을 찾았으니 .encode()와 .decode()를 이용해서 이리저리 조작해봤지만 온갖 에러와 스트레스와 왜 되지 않는지 모르는 내 자신을 발견할 뿐이었다.

    결국 답은 구글링으로 찾았는데

    requests 응답에 한글과 같은 유니코드 문자가 섞여있는 경우 저렇게 깨질 수 있다는 것이었다. 답은 간단하게도 .text 속성 말고 .content 속성을 이용해 접근하면 해결되었다. (한가지 주의할 점은 .text 속성은 str type으로 return 되지만 .content 속성은 bytes type으로 return 되기 때문에 .decode()를 이용해서 str type으로 바꿔주어야 한다는 점이다.)


    JS로 동적생성되는 내용

    보통 페이지 파싱을 위해 BeautifulSoup나 Selenium을 즐겨쓰는 편이다. bs는 이번 경우에서 js를 이용해서 html을 채우는 형식이라 html에는 별 내용이 없기 때문에 사용을 할 수 없었고, Selenium은 js로 동적 생성된 페이지를 파싱할 수 있었지만 너무 느리고 프로그램이 돌아갈 것으로 예상되는 서버(아마도 라즈베리파이)에는 맞지 않을 것이라 생각했기 때문에 requests로 가져와서 직접 슬라이싱 해서 사용하는 방법을 이용했다

    이번 프로젝트에서는 작업 요청 리스트 부분만 필요했는데, 리스트는 아래와 같은 형식이었다.

    1
    2
    3
    4
    5
    6
    7

    var stsAry=['알 수 없음','정상 종료','경고','경고','강제 종료','강제 종료','강제 종료','시스템 종료','이상 종료','전화 착신','상대국 확인'];
    var types=['-','프린트','복사','스캔','메일박스에서 가져오기','팩스','리포트'];
    var jHst=[
    ['Chapter 12 Equilibrium and Elasticity.pdf','USC-PPC1',1,1,2,'중앙트레이-하단','LPD','2018/04/08 11:51 PM'],
    //...
    ];
    function wrTr() {document.write('<TR>');}

    jHst 리스트에 작업 내용이 모두 담겨있고 그 필드 정보는 hdrs 리스트에 저장되어있다.

    1
    var hdrs=['작업명','소유자','결과','작업종류','페이지수','배출 위치','호스트 인터페이스','종료 시각'];

    어쨌든 우리가 필요한 정보는 jHst 리스트이므로 해당 리스트만 추출하기 위해 아래와 같이 코드를 짰다.

    1
    f.write(h[h.find('var jHst')+9:h.find(';\nfunction wrTr() {document.write(\'<TR>\');}')])

    jHist 이전 내용은 유저가 관여할 수 있는 내용이 아니므로 첫번째 나오는 var jHst를 검색하면 시작 위치를 알아낼 수 있다. 우리가 필요하 정보는 var jHst= 이후의 부분이므로 +9만큼 더한 위치에서 시작하도록 했다

    그 이후는 요청하는 파일명에 따라서 리스트 중간에서 find 결과가 나올 수 있으므로 ;까지 찾는다거나 하는 방법은 좋은 방법이 아니다.

    JavaScript 파서를 알아봤지만 마음에 드는 모듈도 없고 해서 고민하다가 나온 아이디어는 \n을 포함하는 문자를 찾는것이다(파일명에는 들어갈 수 없으므로). 따라서 ;와 그 다음줄 일부까지를 포함하는 문자를 찾도록 했고 결과는 성공적이었다.



    'Python > web scraping' 카테고리의 다른 글

    Python으로 Blackboard 서비스 파싱기  (0) 2019.01.26

    댓글

Designed by Tistory.