TigerCow.Door


안녕하세요. 문범우입니다.

이번 포스팅에서는 조인의 개념에 대해서 알아보고 기초적인 이너조인(Inner JOIN), 아우터조인(Outer JOIN), 크로스조인(Cross JOIN), 셀프조인(Self JOIN)에 대해서 함께 알아보도록 하겠습니다.



1. 조인(JOIN)이란 무엇일까?


DB에서 자주 사용되는 조인이란 개념은 무엇일까요?

조인은 '어울리다'라는 의미를 가지고 있는데 이 말대로, 데이터베이스에서 테이블간의 결합(어울림)을 이야기합니다.

즉, 두개 이상의 테이블에 대해서 결합하여 나타낼 때 조인이라는 것을 이용합니다.

물론 셀프조인에서는 사실 하나의 테이블을 다루는 것입니다. 이에 대해서는 뒤에서 다시 이야기해보겠습니다.


예시데이터를 가지고 살펴보겠습니다.

예시데이터는 이전의 글들에서 사용된 employee 테이블과 department 테이블을 사용하며, employee테이블에 아래와 같이 하나의 데이터를 추가해서 진행해보도록 하겠습니다.


insert into employee (empNo, empName, job, manager, hireDate, salary, commission)

values (1015, '문정진', '대리', 1001, '2009-11-11', 350, 50);


select * from employee;


select * from department;



만약 우리가 사원의 이름과 그가 속한 부서를 알고 싶을 땐 어떻게 해야할까요?

기존의 방법으로 employee 테이블을 통해 조회한다면 다음과 같을 것 입니다.


select empName, deptNo from employee;



하지만 위와 같은 결과는 부서이름이 아니라 부서 코드를 넣어 주었기 때문에 사실 어떤 직원이 어떤 부서에 속했는지 한눈에 보기 힘듭니다.

그런데 어떤 부서코드가 어떤 부서인지에 대한 정보는 department 테이블에 있습니다.

즉, 아래와 같이 하나의 결과에서 employee 테이블과 departement 테이블을 매핑시켜준다면 직원의 이름과 그 직원이 속한 부서의 이름을 보다 쉽게 알 수 있겠죠?

이럴 때 사용되는 것이 바로 조인(JOIN)입니다.



조인의 종류에는 처음에 말씀드렸듯 크게4가지, 이너조인, 아우터조인, 크로스조인, 셀프조인이 있습니다.

그럼 각각의 조인에 대해서 간단하게 알아보겠습니다.



2. 이너 조인(INNER JOIN)


이너조인은 위와 같이 우리가 조인하고자 하는 두개의 테이블에서 공통된 요소들을 통해 결합하는 조인방식입니다. 즉 우리가 위에서 하고자 했던, 직원들의 이름과 부서명을 같이 출력하는데 있어서 사용되는 가장 일반적인 조인이죠. sql에서도 단순히 조인을 사용할때는 암묵적으로 이너조인을 뜻하게 됩니다.


기본적인 이너조인의 SQL형태는 다음과 같습니다.


SELECT table1.col1, table1.col2, ..., table2.col1, table2.col2, ...

FROM table1 [table1의 별칭]

JOIN table2 [table2의 별칭] ON table1.col1 = table2.col2


위의 쿼리에서 대괄호로 사용된 각 테이블의 별칭은 SELECT 절에서 컬럼이름 앞에 붙는 테이블명에서 사용될 수 있습니다.

조인시에 table1과 table2의 어떤 컬럼을 기준으로 할지는 ON 뒤에 작성합니다.

즉 위의 쿼리에서는 table1의 col1 컬럼과 table2의 col2 컬럼이 같은 행들에 대해서 조인을 실시합니다.


그럼 바로 이너조인을 통해서 직원의 이름과 부서명을 함께 출력해보도록 합시다.


select employee.empName, department.deptName

from employee

join department on employee.deptNo = department.deptNo



위와 같이 join문을 통해서 직원의 이름과 부서명을 함께 출력하였습니다.

