Today I Learned

Parkboss·2023년 8월 7일
0

TIL

목록 보기
5/8
post-thumbnail

오늘 한일✅

  • 네이버 크롤링 & 네이버 지도 드디어 완성 ㅠㅠ

네이버 크롤링 부분에서 제대로 되지 않아 2주 동안 붙잡고 있었다... 처음 작업한 파일은 되돌릴 수 없을 정도로 꼬여서 처음부터 다시 시작했다.

그때 심정은 정말.........🤮

천천히 하나하나 다시 시작했고 개 막혔던 부분은 같이 공부하던 친구에게 물어보았다.. 그렇게 하나하나 막히던 문제를 풀어갔고 끝이 보이지 않던 크롤링 문제를 드디어 해결했다!

세상을 다 가진 느낌? 근데 조금 허무한 느낌이랄까... 그래도 해결했으면 됐지 뭐~


어쩌다보니 SSR을 해버렸다!

네이버 지도는 금방 불러올 수 있었다.
하지만 네이버 플레이스의 가게 정보 json을 가져오고 싶었다.

그럼 네이버 지도처럼 api를 이용해 보자!

조오옹나 구글링하고 네이버에서 찾아본 결과 네이버 플레이스 api는 따로 없단다.. 그럼 크롤링이라는 방법으로 정보를 긁어오자!

여기서 프로젝트를 엎고 다시 만들게 된 이유가 있다....

난 당연히 지도 api를 불러온 것처럼 크롤링도 간단히 할 줄 알았다.
구글링을 해서 블로그부터 공식 문서부터 스텍오버플로우를 열심히 참고하면서 만들었는데 크롤링을 하려면 SSR을 해야된단다.

뤼튼의 답변

React 자체에서 크롤링을 직접적으로 수행할 수는 없습니다. React는 클라이언트 측에서 UI를 렌더링할 수 있는 라이브러리이며, 서버 측에서 데이터를 가져와 렌더링된 UI를 전달할 수 있습니다.
따라서 React를 사용하여 크롤링을 수행하려면, 서버 측에서 크롤링을 수행하고 해당 데이터를 React 앱으로 전달해야 합니다. 이를 위해서는 서버 사이드 렌더링(Server-Side Rendering)이라는 기술을 사용할 수 있습니다.
서버 사이드 렌더링을 사용하면, 서버 측에서 React 앱을 렌더링하고, 해당 데이터를 HTML 형식으로 클라이언트에게 전달할 수 있습니다. 이 방법을 사용하면, 크롤링한 데이터를 React 앱에서도 사용할 수 있습니다.
하지만 이를 구현하기 위해서는 클라이언트와 서버 간에 데이터를 교환하는 방법을 알고 있어야 할 것입니다. Redux, GraphQL, REST API 등 여러가지 방법을 사용하여 이를 구현할 수 있습니다.

나는 Client와 Server에 대한 기초 지식도 없는 채 프로젝트를 어느 정도 만들었는데 중간에 심하게 꼬여서 되돌릴 수 없는 상황이었다🤬

한편으로 지금 단계에서 다시 처음부터 시작할 수 있어서 다행이다?라는 생각으로 유튜브와 블로그와 공식 문서를 참고하면서 리액트에서 Client와 Server 나누는 방법과 webpack 설정을 다시 하였다.


서론이 길었다. 구현 방법 가보자규!!!!!!!!!!!!!!!!!!

구현 방법✅

파일 구조

1. 패키지 생성과 express,nodemon 설치

npm init
npm i --save express
npm i --save nodemon

2. webpack,리액트와 각종 여러가지 설치

npm i -D webpack webpack-cli webpack-dev-server html-webpack-plugin style-loader css-loader file-loader clean-webpack-plugin react react-dom react-router-dom@babel/core @babel/preset-react babel-loader @babel/plugin-proposal-class-properties @babel/preset-env concurrently styled-components axios cheerio cors

3. webpack.config 설정

4. pack.json 설정


에러 해결✅

5. react-dom/client 에러❗

  • index.jsx에서 import ReactDOM from 'react-dom'; 이런식으로 import한다.
  • 밑에 에러처럼 import ReactDOM from 'react-dom/client'; 로 변경하면 에러 해결!

