반응형

인프런 인강 참고

 

[백문이불여일타] 데이터 분석을 위한 고급 SQL 문제풀이 - 인프런 | 강의

인프런 누적 수강생 7000명 이상, 풍부한 온/오프라인 강의 경험을 가진 데이터리안의 SQL 고급 문제풀이 강의. SQL 고급 내용을 연습해 볼 수 있는 여러 문제를 함께 풀어봅니다., 백문이불여일타!

www.inflearn.com

 

 

 

[문제]

  1. Weather Observation Station 17 : https://www.hackerrank.com/challenges/weather-observation-station-17/problem
  2. Contest Leaderboard : https://www.hackerrank.com/challenges/contest-leaderboard/problem
  3. New Companies : https://www.hackerrank.com/challenges/the-company/problem
    • Join을 사용하지 말고 다른 방법으로 풀어 보세요.
  4. Occupations :c

 

 

 

 

 

 

 

 

 

 

 

 

 

[풀이]

1. Weather Observation Station 17

SELECT ROUND(LONG_W,4) FROM STATION 
WHERE LAT_N = (SELECT MIN(LAT_N) FROM STATION WHERE LAT_N > 38.7770 )

나는 위에 방식처럼 풀어서 결과를 도출해냈지만

인강에서 문제풀이는 나와 달랐다.

 

인강 문제풀이 결과 - 큰결과를 정렬하고 그중에 첫번째 값만 가져오기

SELECT ROUND(LONG_W,4) 
FROM STATION
WHERE LAT_N > 38.7780
ORDER BY LAT_N
LIMIT 1

 

2. Contest Leaderboard

/*
The total score of a hacker is the sum of their maximum scores for all of the challenges. Write a query to print the hacker_id, name, and total score of the hackers ordered by the descending score. If more than one hacker achieved the same total score, then sort the result by ascending hacker_id. Exclude all hackers with a total score of 0  from your result.
*/

SELECT H.hacker_id , H.name , SUM(A.score) AS totalScore
FROM
(
SELECT S.hacker_id, S.challenge_id , MAX(S.SCORE) AS score  FROM Submissions S
GROUP BY S.hacker_id, S.challenge_id) A , Hackers H
WHERE A.hacker_id = H.hacker_id
GROUP BY H.hacker_id, H.name
having totalScore !='0'
ORDER BY totalScore DESC, H.hacker_id ASC

 

3.  New Companies 

/*
 write a query to print the company_code, founder name, total number of lead managers, 
 total number of senior managers, total number of managers, and total number of employees. 
 Order your output by ascending company_code.
*/

SELECT C.company_code, C.founder,
        count(distinct LM.lead_manager_code) AS totLeadManager , 
        count(distinct SM.senior_manager_code) AS totSeniorManager , 
        count(distinct M.manager_code) AS totManager ,
        count(distinct E.employee_code) AS totEmployee
FROM Company C , Lead_Manager LM  , Senior_Manager SM  ,  Manager M , Employee E
WHERE  C.company_code =LM.company_code
AND LM.lead_manager_code = SM.lead_manager_code
AND SM.senior_manager_code = M.senior_manager_code
AND M.manager_code = E.manager_code
GROUP BY C.company_code, C.founder
ORDER BY C.company_code

  서브쿼리로 푸는 방법

/*
 write a query to print the company_code, founder name, total number of lead managers, 
 total number of senior managers, total number of managers, and total number of employees. 
 Order your output by ascending company_code.
*/

SELECT C.company_code, C.founder,
        (SELECT count(distinct LM.lead_manager_code) FROM Lead_Manager LM 
         WHERE C.company_code = LM.company_code  ) AS totLeadManager , 
          (SELECT  count(distinct SM.senior_manager_code) FROM Senior_Manager SM
         WHERE C.company_code = SM.company_code  ) AS totSeniorManager , 
          (SELECT count(distinct M.manager_code) FROM Manager M
         WHERE C.company_code = M.company_code  ) AS totManager , 
          (SELECT count(distinct E.employee_code) FROM Employee E
         WHERE C.company_code = E.company_code  ) AS totEmployee               
FROM Company C
ORDER BY C.company_code

 

4. Occupations ***** 어려웠음

 - Case를 활용한 피벗 테이블 

 

첫번째 컬럼: Doctor , 두번째 컬럼 : Professor, 세번째 컬럼 : Singer, 네번째 컬럼: Actor

 

- ROW_NUMBER() OVER ( PARTITION BY ...ORDER BY ) 사용... <- 오라클의 경우에는 이 window함수로 끝!

- mysql의 경우 ROW_NUM 구현하기

SELECT @RNUM := @RNUM + 1 AS RNUM
            , A.*
    FROM 테이블 A
           , (SELECT @RNUM := 0) B

- mysql의 경우 ROW_NUMBER(PARTITION BY 컬럼1 ORDER BY 컬럼2) 구현하기