employee 테이블의 deptNo과 department 테이블의 deptNo이 같은 것끼리 결합하여 직원이름과 부서명을 출력한 것이죠.



3. 아우터 조인(OUTER JOIN)



아우터 조인은 위의 그림과 같이 레프트 아우터 조인, 라이트 아우터 조인 그리고 그 두개를 합친 풀 아우터 조인 총3개가 있습니다.

아우터 조인은 그림과 같이 두 테이블의 공통영역을 포함해 한쪽 테이블의 다른 데이터를 포함하는 조인방식입니다.

아우터 조인을 보다 쉽게 이해하기 위해서 위에서 진행한 이너 조인의 결과를 한번 더 살펴보겠습니다.



위의 결과에서는 사실 누락된 데이터가 있습니다.

employee 테이블을 기준으로 보면 '문정진'이라는 이름의 사원데이터가 누락되어 있으며, department 테이블을 기준으로 보면 '전산부'라는 부서가 누락되어 있습니다.

해당 데이터들이 누락된 이유는 두 테이블간의 공통된 데이터가 없기 때문이죠.

다시말해서, '문정진'사원의 deptNo가 NULL이기 때문에 department 테이블과 공통된 점이 없으며, '전산부' 또한 employee 테이블에서 같은 부서코드를 가진 데이터가 없기 때문에 출력되지 않은 것 입니다.

하지만 이러한 데이터들도 함께 보고싶은 경우가 있고, 그런 경우에 우리는 아우터 조인을 사용합니다.


이때 left와 outer를 정하는 기준은 from절에 적어준 테이블이 left가 되고, join절에 적어준 테이블이 right가 됩니다. 그럼 먼저 부서코드가 NULL이거나 부서테이블의 deptNo과 일치하는 값이 없는 사원까지 출력하는 left 아우터 조인을 쿼리로 확인해보도록 합시다.


select employee.empName, department.deptName

from employee

left outer join department on employee.deptNo = department.deptNo



위의 결과를 보시면 이전에 실습했던 이너조인과 달리 '문정진'사원의 데이터도 함께 나오는 것을 확인할 수 있습니다.


그럼 이어서 right 아우터 조인과, full 아우터 조인도 확인해보겠습니다.


select employee.empName, department.deptName

from employee

right outer join department on employee.deptNo = department.deptNo



select employee.empName, department.deptName

from employee

full outer join department on employee.deptNo = department.deptNo



앞에서 설명한 바와 같이 right 아우터 조인은 '전산부' 데이터도 함께 출력되고 있으며, full 아우터 조인은 left 아우터 조인과 right 아우터 조인의 결과를 합친 것과 같습니다.



4. 크로스 조인(CROSS JOIN)


크로스 조인은 사실 앞에서 진행한 이너 조인 및 아우터 조인과 약간의 차이가 존재합니다.

이너 조인과 아우터 조인은 두 테이블간의 특정 기준에 의해 데이터 결합의 결과를 보여주는 방식이었다면, 크로스 조인은 특정 기준 없이, 두 테이블간 가능한 모든 경우의 수에 대한 결합을 결과로 보여주는 방식입니다.


쿼리를 작성할 때에도, 특정한 기준이 필요없으므로 on절이 없어지게 됩니다.

바로 쿼리로 확인해보도록 하겠습니다.


select employee.empName, department.deptName

from employee

cross join department



위와 같이 모든 경우에 수에 대한 결과가 출력되기 때문에 출력 데이터의 행수는 총 15(employee의 모든 행의 개수) * 4(department의 모든 행의 개수) 으로써 60개 입니다.



5. 셀프 조인(SELF JOIN)


셀프조인은 말 그대로 자기 스스로를 결합시키는 조인입니다. 셀프조인은 이너조인 및 아우터 조인, 크로스 조인과 동일한 방식으로 사용될 수 있지만 조인을 할 때에 기본 테이블 이외에 참조하는 테이블이 다른 테이블이 아닌 자기 자신이라는 점이 중요합니다.

셀프조인이 어떤식으로 사용되는지에 대해서 employee 테이블의 데이터를 한번 더 보면서 설명드리겠습니다.