6. cors 에러❗

  • cors란?

    Cross-Origin Resource Sharing (CORS) 오류는 보안 상의 이유로 다른 도메인의 리소스에 접근할 경우 발생하는 오류입니다. 브라우저는 도메인간 요청이 발생할 경우 보안을 위해 기본적으로 해당 요청을 차단하는데, 이를 CORS 오류라고 합니다.

  • cors 에러를 해결하는 방법들이 다양하게 있는것같다.

  1. proxy-middleware를 사용하여 에러를 해결할 수 있다.

proxy-middleware는 클라이언트에서 서버와의 API 통신을 라우팅하고자 할 때 사용되는 미들웨어입니다.

처음에는 Proxy-middleware 패키지를 사용했다.
새로 다시 프로젝트를 만들때는 cors 패키지를 사용했다.

이 둘의 차이를 잠시 알고 가보자!

proxy-middleware는 클라이언트 측에서 서버와 통신 시, 다른 도메인에서 API를 호출하고자 할 때 사용됩니다. 이 경우, 클라이언트에서 API 요청이 프록시를 통해 라우팅되어 백엔드와 통신이 이루어지게 됩니다. 주로 클라이언트 측에서 개발할 때 사용되며, React + CRA(Create React App)와 통합하여 사용하기 용이합니다.

cors는 서버 사이드 렌더링(Server-Side Rendering)을 위해 서버에서 CORS를 처리하기 위해 사용됩니다. 서버 사이드에서 다른 도메인에서 온 요청에 대한 보안 처리를 하게 되어 있습니다. 이 패키지는 서버에서 사용되며 Express.js, Koa.js 등과 같은 Node.js 프레임워크에서 쉽게 사용될 수 있습니다.

나의 목적은 SSR 서버 단에서 다른 도메인을 요청하기 때문에 cors를 사용하는것이 적합하다 생각해 cors를 사용하기로 했다!

  1. cors 패키지 설정

7. api.jsx 에러❗

콘솔로그에 하나의 배열에 다섯개의 객체가 찍힌다.
그리고 client 쪽에서 콘솔을 찍어보면 빈 배열이 자꾸 뜬다.

그 이유는 dataArr.push에서 잘못되고 있었다.

다섯 번의 객체가 찍히는 이유는 api_subject_bx를 each를 돌면서 해당된 것을 반환하기 때문에 첫 번째 객체에서는 아무것도 없이 객체가 찍히고 두 번째는 Title이 있기 때문에 Title이 찍히고 세 번째 객체는 Address, Time, Number가 같이 있기 때문에 그렇다.

참고하던 블로그에서도 if문을 주고 빈값이면 리턴을 하게끔 장치를 설치했다.

1. if문

  if (Title !== '') {
      dataArr.push(Title);
    } else if (Address !== '' && Time !== '' && Number !== '') {
      dataArr.push(Address, Number, Time);
    }

위에 처럼 변경하였는데 배열에 잘 들어가지만 json 형태인 배열안에 객체로 찍히지 않았다.

