[Crawling] RIDISELECT

리디셀렉트 보유 도서 리스트 만들기

리디셀렉트를 구독 신청을 하기 전에는 도서 검색이 안 된다. 아래 사이트에서 페이지를 하나하나 넘겨가면서 무슨 책들이 있는지 볼 수밖에 없다.
https://select.ridibooks.com/books
도서 리스트가 있으면 검색하기와 읽고 싶은 책 고르기가 편할 것 같아서 셀레늄으로 책 제목들을 긁어와 도서 리스트를 만들어 봤다.

from selenium import webdriver
import numpy as np
import time
# 브라우저 열기
driver = webdriver.Chrome()

책 목록이 109페이지까지 있는 건 끝으로 가기 버튼을 눌러 확인했다.

book_list = []
for i in range(1, 109):
url = "https://select.ridibooks.com/books?page={}".format(i)
driver.get(url)
time.sleep(2)
book = driver.find_element_by_css_selector(".GridBookList").text.split("\n")
book_list.append(book)

# 브라우저 닫기
driver.quit()

페이지별로 제목을 긁어오기 때문에 리스트 속의 리스트 형태로 저장되는데 이를 하나의 리스트로 변환해 준다.

ls = sum(book_list, [])

리스트가 완성됐으니 csv 파일로 리스트를 만든다. 판다스 데이터프레임으로 만든 뒤 csv 파일로 내보냈다.

import pandas as pd
df = pd.DataFrame({"title": ls})
df.to_csv("ridiselect.csv", mode='w')

csv 파일을 열어서 보고 싶은 책이 있는지 쉽게 검색할 수 있다. 구독한 후에는 보고싶은 책을 미리 체크해두면 좋다.

[MySQL] 4.2 데이터 정렬 - ORDER BY를 활용한 Natural Sorting


http://www.mysqltutorial.org 내용을 따라 익히며 정리한 글입니다.


1. Natural Sorting이란

데이터를 정렬할 때 사람에겐 다음 순서가 자연스럽다.
‘A-1’
‘A-2’
‘A-3’
‘A-4’
‘A-5’
‘A-10’
‘A-11’
‘A-20’
‘A-30’

하지만 콤퓨타가 출동하면 어떨까? 콤퓨타라면 아래처럼 정렬해놓고선 잘했다고 여길 수도 있다.
‘A-1’
‘A-10’
‘A-11’
‘A-2’
‘A-20’
‘A-3’
‘A-30’
‘A-4’
‘A-5’

앞의 예처럼 사람에게 자연스러운 순서로 정렬하는게 바로 Natural Sorting이다. PHP의 경우 natsort() 함수로 간단히 Natural Sorting을 할 수 있지만 MySQL은 얘기가 다르다. ORDER BY 를 활용해 제한적으로만 Natural Sorting이 가능한데 이런 테크닉에 대해서 알아보겠다.

먼저 iditem_no 라는 컬럼이 있는 items 란 테이블을 만든다.

CREATE TABLE IF NOT EXISTS items (
id INT AUTO_INCREMENT PRIMARY KEY,
item_no VARCHAR(255) NOT NULL
);

다음은 위에서 만든 테이블에 데이터를 추가하겠다.

INSERT INTO items(item_no)
VALUES ('1'),
('1C'),
('10Z'),
('2A'),
('2'),
('3C'),
('20D');

위에서 만든 데이터를 item_no 로 정렬해보자.

SELECT
item_no
FROM
items
ORDER BY item_no;
+---------+
| item_no |
+---------+
| 1 |
| 10Z |
| 1C |
| 2 |
| 20D |
| 2A |
| 3C |
+---------+
7 rows in set (0.00 sec)

으으..
숫자 부분을 1, 2, 3, 10, 20 순으로 정렬하고 싶을 때 오더바이를 이용하면 그렇게 되지 않는다. 그렇다면 다음과 같은 결과를 얻으려면 어떻게 해야 할까?