위의 결과를 보면 사원들이 이름과 더불어 manager라는 항목이 존재합니다.

만약 우리가 사원들의 이름과 함께 그 사원의 manager의 이름도 함께 알고 싶다면 어떻게 할까요?

참조할 다른 테이블도 존재하지 않습니다. 이럴 때 우리는 셀프조인을 이용합니다. 즉 employee 테이블, 자기 자신을 조인하는 것 입니다.

이때 우리는 위에서 각 테이블에 대한 별칭을 선택적으로 사용했지만 셀프 조인시에는 별칭을 필수로 입력해주어야 합니다. 같은 테이블을 2개 또는 그 이상 사용하는데 별칭을 정해주지 않으면 혼동되기 때문이죠.


그럼 앞서 말씀드린 상황, 직원의 이름과 그 manager의 이름을 동시에 출력하는 쿼리를 셀프조인 방식으로 확인해보도록 하겠습니다.


select emp1.empNo 사원번호, emp1.empName 직원이름,

emp1.manager 매니저번호, emp2.empName 매니저이름

from employee emp1

join employee emp2 on emp1.manager = emp2.empNo



위와 같이 쿼리의 기본형태는 이너조인과 동일하지만 참조하는 테이블이 from절에 오는 기본 테이블과 동일하며, 별칭을 적어줌으로써 구별하는 모습을 볼 수 있습니다.



블로그 이미지

Tigercow.Door

Web Programming / Back-end / Database / AI / Algorithm / DeepLearning / etc

댓글을 달아 주세요



안녕하세요 문범우입니다.

이번 포스팅에서는 IN, EXISTS, NOT IN, NOT EXISTS 에 대해서 보다 상세하게 알아보려고 합니다.

해당 내용은 꼭 SQL Server 뿐만 아니라 MySQL 등에서도 포괄적으로 적용되는 내용입니다.



0. 데이터 세팅


먼저 각 구문에 대해서 비교를 할 때 보다 쉽게 확인할 수 있도록 가상 데이터를 세팅해보도록 하겠습니다. 총 2개의 테이블을 생성하며 각 테이블의 이름과 데이터는 아래와 같습니다.


SELECT * FROM TB_FOOD;




SELECT * FROM TB_COLOR;




1. IN


SELECT * FROM TB_FOOD f

WHERE f.number IN (SELECT c.number FROM TB_COLOR c);


위와 같은 쿼리를 실행하면 어떤 결과가 나올까요?

먼저 결과를 살펴보면 다음과 같습니다.



이는 우리가 어느정도 예상할 수 있는 결과입니다. 하지만 실제로 IN 을 포함한 쿼리가 어떻게, 어떤 식으로 작동되는지 알아야 이후에 EXISTS 또는 NOT IN / NOT EXISTS와 헷갈리지 않습니다.


위의 쿼리에서는 제일먼저 TB_COLOR 테이블에 접근하게 됩니다.

즉, IN 뒤에 있는 괄호의 서브쿼리를 먼저 실행해서 그에 대한 요소를 가져오는 것이죠.

따라서 사실 IN뒤에 괄호안에는 서브쿼리 이외에도 직접 요소값을 적어줄 수 있습니다.


이후에는 TB_FOOD에서 하나의 레코드를 가져오며 그 레코드의 number 값이 앞에서 가져온 IN 이하의 요소들에 포함되어 있는지를 체크합니다. 그리고 IN 이하의 요소들 중 하나라도 일치한다면 그 레코드를 출력하게 되는 것이죠.


여기서 중요한 것은, 쿼리에서 TB_COLOR에 먼저 접근하여, number 값들을 가져와 리스트로 IN 이하에 뿌려주고, 그 이후에 TB_FOOD에서 하나의 레코드씩 IN 이하의 요소들과 일치하는지 비교한다는 것 입니다.



2. EXISTS


그럼 EXISTS는 어떻게 동작하는지 쿼리와 그 결과를 보도록 합시다.


SELECT * FROM TB_FOOD f