SELECT @ROW_NUM := IF(@PREV_VALUE = A.컬럼1, @ROW_NUM + 1, 1) AS ROW_NUMBER
          , @PREV_VALUE := A.컬럼1
          , A.*
  FROM 테이블 A
         , (SELECT @ROW_NUM := 1) X
         , (SELECT @PREV_VALUE := '') Y
 ORDER BY A.컬럼2

- CASE 문을 MIN() 으로  감싼 이유 : MAX() 나 MIN() 에서 NULL 은 비교대상으로 삼지 않는다

SELECT MIN(CASE WHEN A.occupation = 'Doctor' THEN A.name else null END) doctor ,
       MIN(CASE WHEN A.occupation = 'Professor' THEN A.name else null END) professor ,
       MIN(CASE WHEN A.occupation = 'Singer' THEN A.name else null END) singer ,
       MIN(CASE WHEN A.occupation = 'Actor' THEN A.name else null END) actor     
FROM (
    SELECT 
        occupation, 
        name, 
        -- ROW_NUMBER() OVER (PARTITION BY occupation ORDER BY name) RNUM    
        @rownum := IF(@value=occupation,@rownum+1,1) AS RNUM  ,     
        @value := occupation
    FROM OCCUPATIONS, 
        (SELECT @rownum :=0) AS R , -- @rownum 0 reset 
        (SELECT @value := '') AS P
    ORDER BY occupation, name
) A  
GROUP BY A.RNUM

 

반응형

서비스 간 통신을 위해 사용하는 API는 구현 방식에 따라 SOAPREST가 있다. 

 

JAVA개발하면서 웹서비스 호출관련해서 SOAPREST 의 차이점에 대한 질문을 많이 받았었다.

아래 사이트에 정리가 쉽게 잘 되어 있는 것 같다.

 

[참고링크]

 

SOAP API VS REST API 비교 분석 및 차이점 : API Gateway 주요기능과 적용 분야

SOAP API 란 무엇인가?SOAP API는 simple Object access Protocol Application Programming Interface의 약자로 이름에서부터 알 수 있듯이 프로토콜이다. 보안이나 메시지 전송 등에 있어 REST API보다 더 많은 표준들이

ideatec.co.kr

 

SOAP는 프로토콜이고, REST는 아키텍처 스타일이며 데이터 처리하는 방식에 차이가 있다. 

SOAP는 서비스 인터페이스를 이용해서 서버에 접근하며, REST는 URI를 이용해서 접근한다. 

REST는 HTTP와 JSON을 사용하기도 하지만 SOAP는 XML에만 의존한다

'백엔드' 카테고리의 다른 글

[springBoot] @Mapper 사용하기  (0) 2022.09.02
[Spring] properties 동적 로딩 @Value 주입  (0) 2022.08.09
반응형
  1. Weather Observation Station 3 : https://www.hackerrank.com/challenges/weather-observation-station-3/problem
  2. Weather Observation Station 19 : https://www.hackerrank.com/challenges/weather-observation-station-19/problem
  3. Placements: https://www.hackerrank.com/challenges/placements/problem
  4. Binary Tree Nodes: https://www.hackerrank.com/challenges/binary-search-tree-1/problem

 

 

 

 

 

 

 

 

 

 

 

 

답안

1. Weather Observation Station 3

   -ID가 짝수 인 결과 출력

/*
Query a list of CITY names from STATION for cities that have an even ID number
*/
SELECT DISTINCT(CITY) FROM STATION WHERE MOD(ID,2) = 0

 

2. Weather Observation Station 19

/*
Consider p1(a,c) and p2(b,d) to be two points on a 2D plane where (a,b) are the respective minimum and maximum values of Northern Latitude (LAT_N) and (c,d) are the respective minimum and maximum values of Western Longitude (LONG_W) in STATION.

Query the Euclidean Distance between points p1 and p2 and format your answer to display 4 decimal digits.
*/

-- a: minimum(lat_n), b: maximum(lat_n), c: minimum(long_w), d: maximum(long_w)
-- p1(minimum(lat_n),minimum(long_w)) , p2(maximum(lat_n), maximum(long_w))

SELECT ROUND(SQRT(POW(max(lat_n)- min(lat_n),2) + POW(max(long_w)- min(long_w),2)),4)
FROM STATION

3. Placements

/*
Write a query to output the names of those students whose best friends got offered a higher salary than them. Names must be ordered by the salary amount offered to the best friends. It is guaranteed that no two students got same salary offer.
*/

SELECT (SELECT S.NAME FROM Students S WHERE S.ID = F.ID)  
FROM  Friends F
inner join Packages P1 on F.ID = P1.ID
inner join Packages P2 on F.Friend_ID = P2.ID
WHERE P1.salary <  P2.salary
ORDER BY P2.salary

 

4. Binary Tree Nodes - 어려운 문제

Root : 부모 x