+---------+
| item_no |
+---------+
| 1 |
| 1C |
| 2 |
| 2A |
| 3C |
| 10Z |
| 20D |
+---------+
7 rows in set (0.00 sec)

CAST 함수를 사용해 다음과 같이 쿼리문을 작성하면 원하는 결과를 얻을 수 있다. CAST 함수는 어떤 값을 특정 타입으로 바꿔주는 역할을 한다.

SELECT
item_no
FROM
items
ORDER BY CAST(item_no AS UNSIGNED) , item_no;

또 다른 예를 살펴보자. 먼저 아래 쿼리문으로 데이터를 추가한다.

TRUNCATE TABLE items;

INSERT INTO items(item_no)
VALUES('A-1'),
('A-2'),
('A-3'),
('A-4'),
('A-5'),
('A-10'),
('A-11'),
('A-20'),
('A-30');

위 데이터를 Natural Sorting 하려면 문자값의 길이를 반환하는 LENGTH 함수를 활용할 수 있다.

SELECT
item_no
FROM
items
ORDER BY LENGTH(item_no) , item_no;
+---------+
| item_no |
+---------+
| A-1 |
| A-2 |
| A-3 |
| A-4 |
| A-5 |
| A-10 |
| A-11 |
| A-20 |
| A-30 |
+---------+
9 rows in set (0.00 sec)

좐~~

[MySQL] 4.1 데이터 정렬 - ORDER BY


http://www.mysqltutorial.org 내용을 따라 익히며 정리한 글입니다. 예시에 나오는 데이터셋은 MySQL 샘플 데이터셋인 classicmodels DB입니다.


1. ORDER BY 소개

SELECT 문을 사용할 때 결과셋은 따로 정렬되지 않는데, ORDER BY 절을 사용해 정렬할 수 있다.

2. ORDER BY 예시

다음 쿼리는 customers 테이블에서 성과 이름을 가져온 뒤 성을 기준으로 정렬해 보여준다.

SELECT
contactLastname,
contactFirstname
FROM
customers
ORDER BY
contactLastname
LIMIT 5;
+-----------------+------------------+
| contactLastname | contactFirstname |
+-----------------+------------------+
| Accorti | Paolo |
| Altagar,G M | Raanan |
| Andersen | Mel |
| Anton | Carmen |
| Ashworth | Rachel |
+-----------------+------------------+
5 rows in set (0.00 sec)

내림차순으로 정렬하려면 DESC 를 추가해준다.
따로 표시하지 않거나 ASC 을 써주면 오름차순 정렬이 실행된다.

SELECT
contactLastname,
contactFirstname
FROM
customers
ORDER BY
contactLastname DESC
LIMIT 5;
+-----------------+------------------+
| contactLastname | contactFirstname |
+-----------------+------------------+
| Young | Julie |
| Young | Jeff |
| Young | Mary |
| Young | Dorothy |
| Yoshido | Juri |
+-----------------+------------------+
5 rows in set (0.00 sec)

성은 내림차순으로, 이름은 오름차순으로 정렬하고 싶다면 각각의 컬럼에 DESCASC 를 명시해주면 된다.

SELECT
contactLastname,
contactFirstname
FROM
customers
ORDER BY
contactLastname DESC,
contactFirstname ASC
LIMIT 5;
+-----------------+------------------+
| contactLastname | contactFirstname |
+-----------------+------------------+
| Young | Dorothy |
| Young | Jeff |
| Young | Julie |
| Young | Mary |
| Yoshido | Juri |
+-----------------+------------------+
5 rows in set (0.00 sec)

3. 표현식에 기반한 ORDER BY 정렬

다음 쿼리는 orderdetails 테이블에서 주문번호와 주문라인번호, 주문수량과 단가의 곱을 불러온다.

