Inflearn brand logo image

인프런 커뮤니티 질문&답변

poongak님의 프로필 이미지
poongak

작성한 질문수

코딩없이 시작하는 엑셀 크롤링. WEB부터 ChatGPT API까지

나라장터 URL 수집

해결된 질문

작성

·

1.2K

0

다비 강사님 안녕하세요.

강의 너무 잘 듣고 있습니다. 감사합니다.

 

나라장터 조달청 입찰공고 강의 중 내용을 실습하고 있는데요.

몇 일전 나라장터 사이트가 리뉴얼이 되더니 URL 수집이 잘 안됩니다.

 

개발자 페이지에서 URL을 눌렀을때 preview도 loading중이라고만 뜨고 결과가 안나오며, 검색창에 입력해봐도 마찬가지입니다.

image.pngimage.pngimage.png

 

 

 

제가 뭘 놓치고 있는걸까요?

조언 부탁 드립니다.

답변 4

0

다비님의 프로필 이미지
다비
지식공유자

POST로 바뀌면서 API체계를 따라가다 보니 내용이 많이 복잡해졌습니다.

참고하실 수 있도록 아래에 코드 추가해드립니다. 시기를 보아서 이 부분은 강의에서 내리거나 update하도록 하겠습니다.

조달청API도 3개월 후에 정지된다는 메일을 받은 적이 있는데요. 안정성을 고려해서 조치하겠습니다. 미리 조치하지 못해 죄송합니다.

 

POST통신을 하게 되면Header값처럼 별도로 POST통신에 사용하는 값을 전달해주어야 데이터에 접근할 수 있습니다. 나라장터의 경우 이 항목이 매우 많아 코드가 복잡함을 양해해주시기 바랍니다.

 

