SENTENCE U | Day 13 (NavBar/명언데이터 크롤링)

블로그 이사 완료·2023년 1월 26일
0
post-thumbnail

NavBar UI 스타일 적용

NavBar의 프로필 부분을 모달창의 컴포넌트는 만들어놨지만 작동을 안해서 수정할 경 스타일을 적용했다.

약간 어두운 흰색을 배경으로 채도가 조금 빠진 검정색을 이용했다.

유저프로필쪽에 호버를 하면 메뉴가 내려오도록 꾸몄다.

로그인 하지 않은 상태의 기본 모습

로그인 한 상태의 기본 모습

로그인 한 상태에서 호버하면 나타나는 메뉴

로그아웃 한 상태에서 호버하면 나타나는 메뉴


메인페이지 명언 칸 명언데이터 크롤링

기존에 빈 칸이였던 자리에 여러 유명인사들의 명언들을 보여주도록 크롤링 하는법을 찾아봤다.

많은 난항이 있었다...

일단 get메소드로 html파일을 가져오고 cheerio라이브러리를 사용해 html파일에서 원하는 클래스 혹은 태그에서 데이터를 가져왔다.

await axios
  .get(
    `https://search.naver.com/search.naver?where=nexearch&sm=tab_etc&mra=blMy&qvt=0&query=${query}%20%EB%AA%85%EC%96%B8`,
  )
  .then((res) => {
    famousKR = [];
    famousEN = [];
    famousWriterKR = [];
    famousWriterEN = [];
    const $ = cheerio.load(res.data);
    $('.wise_sy .lst .viewlst .stnbx .lngkr').each(function () {
      famousKR.push($(this).text());
    });
    $('.wise_sy .lst .viewlst .stnbx .lngeng').each(function () {
      famousEN.push($(this).text());
    });
    $('.wise_sy .lst .viewlst dl > dt > a').each(function () {
      famousWriterKR.push($(this).text());
    });
    $('.wise_sy .lst .viewlst dl .engnm').each(function () {
      famousWriterEN.push($(this).text());
    });
    famousAllData = [famousKR, famousEN, famousWriterKR, famousWriterEN];
  })
  .catch((error) => {
    console.log(error);
  });

네이버 명언의 카테고리 별로 객체에 키와 쿼리를 담아놨다.

const famousCategory = {
  love: { hash: '%EC%82%AC%EB%9E%91' }, // 사랑
  life: { hash: '%EC%9D%B8%EC%83%9D' }, // 인생
  study: { hash: '%EA%B3%B5%EB%B6%80' }, // 공부
  success: { hash: '%EC%84%B1%EA%B3%B5' }, // 성공
  friend: { hash: '%EC%B9%9C%EA%B5%AC' }, // 친구
  book: { hash: '%EB%8F%85%EC%84%9C' }, // 독서
  parting: { hash: '%EC%9D%B4%EB%B3%84' }, // 이별
  time: { hash: '%EC%8B%9C%EA%B0%84' }, // 시간
  effort: { hash: '%EB%85%B8%EB%A0%A5' }, // 노력
  hope: { hash: '%ED%9D%AC%EB%A7%9D' }, // 희망
  challenge: { hash: '%EB%8F%84%EC%A0%84' }, // 도전
  confidence: { hash: '%EC%9E%90%EC%8B%A0%EA%B0%90' }, // 자신감
};
const query = famousCategory[key].hash;

await axios
  .get(
    `https://search.naver.com/search.naver?where=nexearch&sm=tab_etc&mra=blMy&qvt=0&query=${query}%20%EB%AA%85%EC%96%B8`,
  )

그러면 쿼리라는 변수에서 명언의 카테고리별로 키를 가져와 각각 해당하는 html을 가져올 수 있다.

클라이언트에서 보낸 버튼의 값이 서버에서 만든 객체의 키에 있을 때만 코드가 작동하도록 객체를 돌리는 for..in문을 사용했다.

for (const key in famousCategory) {
    if (key.indexOf(req.body.category) !== -1) {
      ...코드
    }
}

클라이언트에서 일단 서버로 보낼 수 있도록 명언 카테고리에 맞게 버튼을 만들었다.

 const onFamousHandler = useCallback((e) => {
    e.preventDefault();
    setCurrentCategory(e.target.innerHTML);
    axios
      .post('/api/famous', { category: e.target.innerHTML })
      .then((res) => {
        setFamousData(res.data);
      })
      .catch((error) => console.log(error));
  }, []);

버튼을 클릭하면 서버에 크롤링한 데이터를 가져오는 함수를 실행시키도록 했다.

그리고 서버에서 받은 데이터를 FamousData라는 state에 저장해서 사용한다.

서버에서 받은 데이터는 한글명언, 영어명언, 유명인사의 한글/영어 이름으로 나누어진 2차원 배열로 되어있어서 아래와 같이 map함수 안에서 안에 있는 배열의 데이터를 props로 리스트 컴포넌트에 보냈다.

배열의 모든 인덱스만큼 돌면 필요 없는 명언데이터까지 보내버리기 때문에 map함수 안에서 인덱스에 조건을 걸어 렌더링 되도록 했다.

return (
    <Container>
      {famousCategories.map((category, i) => (
        <Button key={i} onClick={onFamousHandler}>
          {category}
        </Button>
      ))}
      {indexArray.map((list, i) =>
        i < 20 ? (
          <FamousSayingList
            key={i}
            famousKR={famousData[0][i]}
            famousEN={famousData[1][i]}
            writerKR={famousData[2][i]}
            writerEN={famousData[3][i]}
          />
        ) : (
          ''
        ),
      )}
    </Container>
  );

명언 카테고리 버튼을 누르면 해당하는 명언리스트를 렌더링해준다.

profile
https://kyledev.tistory.com/

0개의 댓글