Leaf : 자식 x, 부모가 아님( P컬럼에서 등장 x) 

 

/*
N and P, where N represents the value of a node in Binary Tree, and P is the parent of N.
*/

SELECT DISTINCT B1.N ,
       (CASE 
            WHEN B1.P IS NULL THEN 'Root'   
            WHEN  B2.N IS NULL THEN 'Leaf' 
            else 'Inner'    
        end
        ) AS result
FROM BST B1 
LEFT JOIN BST B2 ON B1.N = B2.P
ORDER BY B1.N
반응형
  1. Population Density Difference: https://www.hackerrank.com/challenges/population-density-difference/problem
  2. Weather Observation Station 11: https://www.hackerrank.com/challenges/weather-observation-station-11/problem
  3. Weather Observation Station 13: https://www.hackerrank.com/challenges/weather-observation-station-13/problem
  4. Top Competitors: https://www.hackerrank.com/challenges/full-score/problem

 

 

 

 

 

 

 

 

답안

1. Population Density Difference

SELECT MAX(population)- MIN(population)  FROM CITY

2. Weather Observation Station 11

/*
Query the list of CITY names from STATION that either do not start with vowels or do not end with vowels. Your result cannot contain duplicates
*/
SELECT distinct(CITY) FROM STATION 
WHERE SUBSTR(CITY,1,1) NOT IN ('a','e','i','o','u')
OR SUBSTR(CITY,-1) NOT IN ('a','e','i','o','u')

--LEFT(), RIGHT()함수 사용해도 됨
--WHERE LEFT(CITY,1) NOT IN ('a','e','i','o','u')
--OR RIGHT(CITY,1) NOT IN ('a','e','i','o','u')

3. Weather Observation Station 13

/*
Query the sum of Northern Latitudes (LAT_N) from STATION having values greater than 38.7880 and less than 137.2345 . Truncate your answer to 4 decimal places.
*/

SELECT truncate(sum(LAT_N),4) FROM STATION
WHERE LAT_N > 38.7880 AND LAT_N < 137.2345

-- 해당값보다 크다했는데 아래와 같은경우 해당값도 포함되므로 정답이라 할 수 없음
-- BETWEEN은 LAT_N >= 38.7880 AND LAT_N <= 137.2345와 같은의미
--WHERE LAT_N BETWEEN 38.7880 AND 137.2345

4. Top Competitors   --> 어렵다....................... group by/ having

 

Difficulty table에 diufficulty_level에 해당하는 점수가 full score

1. Submissions 테이블의 challenge_id에 해당하는 값을

 Challenges 테이블 challenge_id 과 매핑 후 difficulty_level 가져오기

2. Difficulty 테이블의 difficulty_level에 해당하는 score가 full score에며

Submissions테이블의 score와 비교

3. Submissions 테이블의 hacker_id가 86870, 904111인 경우 full score와 동일

 

4. 하나보다는 더 많은 challenge에서 full score를 받은 경우는 hacker_id가 90411 인 경우임

코드 작성

/*
Write a query to print the respective hacker_id and name of hackers who achieved full scores for more than one challenge. Order your output in descending order by the total number of challenges in which the hacker earned a full score. If more than one hacker received full scores in same number of challenges, then sort them by ascending hacker_id.
*/

SELECT h.hacker_id, h.name
FROM submissions s
    INNER JOIN Challenges c on s.challenge_id = c.challenge_id
    INNER JOIN Difficulty d on c.difficulty_level = d.difficulty_level
    INNER JOIN Hackers h on s.hacker_id = h.hacker_id
WHERE s.score = d.score
group by h.hacker_id, h.name
having count(distinct(s.submission_id)) > 1
order by  count(distinct(s.submission_id)) desc, h.hacker_id asc

 

반응형

- requests의 한계 

   1. 로그인이 필요한 사이트의 경우

   2. 동적으로 html을 만드는 경우 ***

   

- 셀레니움 : 웹 어플리케이션 테스트를 위한 도구 ( 브라우저를 실제로 띄움)

- 셀레니움 설치 

  1. 크롬 드라이버 다운로드 ( 사용하고 있는 크롬버전 정보랑 동일한 드라이버로 설치)

      https://chromedriver.chromium.org/downloads

 

ChromeDriver - WebDriver for Chrome - Downloads

Current Releases If you are using Chrome version 98, please download ChromeDriver 98.0.4758.48 If you are using Chrome version 97, please download ChromeDriver 97.0.4692.71 If you are using Chrome version 96, please download ChromeDriver 96.0.4664.45 For o

chromedriver.chromium.org

설치 후 c드라이브로 이동  

 

2. 명령어로 라이브러리 설치 pip install selenium

......

3. 설치 후 코드작성 후 실행하면 크롬창이 뜨는것을 확인

from selenium import webdriver

#브라우저 생성
browser = webdriver.Chrome('C:/chromedriver.exe')