let
    Payload = Text.ToBinary(
        "{""dlBidPbancLstM"":{""untyBidPbancNo"":"""",""bidPbancNo"":"""",""bidPbancOrd"":"""",""prcmBsneUntyNoOrd"":"""",""prcmBsneSeCd"":""0000 조070001 조070002 조070003 조070004 조070005 민079999"",""bidPbancNm"":""인공지능"",""pbancPstgDt"":"""",""ldocNoVal"":"""",""bidPrspPrce"":"""",""ctrtDmndRcptNo"":"""",""dmstcOvrsSeCd"":"""",""pbancKndCd"":""공440002"",""ctrtTyCd"":"""",""bidCtrtMthdCd"":"""",""scsbdMthdCd"":"""",""fromBidDt"":""20241208"",""toBidDt"":""20250107"",""minBidPrspPrce"":"""",""maxBidPrspPrce"":"""",""bsneAllYn"":""Y"",""frcpYn"":""Y"",""rsrvYn"":""Y"",""laseYn"":""Y"",""untyGrpGb"":"""",""dmstNm"":"""",""pbancPicNm"":"""",""odnLmtLgdngCd"":"""",""odnLmtLgdngNm"":"""",""intpCd"":"""",""intpNm"":"""",""dtlsPrnmNo"":"""",""dtlsPrnmNm"":"""",""slprRcptDdlnYn"":"""",""lcrtTyCd"":"""",""isMas"":"""",""isElpdt"":"""",""oderInstUntyGrpNo"":"""",""esdacYn"":"""",""infoSysCd"":""정010029"",""contxtSeCd"":""콘010006"",""bidDateType"":""R"",""brcoOrgnCd"":"""",""deptOrgnCd"":"""",""isShop"":"""",""srchTy"":""0"",""cangParmVal"":"""",""currentPage"":"""",""recordCountPerPage"":""10"",""startIndex"":1,""endIndex"":10}}"
    ),

    Source = Json.Document(
        Web.Contents("https://www.g2b.go.kr/pn/pnp/pnpe/BidPbac/selectBidPbacScrollTypeList.do", 
            [
                Headers = [
                    #"authority" = "www.g2b.go.kr",
                    #"method" = "POST",
                    #"path" = "/pn/pnp/pnpe/BidPbac/selectBidPbacScrollTypeList.do",
                    #"scheme" = "https",
                    #"accept" = "application/json",
                    #"accept-encoding" = "gzip, deflate",
                    #"accept-language" = "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6,zh;q=0.5,zh-TW;q=0.4,zh-HK;q=0.3",
                    #"content-type" = "application/json;charset=UTF-8",
                    #"cookie" = "WHATAP=x2amc4safu1krv; XTVID=A2501071301227329; Path=/; infoSysCd=%EC%A0%95010029; _harry_ref=https%3A//www.google.com/; _harry_url=https%3A//www.g2b.go.kr/; _harry_fid=hh-1701578081; _harry_lang=ko-KR; system_language=ko; poupR23AB0000013415=done; poupR23AB0000013414=done; lastAccess=1736223179861; JSESSIONID=NWU3ZmNhMmEtODkyZC00YjdiLWExMzEtNmFjZWQyZDE4Zjk0; _harry_hsid=A250107165624222833; _harry_dsid=A250107165624222403; XTSID=A250107165624222203; xloc=1707X960; globalDebug=false; XTVID=A2501071301227329",
                    #"menu-info" = "{""menuNo"":""01175"",""menuCangVal"":""PNPE001_01"",""bsneClsfCd"":""%EC%97%85130026"",""scrnNo"":""00941""}",
                    #"origin" = "https://www.g2b.go.kr",
                    #"priority" = "u=1, i",
                    #"referer" = "https://www.g2b.go.kr/",
                    #"sec-ch-ua" = """Google Chrome"";v=""131"", ""Chromium"";v=""131"", ""Not_A Brand"";v=""24""",
                    #"sec-ch-ua-mobile" = "?0",
                    #"sec-ch-ua-platform" = """Windows""",
                    #"sec-fetch-dest" = "empty",
                    #"sec-fetch-mode" = "cors",
                    #"sec-fetch-site" = "same-origin",
                    #"submissionid" = "mf_wfm_container_tacBidPbancLst_contents_tab2_body_sbmPbancBidPbancLst",
                    #"target-id" = "btnS0004",
                    #"user-agent" = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
                    #"usr-id" = "null"
                ],
                Content = Payload
            ]
        )
    ),
    result = Source[result],
    #"테이블로 변환됨" = Table.FromList(result, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    #"확장된 Column1" = Table.ExpandRecordColumn(#"테이블로 변환됨", "Column1", {"prcmBsneSeCd", "prcmBsneSeCdNm", "pbancSeYnNm", "scsbdMthdDtlsCrtrNm", "scsbdMthdCd", "scsbdMthdDtlsCrtrNo", "bidPbancUntyNoOrd", "pbancSttsNm", "pbancSttsCd", "untyBidPbancNo", "untyBidPbancOrd", "bidPbancUntyNo", "bidPbancUntyOrd", "bidPbancNm", "oderInstUntyGrpNo", "oderInstUntyGrpNm", "dmstNm", "pbancPstgDt", "linkInstPbancLnkUrl", "untyBidPbancRegTyCd", "bidMthdCd", "aagrSbmsnElctHdwrSeCd", "rowNum", "prcmBsneUntyNo", "prcmBsneUntyOrd", "bidClsfNo", "bidPrgrsOrd", "bsneClsfCd", "prcmBsneUntyOdn3Val", "prcmBsneUntyOdn4Val", "prcmBsneUntyOdn5Val", "prcmBsneUntyOdn6Val", "prcmBsneUntyOdn7Val", "pbancPicId", "pbancPicNm", "lastPbancYn", "currentPage", "recordCountPerPage", "nextRowYn", "sessUsrIpar", "prgrsUntyPrcmBsneNo", "orderByYn", "gupBsneUntNo", "gupBsneUntNm", "stepBsneUntNo", "stepBsneUntNm", "prssBsneUntNo", "prssBsneUntNm", "bsnePrssPrgrsSeCd", "bsnePrssPrgrsSeNm", "prcsDt", "bsneFlowNo", "prcsRsn", "menuCangVal", "cangParmVal", "resultCode", "resultMsg"}, {"prcmBsneSeCd", "prcmBsneSeCdNm", "pbancSeYnNm", "scsbdMthdDtlsCrtrNm", "scsbdMthdCd", "scsbdMthdDtlsCrtrNo", "bidPbancUntyNoOrd", "pbancSttsNm", "pbancSttsCd", "untyBidPbancNo", "untyBidPbancOrd", "bidPbancUntyNo", "bidPbancUntyOrd", "bidPbancNm", "oderInstUntyGrpNo", "oderInstUntyGrpNm", "dmstNm", "pbancPstgDt", "linkInstPbancLnkUrl", "untyBidPbancRegTyCd", "bidMthdCd", "aagrSbmsnElctHdwrSeCd", "rowNum", "prcmBsneUntyNo", "prcmBsneUntyOrd", "bidClsfNo", "bidPrgrsOrd", "bsneClsfCd", "prcmBsneUntyOdn3Val", "prcmBsneUntyOdn4Val", "prcmBsneUntyOdn5Val", "prcmBsneUntyOdn6Val", "prcmBsneUntyOdn7Val", "pbancPicId", "pbancPicNm", "lastPbancYn", "currentPage", "recordCountPerPage", "nextRowYn", "sessUsrIpar", "prgrsUntyPrcmBsneNo", "orderByYn", "gupBsneUntNo", "gupBsneUntNm", "stepBsneUntNo", "stepBsneUntNm", "prssBsneUntNo", "prssBsneUntNm", "bsnePrssPrgrsSeCd", "bsnePrssPrgrsSeNm", "prcsDt", "bsneFlowNo", "prcsRsn", "menuCangVal", "cangParmVal", "resultCode", "resultMsg"})