WHERE EXISTS (SELECT c.number FROM TB_COLOR c);



무언가 이상합니다. 우리가 기대했던 결과와는 달리 TB_FOOD 테이블이 그대로 출력되었습니다. 왜 이럴까요? 이는 EXISTS 구문에 대해서 정확히 알지 못하고 잘못 사용하였기 때문에 나온 결과입니다.


위의 쿼리를 기준으로 DB가 어떻게 동작하는지 한번 알아보겠습니다.

IN구문에서는 IN 이후에 나오는 소괄호 내부의 서브쿼리에 대해서 먼저 접근하였습니다. 하지만 EXISTS 구문에서는 다릅니다. 먼저 TB_FOOD에 접근하여 하나의 레코드를 가져오고 그 레코드에 대해서 EXISTS 이하의 서브쿼리를 실행하고 서브쿼리에 대한 결과가 '존재하는지'를 확인합니다.


예시를 들어 생각해보면, 제일 처음에 [ 1 / 치킨 ] 이라는 레코드를 가져왔을 것이고, 해당 레코드에 대해서 SELECT c.number FROM TB_COLOR c 쿼리를 통해 결과가 나오는지 확인합니다. 이때 서브쿼리에 대해 어떠한 결과라도 존재하기만 한다면 참이 되어서 [ 1 / 치킨 ] 레코드가 출력됩니다.

그런데 SELECT c.number FROM TB_COLOR c 쿼리는 사실 TB_FOOD의 어떠한 레코드하고도 연관이 없이 항상 결과값을 가지는 쿼리입니다. 따라서 TB_FOOD의 모든 레코드가 출력되는 것 이죠.


그럼 이를 우리가 기대하는 결과대로 출력하도록 하기 위해서는 다음과 같이 쿼리를 수정하면 됩니다.


SELECT * FROM TB_FOOD f

WHERE EXISTS (SELECT c.number FROM TB_COLOR c WHERE c.number = f.number);



이렇게 나온 결과는 사실 IN 구문과 같은 결과를 출력합니다. 하지만 내부적으로 쿼리가 동작하는 방식은 아예 다르다는 것에 주의하시길 바랍니다. 그러한 내부 로직에 따라서 성능차이도 크게 발생하기 때문입니다.



3. NOT IN


이번에는 NOT IN 구문입니다.

먼저 쿼리와 그 결과를 보고 함께 생각해보겠습니다.


SELECT * FROM TB_FOOD f

WHERE f.number NOT IN (SELECT c.number FROM TB_COLOR c);



위의 쿼리를 실행하니 위의 사진과 같이 아무런 결과도 출력되지 않았습니다. 왜 그럴까요?

우리가 처음에 알아본 IN의 방식에 대해서 알아봅시다. IN은 먼저 소괄호의 서브쿼리를 실행합니다. 그럼 SELECT c.number FROM TB_COLOR c 의 쿼리가 실행되고 그 결과로 다음의 리스트가 반환됩니다.


( 1, 2, 3, 4, 5, 6, NULL )


즉, 초기의 쿼리는 다음과 같은 쿼리인 것입니다.


SELECT * FROM TB_FOOD f

WHERE f.number NOT IN ( 1, 2, 3, 4, 5, 6, NULL );


그럼 이제 TB_FOOD에서 하나의 레코드씩 가져올 것이고 IN이 아니라 NOT IN 구문이기 때문에 소괄호의 요소들과 일치하지 않아야 결과로 반환됩니다.


TB_FOOD의 레코드들 중에서 [ 7 / 사탕 ] 레코드를 예로 들어서 생각해보면 해당 레코드의 number 값인 7이 NOT IN 이하의 소괄호에 있는지 확인하면 됩니다. 분명히 7이라는 요소는 존재하지 않습니다. 따라서 우리의 생각대로 라면 해당 레코드는 결과로 출력되어야 하는데 위에서 본 것 처럼 출력되지 않았습니다. 왜 일까요?