#웹사이트 열기
browser.get('https://www.naver.com')

 

위의 창에서 쇼핑탭을 개발자 도구로 확인하여 css 선택자 확인하기

(a태그 이면서 class속성값이 nav shop)

from selenium import webdriver

#브라우저 생성
browser = webdriver.Chrome('C:/chromedriver.exe')

#웹사이트 열기
browser.get('https://www.naver.com')
browser.implicitly_wait #로딩이 끝날 때 까지 10초까지는 기다림

#쇼핑 메뉴 클릭
browser.find_element_by_css_selector('a.nav.shop').click()

실행 시 네이버 쇼핑화면이 뜸

개발자도구 확인하여 검색창 css 선택자 확인

(input 태그 이면서 class속성값이 co_srh_input _input)

from select import select
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time

#브라우저 생성
browser = webdriver.Chrome('C:/chromedriver.exe')

#웹사이트 열기
browser.get('https://www.naver.com')
browser.implicitly_wait(10) #로딩이 끝날 때 까지 10초까지는 기다림

#쇼핑 메뉴 클릭
browser.find_element_by_css_selector('a.nav.shop').click()
time.sleep(2) #동시에 실행됨을 막기위해 잠깐 기다림

#검색창 클릭
search = browser.find_element_by_css_selector('input.co_srh_input._input')
search.click()

#검색어 입력
search.send_keys('아이폰 13')
search.send_keys(Keys.ENTER)   #enter 치는 명령어

실행해보면 naver창 뜨고 네이버쇼핑접속해서 검색상에 '아이폰 13'입력 후 검색까지...되는것을 확인

selenium은 만능이네 이것저것 다 할 수 있구나 짱짱

 

이제 상품명, 가격, 링크를 크롤링해보자

네이버쇼핑 검색결과창에서 개발자 도구 열어서 분석, 필요한 정보가 담긴 css 선택자 찾기

(부모태그 ul에 리스트들 전체정보가 담겨있음, 제목과 링크는 a태그 )

 

코드작성

( 스크롤을 끝까지 내려서 페이지 내 전체 리스트 가져오기)

from select import select
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time

#브라우저 생성
browser = webdriver.Chrome('C:/chromedriver.exe')

#웹사이트 열기
browser.get('https://www.naver.com')
browser.implicitly_wait(10) #로딩이 끝날 때 까지 10초까지는 기다림

#쇼핑 메뉴 클릭
browser.find_element_by_css_selector('a.nav.shop').click()
time.sleep(2) #동시에 실행됨을 막기위해 잠깐 기다림

#검색창 클릭
search = browser.find_element_by_css_selector('input.co_srh_input._input')
search.click()

#selenium은 만능이네 이것저것 다 할 수 있구나
#검색어 입력
search.send_keys('아이폰 13')
search.send_keys(Keys.ENTER)   #enter 치는 명령어

#스크롤 내리기 전 높이 확인, 스크립트 실행함수
before_h = browser.execute_script("return window.scrollY")
#무한스크롤(반복문 활용)
while True:
    # 맨 아래로 스크롤을 내린다.
    browser.find_element_by_css_selector("body").send_keys(Keys.END) #키보드 END키

    #스트롤 사이 페이지 로딩시간
    time.sleep(1)

    #스크롤 후 높이
    after_h = browser.execute_script("return window.scrollY")

    if after_h == before_h:
        break
    before_h  = after_h

각 상품정보 div  내용가져오기 (for 문)

코드작성

from select import select
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time

#브라우저 생성
browser = webdriver.Chrome('C:/chromedriver.exe')

#웹사이트 열기
browser.get('https://www.naver.com')
browser.implicitly_wait(10) #로딩이 끝날 때 까지 10초까지는 기다림

#쇼핑 메뉴 클릭
browser.find_element_by_css_selector('a.nav.shop').click()
time.sleep(2) #동시에 실행됨을 막기위해 잠깐 기다림

#검색창 클릭
search = browser.find_element_by_css_selector('input.co_srh_input._input')
search.click()

#selenium은 만능이네 이것저것 다 할 수 있구나
#검색어 입력
search.send_keys('아이폰 13')
search.send_keys(Keys.ENTER)   #enter 치는 명령어

#스크롤 내리기 전 높이 확인, 스크립트 실행함수
before_h = browser.execute_script("return window.scrollY")
#무한스크롤(반복문 활용)
while True:
    # 맨 아래로 스크롤을 내린다.
    browser.find_element_by_css_selector("body").send_keys(Keys.END) #키보드 END키

    #스트롤 사이 페이지 로딩시간
    time.sleep(1)

    #스크롤 후 높이
    after_h = browser.execute_script("return window.scrollY")

    if after_h == before_h:
        break
    before_h  = after_h

#상품 정보 div , elemets사용해서 여러건 가져오기 ( element는 한건)
items = browser.find_elements_by_css_selector(".basicList_info_area__17Xyo")