in
    #"확장된 Column1"

0

다비님의 프로필 이미지
다비
지식공유자

안녕하세요? 개편이 크게 되었네요. ^^

 

가장 큰 변화가 기존에는 통신 방식이 GET이었는데요. POST로 바뀌었네요.

개발자도구에서 파일 형식을 Doc가 아닌 JS로 하면 selectBidPbacScrollTypeList.do 보실 수 있는데요. 이 파일을 클릭해보시면 원하시는 정보가 JSON형식으로 들어 있습니다.

따라서 이 파일을 수집하셔야 하는데요. Headers를 보시면 Request Method가 POST로 되어있습니다.

image.png

 

image.png

 

POST통신은 사실 강의 범위 밖의 내용이라 개편 후 사이트에 맞게 추가 테스트를 해야 답을 드릴 수 있겠습니다.

 

그나마 엑셀 다운로드 기능이 추가 되어 바로 데이터를 다운로드 할 수 있게 되었으니, 이 기능을 이용해보시는 것을 권해드립니다.

 

감사합니다.

0

다비님의 프로필 이미지
다비
지식공유자

안녕하세요?

크롤링은 상대방 웹사이트의 구조에 맞춰서 데이터를 가져오기 때문에,

개편을 하면 대부분 구조가 바뀌어 이전 방식으로 수집이 안되는 경우가 많습니다.

 

저도 개편된 구조를 한 번 살펴보고 다시 답변 드리도록 하겠습니다.

 

감사합니다.

0

안녕하세요, 인프런 AI 인턴입니다. poongak님.

나라장터 웹사이트가 최근에 업데이트되었다면, 기존의 URL 구조나 웹페이지 요소가 변경되었을 가능성이 큽니다. 따라서 데이터를 수집하기 위한 방법론도 이에 맞게 조정되어야 합니다. 몇 가지 확인해 볼 사항과 해결 방법을 제시드립니다.

문제 해결을 위한 확인 사항

  1. 개발자 도구 활용:

    • 웹페이지의 리뉴얼로 인해 개발자 도구에서 확인하던 URL 패턴이나 API 엔드포인트가 바뀌었을 수 있습니다. 개발자 도구의 네트워크 탭을 활용하여 새로운 URL이나 API 요청을 찾아보세요.
  2. JavaScript 실행 여부:

    • 최근 웹사이트들은 자바스크립트를 통해 동적으로 콘텐츠를 로드하는 경우가 많습니다. 이 경우, 단순히 초기 로딩 시점의 HTML만으로는 원하는 데이터를 찾기 어려울 수 있습니다. 필요하다면 Selenium과 같은 도구를 사용하여 자바스크립트가 완전히 실행된 후의 웹페이지를 크롤링하는 방법을 고려해보세요.
  3. 로그인 및 세션 처리:

    • 만약 로그인이 필요한 경우, 로그인 세션이 제대로 설정되었는지 확인하세요. 로그인이 필요하지 않다고 해도 쿠키나 세션 ID를 필요로 하는 페이지일 수 있습니다.
  4. API 활용:

    • 공공 데이터 포털이나 나라장터에서 제공하는 Open API가 있는지 확인해 보세요. API가 있다면, 이를 활용하는 것이 가장 효율적입니다.

추가 참고 자료

이미지와 URL을 함께 첨부해 주셔서 상황을 좀 더 쉽게 이해할 수 있었습니다. 더 궁금한 점이 있으시면 언제든지 추가 질문해 주세요.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

poongak님의 프로필 이미지
poongak

작성한 질문수

질문하기