[항해 99] - 10주차 회고

이번 주에 한 것

  • 실전 프로젝트 (2/25 ~ )

1. 실전 프로젝트 (2/25 ~)

https://github.com/Tacocat3/real-project : 백엔드 깃허브 주소입니다. 이후 프론트와 백이 통합된 레포지로 변경될 예정입니다.

실전 프로젝트가 어느덧 3주차를 마쳤습니다. 이번 주에는 기획과 서비스의 방향도 확실해지고 팀원 분들의 컨디션 이슈도 모두 해결되서 일주일동안 완전히 집중해서 기능구현에 힘을 쏟을 수 있었습니다. MVP구현을 목표로 다같이 쉼없이 달린 결과 비록 목표했던 모든 항목을 달성하지는 못했지만 나름 결과물을 만들어낼 수 있었던 것 같아 뿌듯한 한 주였습니다. 다음주에는 MVP의 모든 항목 달성 및 실제 서비스 배포, MVP이후에 계획되어 있는 미구현 기능들을 목표로 달려나가고자 합니다.

무엇을 만들었나요? 🧐

1. 랜덤한 하나의 스크립트 불러오기

module.exports.findScript = async (req, res) => {
  const { scriptType, scriptCategory } = req.params;
  try {
    if (scriptType === "all" && scriptCategory === "all") {
      const script = await Script.aggregate([{ $sample: { size: 1 } }]);
      res.json({
        script,
        ok: true,
      });
    } else if (scriptCategory === "all" && scriptType !=="all")  {
      console.log(11)
      const script = await Script.aggregate([
        { $match: { scriptType: scriptType } },
        { $sample: { size: 1 } },
      ]);
      res.json({
        script,
        ok: true,
      });
    } else {
      const script = await Script.aggregate([
        { $match: { scriptType: scriptType, scriptCategory: scriptCategory } },
        { $sample: { size: 1 } },
      ]);
      res.json({
        script,
        ok: true,
      });
    }
  } catch (err) {
    console.log(err);
    res.status(200).send({
      ok: false,
      errorMessage: "해당 값이 존재하지 않습니다.",
    });
  }
};

MongoDB의 aggreation 명령어인 match와 sample을 통해 입력받은 카테고리 내에서 해당하는 랜덤한 스크립트 하나를 불러오는 기능을 구현했습니다. 기능 구현이 급해서 신경을 쓰지 못한 부분이 여럿 있는데, if ~ else구문이 아닌 switch구문으로 코드 변경 및 http상태코드 변경, 조금 더 읽기 쉬운 코드로 변경하고자 합니다.

2. 필터링을 통한 스크립트 리스트 불러오기

module.exports.scriptFilter = async (req, res) => {
  req.url;
  try {
    const scriptCategory = req.query.scriptCategory;
    const scriptTopic = req.query.scriptTopic;
    if (scriptCategory === "all" && scriptTopic === "all") {
      const scripts = await Script.find();
      res.json({
        scripts,
        ok: true,
      });
    } else if (scriptCategory === "all" && scriptTopic !=="all") {
      const scriptTopicList = scriptTopic.split("|")
      const scripts = await Script.find(
        { scriptTopic: { $in: scriptTopicList } },
      );
      res.json({
        scripts,
        ok: true,
      });
    } else if (scriptTopic === "all" && scriptCategory !== "all") {
    const scriptCategoryList = scriptCategory.split("|")
      const scripts = await Script.find(
         { scriptCategory: { $in:  scriptCategoryList } } 
      );
      res.json({
        scripts,
        ok: true,
      });
    } else {
        const scriptCategoryList = scriptCategory.split("|")
        const scriptTopicList = scriptTopic.split("|")
        const scripts = await Script.find(
          { scriptCategory: { $in: scriptCategoryList}, scriptTopic: { $in: scriptTopicList} },
     );
      res.json({
        scripts,
        ok: true,
      });
    }
  } catch (err) {
    console.log(err);
    res.status(200).send({
      ok: false,
      errorMessage: "해당 값이 존재하지 않습니다.",
    });
  }
};