for item in items:
    name = item.find_element_by_css_selector(".basicList_title__3P9Q7").text    #상품명
    #판매 중단된 경우는 price정보가 없으므로 에러, 예외처리로 해결 (try_except)
    try :
        price = item.find_element_by_css_selector(".price_num__2WUXn").text         #가격정보
    except:
        price = "판매중단"
    #get_attribute('속성값')
    link = item.find_element_by_css_selector(".basicList_title__3P9Q7 > a").get_attribute('href')   #가격정보

    print(name,price,link)

실행결과

터미널에 40건 리스트에 해당하는 각 상품의 이름,가격, 링크정보를 보여줌

크롤링 결과를 csv파일로 저장하기

코드작성

from select import select
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
import csv

#브라우저 생성
browser = webdriver.Chrome('C:/chromedriver.exe')

#웹사이트 열기
browser.get('https://www.naver.com')
browser.implicitly_wait(10) #로딩이 끝날 때 까지 10초까지는 기다림

#쇼핑 메뉴 클릭
browser.find_element_by_css_selector('a.nav.shop').click()
time.sleep(2) #동시에 실행됨을 막기위해 잠깐 기다림

#검색창 클릭
search = browser.find_element_by_css_selector('input.co_srh_input._input')
search.click()

#selenium은 만능이네 이것저것 다 할 수 있구나
#검색어 입력
search.send_keys('아이폰 13')
search.send_keys(Keys.ENTER)   #enter 치는 명령어

#스크롤 내리기 전 높이 확인, 스크립트 실행함수
before_h = browser.execute_script("return window.scrollY")
#무한스크롤(반복문 활용)
while True:
    # 맨 아래로 스크롤을 내린다.
    browser.find_element_by_css_selector("body").send_keys(Keys.END) #키보드 END키

    #스트롤 사이 페이지 로딩시간
    time.sleep(1)

    #스크롤 후 높이
    after_h = browser.execute_script("return window.scrollY")

    if after_h == before_h:
        break
    before_h  = after_h

#파일 생성 (open(파일경로, 모드_'w'쓰기,encording, newline_줄바꿈없애줌 ))
f= open(r"C:\startcoding\Chapter03\data.csv", "w", encoding="CP949", newline='')
csvWriter = csv.writer(f)

#상품 정보 div , elemets사용해서 여러건 가져오기 ( element는 한건)
items = browser.find_elements_by_css_selector(".basicList_info_area__17Xyo")

for item in items:
    name = item.find_element_by_css_selector(".basicList_title__3P9Q7").text    #상품명
    #판매 중단된 경우는 price정보가 없으므로 에러, 예외처리로 해결 (try_except)
    try :
        price = item.find_element_by_css_selector(".price_num__2WUXn").text         #가격정보
    except:
        price = "판매중단"
    #get_attribute('속성값')
    link = item.find_element_by_css_selector(".basicList_title__3P9Q7 > a").get_attribute('href')   #가격정보

    print(name,price,link)
    #데이터쓰기
    csvWriter.writerow([name,price,link])
#파일닫기
f.close()

결과

data.csv 파일 생성되고 열어보기

 

참고 [무한 스크롤 처리방법]

현재 스크롤 된 높이를 알수있는 자바스크립트 명령어 이용 : window.scrollY

 

새로고침 한 검색결과 창에서 개발자 도구를 열고 Element가 아닌 consonle탭 선택

window.scrollY 입력하고 엔터 -> 스크롤을 내리지않은 상태이므로 결과값은 0

스크롤을 조금 내린 후 명령어 한번 더 실행 (방향키 위 누르면 이전 명령어 불러옴)

결과값(px)이 증가함을 확인

 

 

 

 

 

 

 

아..진짜 넘나신기

저절로 url창이 뜨고 검색하고 검색결과 크롤링하고 내려받기 까지~~~ 진짜 좋은 강의였다!

 

 

-끝-

반응형

알고리즘 문제 및 풀이사이트

https://www.hackerrank.com/onboarding?redirect=%2Fdashboard 

 

Dashboard | HackerRank

Join over 16 million developers in solving code challenges on HackerRank, one of the best ways to prepare for programming interviews.

www.hackerrank.com

 

sql 문제풀이 

  1. Japan Population: https://www.hackerrank.com/challenges/japan-population/problem
  2. Weather Observation Station 2: https://www.hackerrank.com/challenges/weather-observation-station-2/problem
  3. Weather Observation Station 18: https://www.hackerrank.com/challenges/weather-observation-station-18/problem
  4. New Companies: https://www.hackerrank.com/challenges/the-company/problem

 

 

 

 

 

 

 

- 답안

(mysql로 풀이)

 

1. Japan Population

  - SUM

/*
Query the sum of the populations for all Japanese cities in CITY. 
The COUNTRYCODE for Japan is JPN.
*/

