인프런 영문 브랜드 로고
인프런 영문 브랜드 로고

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

poongak님의 프로필 이미지

작성한 질문수

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

나라장터 URL 수집

해결된 질문

작성

·

699

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 인턴님의 프로필 이미지

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

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

문제 해결을 위한 확인 사항

  1. 개발자 도구 활용:

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

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

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

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

추가 참고 자료

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

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

poongak님의 프로필 이미지

작성한 질문수

질문하기