in을 통해서 선택된 스크립트 카테고리 및 토픽에 해당하는 리스트를 불러오는 기능입니다. 1번과 동일한 개선을 목표로 하고 있습니다.

3.스크립트 스크랩핑(with selenium-webdriver)

let scriptParagraphs = [];

async function crawlingScript(url) {
  let driver = await new Builder()
    .forBrowser("firefox")
    .setFirefoxOptions(
      new firefox.Options()
        .headless()
        .setPreference("javascript.enabled", false)
    )
    .build();
  try {
    await driver.get(
      url
    );
    scriptTitle = await driver.findElement(
      By.className(<classname>)
    ).getText()
    paragraphResults = await driver.findElements(
      By.className("<classname>")
    );
    for (let i = 0; i < paragraphResults.length; i++) {
      const singleParagraph = await paragraphResults[i].getText();
      scriptParagraphs.push(singleParagraph);
    }
    
    return {
      scriptTitle : scriptTitle,
      scriptType : 'null', //data.scriptType,
      scriptCategory : 'null', //data.scriptCategory,
      scriptTopic : [null], //data.scriptTopic.split(","),
      scriptParagraph : scriptParagraphs,
      scriptTranslate : [null], //data.scriptTranslate.split("\n"),
      scriptSource : url //data.scriptSource,
    }

  } catch {
    console.log(err);
    res.status(200).send({
      ok: false,
      errorMessage: "올바르지 않은 형식입니다.",
    });
  } finally {
    driver.quit();
  }
}

const postScript = async (data) => {
  try {
     await Script.create(data);
    
      console.log({
        ok: true,
        message: "등록 완료",
      });
    } catch (err) {
      console.log(err);
    }
};

(
  async () => {
    url = "<Site_url>"
    data = await crawlingScript(url)
    const joinScript = data.scriptParagraph.join(`\n`)
    const resultJoinScript = joinScript.replace(/\“| \”/gi, '\"')
    console.log(joinScript)
     await postScript(data)
  }

사실 이 부분은 미구현된 코드입니다. 시간을 정말 많이 쏟았는데 생각처럼 잘 구현되지 않아서 우선 필수적인 기능들을 위해서 잠시 뒤로 미뤄두었습니다. 애를 많이 먹었던 이유는 firefox.Options()에 있는 .setPreference("javascript.enabled", false) 였는데, 해당 기능은 웹드라이버로 브라우저를 띄웠을 때 자바스크립트를 비활성화시킴으로써 페이지를 읽어오는데 방해가 되는 요소인 가입 후 이용같은 창을 띄우지 못하게 하는 역할을 수행합니다. 해당 내장함수를 찾는 것과 바보같이 Chrome에도 동일한 명령어가 먹힌다고 생각해서 chrome.Options()로 한참을 씨름하는데에 시간을 많이 써버리고 말았습니다. 현재 미구현인 이유는 번역기능 때문인데, 스크립트 자동 번역을 위해 구글 번역 api를 활용을 염두에 두고 있으며, MVP단 및 마이페이지 관련 기능이 모두 완료되면 우선적으로 번역 api를 학습 후 구현해보고자 계획하고 있습니다.


이외에도 정말 많은 일들이 있었습니다. 좀 더 나은 기능을 제공하기 위해서 디자인이 크고 작은 영역에서 변경이 수차례 이루어졌고, 그에 따라 코드도 처음부터 새로 짜여지거나 부분부분의 수정이 이루어져야 했습니다. 많이 빡빡하고 힘든 상황임에도 팀원 분들이 정말 열심히 해주셔서 제 자신도 부끄럽지 않기 위해서 더욱더 집중할 수 있었습니다. 프로그래밍이라는 걸 떠나서 여러가지로 항상 다른 분들께 많이 배우고 있습니다. 모두에게 항상 감사하고 남은 기간도 최선을 다하고자 합니다. 모두들 화이팅입니다!

좋은 웹페이지 즐겨찾기