SELECT SUM(POPULATION) FROM CITY 
WHERE COUNTRYCODE ='JPN'

2. Weather Observation Station 2

  - 두자리 숫자까지 반올림

/*
The sum of all values in LAT_N rounded to a scale of  decimal places.
The sum of all values in LONG_W rounded to a scale of  decimal places.
*/
SELECT ROUND(SUM(LAT_N),2) AS lat, 
    ROUND(SUM(LONG_W),2) AS lon
FROM STATION

3. Weather Observation Station 18

 - ABS() 절대값

Consider p1(a,b)  and p2(c,d) to be two points on a 2D plane.

위와 같으므로 해당 쿼리에서 Manhattan distance 구하는 공식 |a-c| + |b-d|

 

/*
a: happens to equal the minimum value in Northern Latitude (LAT_N in STATION).
b: happens to equal the minimum value in Western Longitude (LONG_W in STATION).
c: happens to equal the maximum value in Northern Latitude (LAT_N in STATION).
d: happens to equal the maximum value in Western Longitude (LONG_W in STATION).

Query the Manhattan Distance between points p1 and p2 and round it to a scale of 4 decimal places.
*/

SELECT ROUND(ABS(ST.a-ST.c) + ABS(ST.b-ST.d),4)
FROM
(
SELECT MIN(LAT_N) AS a, MIN(LONG_W) AS b, MAX(LAT_N) AS c ,MAX(LONG_W) AS d  FROM  STATION 
) ST

4. New Companies

 - company_code, founder name 별 각 manager와 employee 수 구하기 , company_code순으로 정렬

Company 테이블에 company_code, founder name 존재

Employee Table (모든 컬럼값을 가지고있음)

  -> 주의사항 :  Employee에 없는경우도 생각해야함

                     현재상황은 Company 테이블과  Employee 테이블을 INNER JOIN 해도 결과가 나옴

output 결과

/*

Given the table schemas below, write a query to print the company_code, founder name, total number of lead managers, total number of senior managers, total number of managers, and total number of employees. Order your output by ascending company_code.

Note:
The tables may contain duplicate records.
The company_code is string, so the sorting should not be numeric. For example, if the company_codes are C_1, C_2, and C_10, then the ascending company_codes will be C_1, C_10, and C_2.
*/

SELECT  C.company_code ,
        C.founder ,
        COUNT(DISTINCT L.lead_manager_code ), 
        COUNT(DISTINCT S.senior_manager_code ), 
        COUNT(DISTINCT M.manager_code ),
        COUNT(DISTINCT E.employee_code )
FROM Company C
LEFT JOIN Lead_Manager L ON C.company_code = L.company_code
LEFT JOIN Senior_Manager S ON L.company_code = S.company_code
LEFT JOIN Manager M ON S.company_code = M.company_code
LEFT JOIN Employee E ON M.company_code = E.company_code
GROUP BY C.company_code, C.founder
ORDER BY C.company_code
반응형

1. 현재가 크롤링

   - 현재가를 크롤링해서 엑셀에 저장

 

네이버 금융 > 삼성전자 검색

https://finance.naver.com/item/sise.naver?code=005930 

(code파라미터 값이 삼성전자의 종목코드)

 

개발자도구(F12) 눌러서 현재가 가져오기위한 태그 확인 후 id값 추출

위에 code파라미터 값을 다른 종목코드로 변경 시 해당기업의 현재가 조회됨을 확인

그러므로 코드종목값을 받아서 크롤링해보도록 하자

코드 작성(1)

import requests
from bs4 import BeautifulSoup

url = "https://finance.naver.com/item/sise.naver?code=005930"
response = requests.get(url);
html = response.text
soup = BeautifulSoup(html, 'html.parser')
price = soup.select_one('#_nowVal').text
print("현재가 :"+ price)
# ,제거
price = price.replace(',','')
print(price)

현재가 출력 결과

코드작성(2)

import requests
from bs4 import BeautifulSoup

# 종목 코드 리스트
codes = [
    '005930', #삼성전자
    '000660', #sk하이닉스
    '035720' #카카오
]

#for문쓸때 내용은 한칸씩 들여쓰기
for code in codes:
    url = f"https://finance.naver.com/item/sise.naver?code={code}"
    response = requests.get(url);
    html = response.text
    soup = BeautifulSoup(html, 'html.parser')
    price = soup.select_one('#_nowVal').text
    print("현재가 :"+ price)
    # ,제거
    price = price.replace(',','')
    print(price)

리스트에 담긴 코드종목들의 현재가 출력 결과

 

2. 수집한데이터 엑셀에 저장하기

코드 생성

import requests
from bs4 import BeautifulSoup
import openpyxl

fpath = r'C:\startcoding\Chapter03\테스트데이터.xlsx'
wb = openpyxl.load_workbook(fpath)
ws = wb.active #현재 활성화 된 시트 선택(기본시트)