이는 DB 에서 해당 요소가 NOT IN 이하의 소괄호의 요소들에 대한 포함여부를 어떻게 판단하는지를 알면 쉽게 이해할수 있습니다. 사실 위의 쿼리는 아래의 쿼리와 같이 동작함으로써 NOT IN 이하의 소괄호에 대한 포함 여부를 판단하게 됩니다.


SELECT * FROM TB_FOOD f

WHERE f.number != 1

AND f.number != 2

AND f.number != 3

AND f.number != 4

AND f.number != 5

AND f.number != 6

AND f.number != NULL;

즉, NOT IN 구문은 TB_FOOD에서 가져온 레코드의 number 값이 소괄호의 모든 요소들과 일치하지 않는지를 체크하는 것입니다. 그런데 위에서는 number 값이 NULL과 연산을 진행하게 되는데, 이때 NULL과의 비교연산은 항상 UNKNOWN 값을 반환하게 됩니다. 따라서 WHERE 절 이하가 TRUE가 아니므로 해당 레코드가 출력되지 않게 되는 것이죠.


이렇게 NOT IN이 어떻게 동작하는지를 알고보니 결국 TB_COLOR에 존재하는 NULL 때문에 우리가 기대하던 결과가 나오지 않음을 알 수 있었습니다. 그럼 우리가 기대한 결과가 나오게 하려면 다음과 같이 쿼리를 수정하면 됩니다.


SELECT * FROM TB_FOOD f

WHERE f.number NOT IN (SELECT c.number FROM TB_COLOR c WHERE c.number IS NOT NULL);


 



4. NOT EXISTS


그럼 마지막으로 NOT EXISTS에 대해서 알아보도록 하겠습니다.

오히려 NOT EXISTS는 위에서 EXISTS에 대해서 이해했다면 크게 어려운 점이 없습니다. 하지만 그 결과가 NOT IN과 약간 다르죠. 쿼리와 결과를 먼저 보도록 하겠습니다.


SELECT * FROM TB_FOOD f

WHERE NOT EXISTS (SELECT c.number FROM TB_COLOR c WHERE c.number = f.number);



위에서 NOT IN을 사용했을 때에는 number 값이 NULL인 레코드는 출력되지 않았습니다. 그 이유를 다시 생각해보자면, IN 구문은 요소간에 비교 연산으로 레코드가 출력되는데 NULL 값에 대한 비교연산은 항상 UNKNOWN을 반환하기 때문이었습니다. 

하지만 앞에서 알아볼 때 EXISTS 구문은 다르게 동작했습니다. 위 쿼리를 기준으로 한다면 먼저 TB_FOOD에서 레코드를 가져오고 해당 레코드의 number를 NOT EXISTS 이하의 서브쿼리에 전달하여 해당 서브쿼리에서 값이 존재하는지를 확인합니다. EXISTS 구문이었다면 값이 존재할 때 해당 레코드를 출력하지만, NOT EXISTS 구문이기에 해당 서브쿼리의 값이 존재하지 않으면 해당 레코드를 출력합니다.


여기서 NULL이 출력하는 과정을 한번 더 자세하게 알아보자면, [ NULL / 타코 ] 레코드를 예로 들었을 떄, number = NULL 입니다. 따라서 NOT EXISTS 이하의 쿼리를 확인해보면 다음과 같을 것 입니다.


SELECT c.number FROM TB_COLOR c WHERE c.number = NULL;


이때 우리가 NOT IN에서 알아본 것과 같이 NULL에 대한 비교연산은 항상 UNKNOWN 값을 반환하므로 해당 쿼리의 결과가 존재하지 않게 되고, 이에 따라서 [ NULL / 타코 ] 레코드가 출력되는 것 입니다.



이렇게 IN, EXISTS, NOT IN, NOT EXISTS 에 대해서 알아보았습니다.

저 또한 많이 헷갈리던 개념들아었는데 다시 한번 정리하고 나니 확실히 개념이 잡히는 것 같습니다. IN과 EXISTS는 성능에 대해서도 많은 이슈를 가져오는 구문들이니 그 차이를 확실히 짚고 넘어가는 것을 추천드립니다.