SELECT
ordernumber,
orderlinenumber,
quantityOrdered * priceEach AS subtotal
FROM
orderdetails
ORDER BY
ordernumber,
orderLineNumber,
subtotal
LIMIT 5;
+-------------+-----------------+----------+
| ordernumber | orderlinenumber | subtotal |
+-------------+-----------------+----------+
| 10100 | 1 | 1729.21 |
| 10100 | 2 | 2754.50 |
| 10100 | 3 | 4080.00 |
| 10100 | 4 | 1660.12 |
| 10101 | 1 | 4343.56 |
+-------------+-----------------+----------+
5 rows in set (0.00 sec)

4. ORDER BY 와 커스텀 정렬

ORDER BY 를 이용하면 FIELD() 함수를 이용해 커스텀 정렬을 정의할 수 있다. 다음 순서대로 정렬을 해야한다고 가정하자.

  • In Process
  • On Hold
  • Cancelled
  • Resolved
  • Disputed
  • Shipped

이 경우 쿼리문은 다음과 같이 작성한다.

SELECT
orderNumber, status
FROM
orders
ORDER BY FIELD(status,
'In Process',
'On Hold',
'Cancelled',
'Resolved',
'Disputed',
'Shipped')
LIMIT 10;
+-------------+------------+
| orderNumber | status |
+-------------+------------+
| 10425 | In Process |
| 10421 | In Process |
| 10422 | In Process |
| 10420 | In Process |
| 10424 | In Process |
| 10423 | In Process |
| 10414 | On Hold |
| 10401 | On Hold |
| 10334 | On Hold |
| 10407 | On Hold |
+-------------+------------+
10 rows in set (0.00 sec)

[MySQL] 3.8 데이터 필터링 - IS NULL


http://www.mysqltutorial.org 내용을 따라 익히며 정리한 글입니다. 예시에 나오는 데이터셋은 MySQL 샘플 데이터셋인 classicmodels DB입니다.


1. IS NULL 소개

값이 NULL 인지 테스트 하려면 다음과 같이 IS NULL 을 사용한다

value IS NULL

값이 NULL 이면 TRUE 를, 아니면 FALSE 를 리턴한다.

MySQL에는 불리언 타입이 내장되어 있지 않다. 대신 TINYINT(1) 를 써서 참트루 일 경우 1, FALSE 면 0으로 표시한다.

IS NULL 은 비교연산자이기 때문에 SELECTWHERE 절에서 쓸 수 있다.

SELECT 1 IS NULL,
0 IS NULL,
NULL IS NULL;
+-----------+-----------+--------------+
| 1 IS NULL | 0 IS NULL | NULL IS NULL |
+-----------+-----------+--------------+
| 0 | 0 | 1 |
+-----------+-----------+--------------+
1 row in set (0.00 sec)

값이 NULL 이 아닌지 확인하고 싶다면 하려면 IS NOT NULL 을 사용한다

value IS NOT NULL

값이 NULL 이 아니면 TRUE(1) 를, 값이 NULL 이면 FALSE(0) 을 리턴한다

SELECT 1 IS NOT NULL,
0 IS NOT NULL,
NULL IS NOT NULL;

+---------------+---------------+------------------+
| 1 IS NOT NULL | 0 IS NOT NULL | NULL IS NOT NULL |
+---------------+---------------+------------------+
| 1 | 1 | 0 |
+---------------+---------------+------------------+
1 row in set (0.00 sec)

2. IS NULL 예시

customers 테이블에서 salesrepemployeenumber 가 없는 데이터들의 고객명, 국가, salesrepemployeenumber 을 가져와 보겠다.

SELECT
customerName,
country,
salesrepemployeenumber
FROM
customers
WHERE
salesrepemployeenumber IS NULL
ORDER BY customerName
LIMIT 5;
+----------------------------+-------------+------------------------+
| customerName | country | salesrepemployeenumber |
+----------------------------+-------------+------------------------+
| ANG Resellers | Spain | NULL |
| Anton Designs, Ltd. | Spain | NULL |
| Asian Shopping Network, Co | Singapore | NULL |
| Asian Treasures, Inc. | Ireland | NULL |
| BG&E Collectables | Switzerland | NULL |
+----------------------------+-------------+------------------------+
5 rows in set (0.00 sec)