# 종목 코드 리스트
codes = [
    '005930', #삼성전자
    '000660', #sk하이닉스
    '035720' #카카오
]

row =2 #행값

#for문쓸때 내용은 한칸씩 들여쓰기
for code in codes:
    url = f"https://finance.naver.com/item/sise.naver?code={code}"
    response = requests.get(url);
    html = response.text
    soup = BeautifulSoup(html, 'html.parser')
    price = soup.select_one('#_nowVal').text
    price = price.replace(',','')
    print(price)
    ws[f'B{row}'] = int(price)
    row = row+1
    
wb.save(fpath)

엑셀파일 확인

('현재가' B셀 B2,B3,B4에 내용생성됨을 확인)

 

 

[참고] 엑셀 만들기 / 엑셀 불러오기

  - openpyxl 라이브러리 설치

    openpyxl  : 파이썬에서 엑셀을 쉽게 다룰 수 있도록 도와주는 라이브러리

 

명령어 : pip install openpyxl

설치완료

[엑셀만들기] 코드 생성

import openpyxl

#1) 엑셀 만들기
wb = openpyxl.Workbook()

#2) 엑셀 워크시트 만들기
ws = wb.create_sheet('테스트엑셀') #워크시트이름

#3) 데이터 추가하기
ws['A1'] = '번호' #셀 값 설정
ws['B1'] = '성명'

ws['A2'] = '1' 
ws['B2'] = '이은주'

#4) 엑셀 저장하기
wb.save('테스트데이터.xlsx') #저장파일명

#참고 절대경로로 Chapter03안에 엑셀파일 생성
#이때 복사한 경로 그대로 사용하려면 문자열앞에 r 써주면됨(경로 str앞에 r붙이기)
#\ 은 Escape Character 이므로 파이썬에서 읽어들일 수없음 (\\또는 /로 변경해야함)
wb.save(r'C:\startcoding\Chapter03\테스트데이터.xlsx')

코드실행 시 STARTCORDING 아래 xlsx파일이 생성됨을 확인

절대경로 통해서 Chapter03폴더안에 생성됨도 확인

엑셀파일 확인

 

[엑셀 불러오기] 코드생성

import openpyxl

fpath = r'C:\startcoding\Chapter03\테스트데이터.xlsx'
# 1) 엑셀 불러오기
wb = openpyxl.load_workbook(fpath)

# 2) 엑셀 시트선택
ws = wb['테스트엑셀']

#3) 데이터 수정하기
ws['A3'] = 456
ws['B3'] = '누구누구'

#4) 엑셀저장하기
wb.save(fpath)

 

엑셀파일 확인_경로 내 파일내용이 수정됨을 확인

반응형

1. 뉴스데이터 수집하기

  - 네이버 뉴스의 제목과 링크 가져오기

뉴스검색

개발자도구(F12)를 열어서 제목에 해당하는 태그 확인

태그 내 별명( id또는  class) 확인

ctrl+F 눌러서 해당 클래스명 검색 (10건 조회됨을 확인)

id 검색시 #별명 , class검색시 .별명

소스작성(설명은 주석참고)

import requests
from bs4 import BeautifulSoup


#검색한 화면의 url복사해서 붙여넣기
response = requests.get("https://search.naver.com/search.naver?where=news&sm=tab_jum&query=%EC%82%BC%EC%84%B1%EC%A0%84%EC%9E%90")
#응답값을 텍스트로 추출
html =response.text
#text형태의 html로 원하는 값만 검색
soup = BeautifulSoup(html, 'html.parser')
#결과가 리스트로 조회됨_select(css 별명)
links = soup.select(".news_tit")
#여러 기사의 제목과 링크를 출력
for link in links:
    title = link.text #태그안에 텍스트요소 가져옴
    url = link.attrs['href'] #href의 속성값을 가져옴
    print(title, url)

결과

 

[과제]

Q1) 검색어 입력받아서 해당검색어로 크롤링

  - 검색어 변경하기

import requests
from bs4 import BeautifulSoup

keyword = input("검색어를 입력하세요>>>")
#검색한 화면의 url복사해서 붙여넣기
#해당 url에서 query="값" 에서 값부분을 입력받게 변경하기
response = requests.get("https://search.naver.com/search.naver?where=news&sm=tab_jum&query="+ keyword)
#응답값을 텍스트로 추출
html =response.text
#text형태의 html로 원하는 값만 검색
soup = BeautifulSoup(html, 'html.parser')g
#결과가 리스트로 조회됨_select(css 속성)
links = soup.select(".news_tit")
#여러 기사의 제목과 링크를 출력
for link in links:
    title = link.text #태그안에 텍스트요소 가져옴
    url = link.attrs['href'] #href의 속성값을 가져옴
    print(title, url)

command창에 keyword를 "현대차"차고 입력 후 enter

  - 참고 : pyautogui로 간단한 입력팝업창 띄워보기

            pyautogui  라이브러리 : 마우스와 키보드 제어    

 

