JavaScript/Nodejs

[Node.js] 메이플스토리 api 사용하기(2) - 크롤링, SoapApi

반응형

메이플스토리 SoapApi (2)
고객센터에서는 없다고 잡아떼더만 찾으니 나오더군요

먼저, soap api 를 사용하기 위해서 제공하는 xml코드를 분석하기로 하였습니다.

사진을 보면 위아래 두개가 있는거로 보입니다.

느낌상 위에가 값을 보낼 때 사용을 하는것이고,

아래가 데이터를 받아올 때 보여주는 값 인것으로 확인되니 위에것을 먼저 분석하였습니다.

POST /soap/maplestory.asmx HTTP/1.1
Host: api.maplestory.nexon.com
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://gnxsoap.nexon.com/soap/GetCharacterInfoByAccountID"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetCharacterInfoByAccountID xmlns="http://gnxsoap.nexon.com/soap/">
      <AccountID>int</AccountID>
    </GetCharacterInfoByAccountID>
  </soap:Body>
</soap:Envelope>

보아하니

<?xml version="1.0" encoding="utf-8"?>

윗부분이 Header 부분이고, 아래부분이 Request 할때 보내는 값 인걸로 확인이 됩니다.

 

그런데 여기서 문제가 발생합니다.

다른 soap api 통신 예제를 보면 url에" ~~?wsdl" 이라는 단어가 보이게 되는데 여기서는 찾을수가 없었습니다.

 

한참을 고민하다가 한가지 시도를 해보게 됩니다.

 

Host의 api.maplestory.nexon.com

위 POST와 HTTP/1.1  사이의 /soap/maplestory.asmx

 

이 두가지를 묶고 ?wsdl 을 붙히기로 하였습니다.

 

http://api.maplestory.nexon.com/soap/maplestory.asmx?wsdl 

 

위와같은 url이 나오게 되었습니다.

자 그럼 이제 이걸가지고 지지고 볶고 해봅시다.

 

SoapUI 를 설치하였습니다.

 

설치 후 new SoapApi 를 클릭 후 위에서 알아낸 url을 사용하였습니다.

이쯤되니 좀 황홀해집니다.

 

새로운 reques 를 만들고 테스트케이스로 값을 집어넣으니

 

이런 값을 반환해주던군요.

이 값을 이용하면 될거같습니다.

 

자 그럼 이제 폭풍코딩을 하기전에 nodejs 에서 SoapApi를 사용하기 위해서 easy-soap-request 를 설치해줍시다

npm i --save easy-soap-request

이제 이 모듈을 이용해 봅시다.

 

먼저 베이스를 잡아줍시다.

 

let xml =
       `<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetCharacterInfoByAccountID xmlns="http://gnxsoap.nexon.com/soap/">
      <AccountID> AccountID[32bit Int Data] </AccountID>
    </GetCharacterInfoByAccountID>
  </soap:Body>
</soap:Envelope>
`
   const url = "http://api.maplestory.nexon.com/soap/maplestory.asmx?wsdl";
   const sampleHeaders = {
      'Content-Type':'text/xml; charset=utf-8',
      'Content-Length':xml.length,
      'SOAPAction':"http://gnxsoap.nexon.com/soap/GetCharacterInfoByAccountID"
   };

위 코드가 베이스가되는 코드 입니다.

알아낸 url을 넣어주고,

xml에 있던 헤더를 정리하여 sampleHeaders에 넣어줍니다.

추가로 xml에 request 할때 보낼 xml을 적어줍니다.

 

const getUserData = async() => {
  const { response } = await soapRequest({
              url : url,
              headers : sampleHeaders,
              xml : xml,
              timeout : 1000
           });
           const { header, body, statusCode } = response;
           console.log(`header : ${header}`);
           console.log(`body : ${body}`);
           console.log(`statusCode : ${statusCode}`);
}

 

이 코드는 비동기로 처리를 해 주셔야 합니다.

비동기다보니 해당 코드에 xml-json과 콜백함수를 적용하면

 

const getUserData = async(callBack) => {
      try{
         const { response } = await soapRequest({
            url : url,
            headers : sampleHeaders,
            xml : xml,
            timeout : 1000
         });
         const { header, body, statusCode } = response;
         console.log(`header : ${header}`);
         console.log(`body : ${body}`);
         console.log(`statusCode : ${statusCode}`);

         var xmlToJson = convert.xml2json(body, {compact: true, spaces: 4});

         callBack(xmlToJson);
      } catch (error){
         console.error(error);
      }
   }

   getUserData( (userXML) => {
      res.json(userXML);
   });

출처 : medium.com/better-programming/how-to-perform-soap-requests-with-node-js-4a9627070eb6 

 

이런식으로 작성이 가능합니다.

이 코드를 동작시켜보니 오류가 발생하였습니다.

 

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

 

흠... 어디서 문제가 된 것인지 한번 찾아보았더니

getUserData( (userXML) => {
      res.json(userXML);
   });

여기 이 콜백함수에서 res.json부분에 오류가 있었습니다.

이때부터 폭풍 구글링을 시작하였습니다.

 

도대체 어디서 중복이 된건가 계속 찾아다녔는데 getUserData() 밖에 보니  res.end가 있었습니다.. 이부분을 삭제하고 실행하니 오류는 나지 않았습니다.

 

 

 

뭐 이런 거지같은...

문제가 뭔지 찾아봤더니 json으로 변경하고 parse를 안해줫더군요

 

getUserData( (userXML) => {
      res.json(JSON.parse(userXML));
   });

 

이렇게 해주니 정상적으로 잘 나옵니다.

이제 여기서 제가 필요한 필드만 한번 불러와 보겠습니다.

 

getUserData( (userXML) => {
      const jsonData = JSON.parse(userXML)['soap:Envelope']['soap:Body']['GetCharacterInfoByAccountIDResponse']['GetCharacterInfoByAccountIDResult']['diffgr:diffgram']['NewDataSet']['UserInfo'];
      console.log("##############################################");
      console.log(jsonData.AvatarImgURL._text);
      console.log(jsonData.WorldName._text);
      console.log(jsonData.CharacterName._text);
      console.log(jsonData.Lev._text);
      console.log(jsonData.Exp._text);
      console.log(jsonData.JobDetail._text);
      console.log(jsonData.TotRank._text);
      console.log(jsonData.WorldRank._text);
      console.log("##############################################");
      res.json(jsonData);
   });

 

이런식으로 작성을 하여 필요한 정보를 모두 불러왔습니다.

이놈의 메이플SoapApi... 중간에 특수문자때문에 고생좀 했네요

결과는 데이터 잘 가져와집니다.

 

저의 다른 블로그 ngyu.tistory.com에서 가져옴을 알립니다.

이전 글이 궁금하시다면?!
2020/12/08 - [공부/JavaScript] - [Node.js] 메이플스토리 api 사용하기(1) - 크롤링, SoapApi

반응형