salesrepemployeenumber 가 있는 데이터들을 가져오려면 IS NULL 대신 IS NOT NULL 을 써준다.

SELECT
customerName,
country,
salesrepemployeenumber
FROM
customers
WHERE
salesrepemployeenumber IS NOT NULL
ORDER BY customerName
LIMIT 5;
+-------------------------+-----------+------------------------+
| customerName | country | salesrepemployeenumber |
+-------------------------+-----------+------------------------+
| Alpha Cognac | France | 1370 |
| American Souvenirs Inc | USA | 1286 |
| Amica Models & Co. | Italy | 1401 |
| Anna's Decorations, Ltd | Australia | 1611 |
| Atelier graphique | France | 1370 |
+-------------------------+-----------+------------------------+
5 rows in set (0.00 sec)

3. IS NULL 최적화

IS NULL 은 연산자 = 과 같은 방식으로 최적화를 수행한다.

SELECT
customerNumber,
salesRepEmployeeNumber
FROM
customers
WHERE
salesRepEmployeeNumber IS NULL
LIMIT 5;
+----------------+------------------------+
| customerNumber | salesRepEmployeeNumber |
+----------------+------------------------+
| 125 | NULL |
| 169 | NULL |
| 206 | NULL |
| 223 | NULL |
| 237 | NULL |
+----------------+------------------------+
5 rows in set (0.00 sec)

다음은 쿼리의 EXPLAIN 이다.

EXPLAIN SELECT
customerNumber,
salesRepEmployeeNumber
FROM
customers
WHERE
salesRepEmployeeNumber IS NULL;

+----+-------------+-----------+------------+------+------------------------+------------------------+---------+-------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+------+------------------------+------------------------+---------+-------+------+----------+--------------------------+
| 1 | SIMPLE | customers | NULL | ref | salesRepEmployeeNumber | salesRepEmployeeNumber | 5 | const | 22 | 100.00 | Using where; Using index |
+----+-------------+-----------+------------+------+------------------------+------------------------+---------+-------+------+----------+--------------------------+
1 row in set, 1 warning (0.01 sec)

MySQL은 col = value OR col IS NULL 조합도 최적화할 수 있다. 다음의 예를 보면, 최적화가 적용됐을 경우 EXPLAIN 에서 ref_or_null 을 볼 수 있다.

EXPLAIN SELECT
customerNumber,
salesRepEmployeeNumber
FROM
customers
WHERE
salesRepEmployeeNumber = 1370 OR
salesRepEmployeeNumber IS NULL;
+----+-------------+-----------+------------+-------------+------------------------+------------------------+---------+-------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+-------------+------------------------+------------------------+---------+-------+------+----------+--------------------------+
| 1 | SIMPLE | customers | NULL | ref_or_null | salesRepEmployeeNumber | salesRepEmployeeNumber | 5 | const | 29 | 100.00 | Using where; Using index |
+----+-------------+-----------+------------+-------------+------------------------+------------------------+---------+-------+------+----------+--------------------------+
1 row in set, 1 warning (0.00 sec)

[MySQL] 3.7 데이터 필터링 - LIMIT


http://www.mysqltutorial.org 내용을 따라 익히며 정리한 글입니다. 예시에 나오는 데이터셋은 MySQL 샘플 데이터셋인 classicmodels DB입니다.


1. LIMIT 소개

LIMITSELECT 문에서 결과값 수를 제한할 때 사용한다.
하나 혹은 두 개의 아규먼트를 받는다. 아규먼트는 0 또는 양의 정수여야 한다. 다음과 같이 사용한다.

SELECT
column1,column2,...
FROM
table
LIMIT offset , count;
  • offset : 리턴하기 시작할 행 넘버를 지정한다. (첫 행이 0번이다)
  • count : 리턴할 행의 수를 지정한다

2. LIMIT 로 N번째 행까지 가져오기

customers 테이블에서 5번째 행까지의 고객번호, 고객명, 신용한도를 가져와보자.