2. 객체 추가

  • {}를 추가하면 내가 원하는 json처럼 나올것 같았다.
  if (Title !== '') {
      dataArr.push({Title});
    } else if (Address !== '' && Time !== '' && Number !== '') {
      dataArr.push({Address, Number, Time};
    }

이런식으로 찍히면 문제가 있었다.
아래 캡쳐본처럼 더블 출력의 문제가 발생했다.

3. 객체에 값을 할당

  • 아래 방식대로 바꾸니 내가 원하는 json 형태로 출력이 된다!(이 부분이 정말 막혀서 도움을 받았다)
    // 빈 값 리턴
    if (Title !== '') {
      dataObject.Title = Title;
    } else if (Address !== '' && Time !== '' && Number !== '') {
      dataObject.Address = Address;
      dataObject.Time = Time;
      dataObject.Number = Number;
    }

8. server.jsx 에러❗

  • api를 불러와서 server에서 파싱을 불러오는 부분에서 아무것도 뜨지않는다.

promise pending이란?

  • 대기(pending) : 이행하거나 거부되지 않는 초기 상태
  • 이행(fulfilled) : 연산이 성공적으로 완료됨
  • 거부 (rejected) : 연산이 실패함

promise 객체에 아무것도 실행되지 않는 초기의 상태였다.

1. async await

  • 함수가 async 함수로 정의되어 있기 때문에, 내부에서 parsing 함수를 호출할 때 await 키워드를 사용해 비동기적으로 처리할 수 있다.

  • await 키워드를 사용하여 parsing 함수가 반환하는 Promise 객체의 처리 결과값을 받게 됩니다. 이때 await가 사용된 지점에서 함수의 실행이 일시적으로 차단되어 있는 상태가 되며, parsing 함수의 처리 결과값이 반환될 때까지 기다립니다. 따라서, await parsing() 코드 실행 후에는 parsed 변수는 parsing 함수의 반환값으로 대체된다.

const parsingData = async () => {
  const parsed = await parsing();
  console.log(parsed, 'ssss');
};

JSON 에러❗

  • 콘솔로그는 잘 뜬다.
const parsingData = async () => {
  const parsed = await parsing();
  console.log(parsed, 'fff');
};

app.get('/api', (req, res) => {
  // res.json(parsingData());
  parsingData().then((response) => {
    res.send(response);
  });
  // res.send(parsingData);
});
  • client 쪽에서 Unexpected end of JSON input 에러가 뜬다❗
  const requestOptions = {
    method: 'GET',
    Headers: { 'Content-Type': 'application/json' },
    redirect: 'follow',
  };
  fetch('http://localhost:5000/api', requestOptions)
    .then((response) => response.json())
    .then((data) => console.log(data));
  • json.parse로 바꿔서도 해보고 mdn을 보면서 수정을 하였는데 먹히지 않았다.

2. 서버에서 크롤링 해온 정보를 json 파일에 넣어주고 /api로 보내주는 방식으로 변경

  • server와 연결이 되면 api.jsx에서 파싱한 json을 datapath인 빈 json 파일에 넣어주는 방식으로 바꾸었다.

  • 서버에서 npm run server를 하면 ./CheeseInformation.json에 api 파싱한 json이 잘들어온다이이이이이이

fetch와 axios

  • fetch란?

    fetch()는 .then() 메서드에서 처리된 promise를 반환한다.
    이 때는 아직 우리가 필요한 JSON 데이터의 포맷이 아니기 때문에 응답 객체의 .json() 메서드를 호출합니다.
    그러면 JSON 형식의 데이터로 이행(resolve)된 또 다른 promise를 반환합니다. 따라서 일반적인 fetch 요청은 두 개의 .then() 호출을 갖습니다.

  • axios란?

    Axios를 사용하면 응답 데이터를 기본적으로 JSON 타입으로 사용할 수 있습니다. 응답 데이터는 언제나 응답 객체의 data 프로퍼티에서 사용할 수 있습니다.

첫번째로 axios를 사용하였는데 json으로 응답을 받아오지 못하였다. 그래서 위에 언급했던것처럼 Unexpected end of JSON input 에러가 계속 발생하였다.

파싱하는 부분에서 빈 json 파일에 server가 연결이 되면 파싱된 정보가 json 파일에 쏙 들어가게끔 변경해 줬다.

나는 JSON 데이터가 있으므로 이번 프로젝트는 fetch를 사용하는것이 적합하여 fetch를 사용하였다.


알게 된점✅

  • client와 server를 나누어 SSR을 알게 되었고 한번 사용해 보고 싶었던 Express를 사용해서 좋았다.
  • 수많은 삽질로 자연스럽게 fetch와 axios도 살짝 맛보면서 알게 되었고 악명 높은 cors 에러를 손쉽게 처리할 수 있었다.
  • 자바스크립트의 부족함을 또 한 번 알게 되었다!!!!!!!!!!!!!!
  • 하면 된다

참고 블로그
참고 블로그
fetch & Axios 블로그

profile
ur gonna figure it out. just like always have.

4개의 댓글

comment-user-thumbnail
2023년 8월 7일

많은 도움이 되었습니다, 감사합니다.

1개의 답글
comment-user-thumbnail
2023년 8월 7일

좋은 글 잘 보았습니다. 파이팅입니다 :)

1개의 답글