pyautogui 설치 : pip install pyautogui

......

warning났다......업데이트 명령어 실패하여

삭제 후 재 설치했더니....잘됨 오잉? 성공!

설치완료 후 import하고 사용하기

import requests
from bs4 import BeautifulSoup
import pyautogui

keyword = pyautogui.prompt("검색어를 입력하세요.")
#검색한 화면의 url복사해서 붙여넣기
#해당 url에서 query="값" 에서 값부분을 입력받게 변경하기
#f-문자열(string) 포맷팅 - 문자열앞에 f , 변수가 들어가는 부분 {}
response = requests.get(f"https://search.naver.com/search.naver?where=news&sm=tab_jum&query={keyword}")
#응답값을 텍스트로 추출
html =response.text
#text형태의 html로 원하는 값만 검색
soup = BeautifulSoup(html, 'html.parser')
#결과가 리스트로 조회됨_select(css 속성)
links = soup.select(".news_tit")
#여러 기사의 제목과 링크를 출력
for link in links:
    title = link.text #태그안에 텍스트요소 가져옴
    url = link.attrs['href'] #href의 속성값을 가져옴
    print(title, url)

왜 에러가 나는건가...

이때 파일명을 pyautogui.py로 했는데 import명과 달라야한다는 글을 보고

다른이름으로 변경하여 해결!

이름변경 후 실행하니 팝업창이 뜨고 카카오라고 입력 후 OK

뉴스기사 추출 완료

 

Q2) 원하는 페이지까지 크롤링
   - 반복문사용하기

     for i in range(시작, 끝, 단계)

     ex) for i in range(1,10,2) :  1부터 10까지사이의 숫자가 2씩증가하므로 range의 결과값은 1,3,5,7,9

 

페이지 변경 시 url에서 파라미터가 어떻게 변하는지 분석하고

for문 사용하여 소스 완성 (tab 들여쓰기 지켜야함)

import requests
from bs4 import BeautifulSoup
import pyautogui

#1페이지 : https://search.naver.com/search.naver?where=news&sm=tab_pge&query=%EC%82%BC%EC%84%B1%EC%A0%84%EC%9E%90&sort=0&photo=0&field=0&pd=0&ds=&de=&cluster_rank=79&mynews=0&office_type=0&office_section_code=0&news_office_checked=&nso=so:r,p:all,a:all&start=1
#2페이지 : https://search.naver.com/search.naver?where=news&sm=tab_pge&query=%EC%82%BC%EC%84%B1%EC%A0%84%EC%9E%90&sort=0&photo=0&field=0&pd=0&ds=&de=&cluster_rank=34&mynews=0&office_type=0&office_section_code=0&news_office_checked=&nso=so:r,p:all,a:all&start=11
#3페이지 : https://search.naver.com/search.naver?where=news&sm=tab_pge&query=%EC%82%BC%EC%84%B1%EC%A0%84%EC%9E%90&sort=0&photo=0&field=0&pd=0&ds=&de=&cluster_rank=50&mynews=0&office_type=0&office_section_code=0&news_office_checked=&nso=so:r,p:all,a:all&start=21
#4페이지 : https://search.naver.com/search.naver?where=news&sm=tab_pge&query=%EC%82%BC%EC%84%B1%EC%A0%84%EC%9E%90&sort=0&photo=0&field=0&pd=0&ds=&de=&cluster_rank=64&mynews=0&office_type=0&office_section_code=0&news_office_checked=&nso=so:r,p:all,a:all&start=31
#start값이 변경됨을 확인(10단위로 증가)_페이지번호일것이다...

keyword = pyautogui.prompt("검색어를 입력하세요.")
pageNum = 1 #페이지number 표기를 위한 변수
#검색한 화면의 url복사해서 붙여넣기
#해당 url에서 query="값" 에서 값부분을 입력받게 변경하기
#f-문자열(string) 포맷팅 - 문자열앞에 f , 변수가 들어가는 부분 {}
#for문 실행
for i in range(1,30,10): #range결과(i는 start변수값) : 1,11,21
    print(f"{pageNum}페이지입니다.================================")
    response = requests.get(f"https://search.naver.com/search.naver?where=news&sm=tab_jum&query={keyword}&start={i}")
    #응답값을 텍스트로 추출
    html =response.text
    #text형태의 html로 원하는 값만 검색
    soup = BeautifulSoup(html, 'html.parser')
    #결과가 리스트로 조회됨_select(css 속성)
    links = soup.select(".news_tit")
    #여러 기사의 제목과 링크를 출력
    for link in links:
        title = link.text #태그안에 텍스트요소 가져옴
        url = link.attrs['href'] #href의 속성값을 가져옴
        print(title, url)
pageNum = pageNum +1

 

실행하면 입력팝업창 뜨고 삼성전자 입력 후 OK

크롤링 성공! 

+ Recent posts