혹시 내용이 잘못되었거나 더 궁금하신 점이 있다면 언제든지 말씀해주시면 감사하겠습니다.

블로그 이미지

Tigercow.Door

Web Programming / Back-end / Database / AI / Algorithm / DeepLearning / etc

댓글을 달아 주세요


안녕하세요. 문범우입니다.

이번 글에서는 SQL Server에서의 순위함수들(RANK, DENSE_RANK, ROW_NUMBER, NTILE)에 대해서 알아보며 함께 PARTITION BY 절에 대해서도 함께 알아보도록 하겠습니다.



이번 실습 또한 과거 글에서 만들었던 SampleDB를 통해 진행하도록 하겠습니다.


SELECT * FROM employee;



먼저 RANK, DENSE_RANK, ROW_NUMBER 세가지 함수에 대해서 알아보겠습니다. 먼저 각각의 함수에 대해 간략한 설명과 함께 쿼리를 통해 결과를 확인해보고 세가지 함수의 차이에 대해서 함께 알아보도록 하겠습니다.



1. RANK


RANK 함수는 중복 값들에 대해서 동일 순위로 표시하고, 중복 순위 다음 값에 대해서는 중복 개수만큼 떨어진 순위로 출력하도록 하는 함수 입니다.


SELECT empNo, empName, salary,

RANK() OVER (ORDER BY salary DESC) RANK등수

FROM employee;




2. DENSE_RANK


DENSE_RANK 함수는 중복 값들에 대해서 동일 순위로 표시하고, 중복 순위 다음 값에 대해서는 중복 값 개수와 상관없이 순차적인 순위 값을 출력하도록 하는 함수 입니다.


SELECT empNo, empName, salary,

DENSE_RANK() OVER (ORDER BY salary DESC) DENSE_RANK등수

FROM employee;




3. ROW_NUMBER


ROW_NUMBER 함수는 중복 값들에 대해서도 순차적인 순위를 표시하도록 출력하는 함수 입니다.


SELECT empNo, empName, salary,

ROW_NUMBER() OVER (ORDER BY salary DESC) ROW_NUMBER등수

FROM employee;




4. RANK / DENSE_RANK / ROW_NUMBER


위에서 3가지 함수에 대해서 각각 알아보았습니다.

크게 어려운 내용들은 아니기에 각 함수에 대한 설명과 쿼리문 그리고 그에 대한 결과를 보여드렸습니다.

하지만 세가지 함수의 차이에 대해서는 약간 헷갈릴 수 있기에 이번에는 3가지 함수를 동시에 사용해서 차이를 비교해보도록 하겠습니다.


SELECT empNo, empName, salary,

RANK() OVER (ORDER BY salary DESC) RANK등수,

DENSE_RANK() OVER (ORDER BY salary DESC) DENSE_RANK등수,

ROW_NUMBER() OVER (ORDER BY salary DESC) ROW_NUMBER등수

FROM employee;



세가지 함수의 차이를 고려하려면 위 결과의 빨간색 박스를 보면 됩니다.

salary 값이 500으로 중복된 행이 총 3개 존재합니다.


먼저 RANK함수는

중복 값에 대해서 동일한 순위 그리고

중복 값 다음 값에 대해서 중복순위 + 중복값 개수 의 순위를 출력합니다.


DENSE_RANK함수는

중복 값에 대해서 동일한 순위 그리고

중복 값 다음 값에 대해서 중복순위 + 1 의 순위를 출력합니다.


ROW_NUMBER함수는

중복 값에 대해서 순차적인 순위 그리고

중복 값 다음 값에 대해서 또한 순차적인 순위를 출력합니다.



5. NTILE


NTILE 함수도 순위함수로 사용되지만 위에서 사용된 함수들과는 약간 다르게 느껴질 수 있습니다.

NTILE함수는 뒤에 함께 적어주는 숫자 만큼으로 등분을 하는 함수 입니다.

만약 직원들 데이터에 대해서 salary 순서를 기준으로 4등분을 하고자 한다면 다음과 같습니다.