SELECT
customernumber,
customername,
creditlimit
FROM
customers
LIMIT 5;
+----------------+----------------------------+-------------+
| customernumber | customername | creditlimit |
+----------------+----------------------------+-------------+
| 103 | Atelier graphique | 21000.00 |
| 112 | Signal Gift Stores | 71800.00 |
| 114 | Australian Collectors, Co. | 117300.00 |
| 119 | La Rochelle Gifts | 118200.00 |
| 121 | Baane Mini Imports | 81700.00 |
+----------------+----------------------------+-------------+
5 rows in set (0.00 sec)

offset 아규먼트에 0을 넣는 것과 아무것도 넣지 않는 것은 같다. 즉, LIMIT 5LIMIT 0, 5 과 같은 결과를 리턴한다.

3. LIMIT 로 상위값들, 하위값들 가져오기

LIMITORDER BY 와 같이 자주 쓰인다.

customers 테이블에서 신용한도 상위 5명의 고객번호, 고객명, 신용한도를 내림차순으로 가져오려면 다음과 같이 작성한다.

SELECT
customernumber,
customername,
creditlimit
FROM
customers
ORDER BY
creditlimit DESC
LIMIT 5;
+----------------+------------------------------+-------------+
| customernumber | customername | creditlimit |
+----------------+------------------------------+-------------+
| 141 | Euro+ Shopping Channel | 227600.00 |
| 124 | Mini Gifts Distributors Ltd. | 210500.00 |
| 298 | Vida Sport, Ltd | 141300.00 |
| 151 | Muscle Machine Inc | 138500.00 |
| 187 | AV Stores, Co. | 136800.00 |
+----------------+------------------------------+-------------+
5 rows in set (0.00 sec)

하위 5명을 오름차순으로 가져오려면 DESC 대신 ASC 을 사용해 다음과 같이 작성한다.

SELECT
customernumber,
customername,
creditlimit
FROM
customers
ORDER BY
creditlimit ASC
LIMIT 5;
+----------------+----------------------------+-------------+
| customernumber | customername | creditlimit |
+----------------+----------------------------+-------------+
| 223 | Natürlich Autos | 0.00 |
| 168 | American Souvenirs Inc | 0.00 |
| 169 | Porto Imports Co. | 0.00 |
| 206 | Asian Shopping Network, Co | 0.00 |
| 125 | Havel & Zbyszek Co | 0.00 |
+----------------+----------------------------+-------------+
5 rows in set (0.01 sec)

4. LIMIT 로 상위 N번째 값 가져오기

상품 중 가장 비싸거나 가장 싼 상품을 찾으려면 MAXMIN 등을 사용할 수 있다. 하지만 세 번째로 비싼 상품을 찾으려면?

  1. 먼저 결과값을 내림차순으로 정렬해보자.
SELECT
productName,
buyprice
FROM
products
ORDER BY
buyprice DESC;
+---------------------------------------------+----------+
| productName | buyprice |
+---------------------------------------------+----------+
| 1962 LanciaA Delta 16V | 103.42 |
| 1998 Chrysler Plymouth Prowler | 101.51 |
| 1952 Alpine Renault 1300 | 98.58 |
| 1956 Porsche 356A Coupe | 98.30 |
| 2001 Ferrari Enzo | 95.59 |
| 1968 Ford Mustang | 95.34 |
  1. 가져와야 할 값은 Alpine Renault 1300 이다. 위 쿼리에 LIMIT 2, 1 을 추가하면 아래처럼 ‘2번행(첫 줄이 0번행)부터 1개 행을 리턴’한다.
SELECT
productName,
buyprice
FROM
products
ORDER BY
buyprice DESC
LIMIT 2, 1;
+--------------------------+----------+
| productName | buyprice |
+--------------------------+----------+
| 1952 Alpine Renault 1300 | 98.58 |
+--------------------------+----------+
1 row in set (0.00 sec)
© 2019 THE DATASCIENTIST All Rights Reserved.
Theme by hiero