SELECT empNo, empName, salary,

NTILE(4) OVER (ORDER BY salary DESC) NTILE등분

FROM employee;





6. PARTITION BY


PARTITION BY 절 또한 어렵지 않습니다.

만약 위와 같은 데이터에서 단순히 모든 사람의 salary를 순위 매기고 싶은 것이 아니라, 직급별 순위를 매기고 싶다면 어떻게 할까요?

직급 별로 구분을 해서 순위를 매기면 됩니다. 이렇게 특정 속성 별로 구분을 하고자 할 때 PARTITION BY절을 사용하면 됩니다.


SELECT empName, job, salary,

RANK() OVER (PARTITION BY job ORDER BY salary DESC) RANK등수

FROM employee;



블로그 이미지

Tigercow.Door

Web Programming / Back-end / Database / AI / Algorithm / DeepLearning / etc

댓글을 달아 주세요

안녕하세요. 문범우입니다.

오랜만에 파이썬으로 필요한 프로그램을 만들어 공유하려고 글 작성합니다.

소개해드리고자 하는 프로그램은


중고나라에서 키워드 검색후 게시글 크롤링 및 메일 발송

기능을 가진 프로그램입니다.


모든 소스코드는 아래의 github주소에 공개되어있습니다.

https://github.com/doorBW/joonggonara_crawl


간단하게 활용 스택 및 배운점 등을 공유하겠습니다.


1. 활용 스택


- Python 3.7.1

- pyenv 및 virtualenv를 통한 가상환경설정

- Selenium / BeautifulSoup / smtplib / dotenv 라이브러리 활용

- ubuntu crontab 활용


위와 같은 언어 및 라이브러리를 활용하였습니다.

crawl.py 에서 중고나라 사이트에 접속하여 사전에 설정해놓은 키워드로 검색을 하고

50개씩 보기를 선택한 후에 중복 글쓴이를 제외한 나머지 게시글을 리스트로 만들어서 메일로 발송합니다.

해당 파일은 aws의 개인서버에 두고 crontab을 활용하여 정해진 시각에 실행되도록 설정하였습니다.



2. 배운 점


과거에 selenium을 활용해본적은 있으나, 이번에 보다 많이 활용해본 것 같습니다.

네이버 카페에서 게시글이 나오는 쪽이 iframe으로 설정되어 있어 selenium에서 frame도 바꿔주어야 했고,

50개씩 보기를 선택하면서 보다 활용도가 높았던 것 같습니다.

활용할수록 매우 재미있는 라이브러리 같아서, 여름쯤 시간내서 한번 더 깊게 공부해보면 재미있을 것 같습니다.

관련되서 재밌는 프로젝트들에 대해서 아시는게 있다면 알려주세요 :)

이 외에 다른 라이브러리나 ubuntu crontab 활용에 대해서는 과거에 사용해봤던 것과 동일했기 때문에 따로 언급하지 않겠습니다.



3. 더 공부해볼 점


사실상 게시글 제목을 중심으로 크롤링을 진행했지만, 그러한 제목에는 상품의 가격이 제대로 나와있지 않습니다.

가격 또한 쉽게 보려면 게시글에 들어가서 내용을 검토해야 하는데, 그렇게 하지 않은 이유는 게시글 내용에서도 가격이 정확하게 나와 있지 않기 때문입니다.

중고나라에서 가격을 적는 칸이 있지만, 사실 대다수가 지키지 않고 있는 실정입니다.

이에 따라서 게시글 내용을 text로 반환 받아 그 내용 중 상품 가격을 추출할 수 있다면 매우 활용적일 수 있습니다.

인공지능 분야에서도 자연어처리 분야에 대해 지식이 필요할 것 같은데, 혹시 관련되서 내용을 아시거나, 다른 방법으로 해당 문제를 해결할 수 있는 방안에 대해서 아신다면 댓글 부탁드립니다!


블로그 이미지

Tigercow.Door

Web Programming / Back-end / Database / AI / Algorithm / DeepLearning / etc

댓글을 달아 주세요