๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’ป IT·๊ธฐ์ˆ ·ํ†ต๊ณ„

[์›นํฌ๋กค๋ง 3ํƒ„ - ไธŠ] requests-html์„ ํ™œ์šฉํ•œ ๋„ค์ด๋ฒ„ ๋‰ด์Šค ๊ฐ€์ ธ์˜ค๊ธฐ

by nowgeun 2023. 2. 15.
728x90

 

์ด์ „ ํฌ์ŠคํŒ…์—์„œ๋Š” requests์™€ selenium์œผ๋กœ ํฌ๋กค๋งํ•˜๋Š” ๋ฒ•์— ๋Œ€ํ•ด ์†Œ๊ฐœ๋ฅผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

 

[์›นํฌ๋กค๋ง 1ํƒ„] requests์™€ bs4๋ฅผ ํ™œ์šฉํ•œ ๋ ˆ์‹œํ”ผ ๋ชฉ๋ก ํฌ๋กค๋ง

ํšŒ์‚ฌ์—์„œ ํ˜น์€ ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•  ๋•Œ ๋ฐ์ดํ„ฐ๋ฅผ ํฌ๋กค๋งํ•ด ์˜ค๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ข…์ข… ์žˆ์Šต๋‹ˆ๋‹ค. ์ œํ’ˆ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค๋˜์ง€, ์ตœ๊ทผ 2๋…„ ์น˜์˜ ๊ฒฝ์ œ ๋‰ด์Šค ๊ธฐ์‚ฌ๋ฅผ ๋ชจ์€๋‹ค๋˜์ง€ ๋“ฑ ์›น์‚ฌ์ดํŠธ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ

jakely.tistory.com

 

[์›นํฌ๋กค๋ง 2ํƒ„] selenium webdriver๋ฅผ ํ™œ์šฉํ•œ ์ƒํ’ˆ ๋ฆฌ์ŠคํŠธ ํฌ๋กค๋ง

์›นํฌ๋กค๋ง 1ํƒ„์—์„œ requests์™€ bs4์„ ์ด์šฉํ•˜์—ฌ ๊ฐ„๋‹จํ•œ ์›น์‚ฌ์ดํŠธ ํฌ๋กค๋ง ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ๋‹ค๋ค˜์Šต๋‹ˆ๋‹ค. [์›นํฌ๋กค๋ง 1ํƒ„] requests์™€ bs4๋ฅผ ํ™œ์šฉํ•œ ๋ ˆ์‹œํ”ผ ๋ชฉ๋ก ํฌ๋กค๋ง ํšŒ์‚ฌ์—์„œ ํ˜น์€ ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•  ๋•Œ

jakely.tistory.com

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” requests-html์„ ํ™œ์šฉํ•˜์—ฌ ์ฃผ์‹ ์ข…๋ชฉ ๋‰ด์Šค ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

Requests-HTML: HTML Scraping for Humans

 

๋„ค์ด๋ฒ„ ๋‰ด์Šค ๊ฒ€์ƒ‰

๋„ค์ด๋ฒ„ ๊ฒ€์ƒ‰์ฐฝ์— ๊ฒ€์ƒ‰์–ด๋ฅผ ์ž…๋ ฅํ•œ ๋’ค, ๋‰ด์Šคํƒญ์œผ๋กœ ์ด๋™ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒ€์ƒ‰ ์˜ต์…˜๋“ค์ด ๋ณด์ž…๋‹ˆ๋‹ค.

๋„ค์ด๋ฒ„ ๋‰ด์Šค ๊ฒ€์ƒ‰์˜ต์…˜

์—ฌํƒ€ ์‚ฌ์ดํŠธ์™€ ๊ฐ™์ด URL ๋ถ€๋ถ„์„ ๋ณด์‹œ๋ฉด ํŠน์ •ํ•œ ๊ตฌ์กฐ๋กœ ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ ค์„œ ์กฐ๊ฑด์— ๋งž๋Š” ๊ฒฐ๊ด๊ฐ’์„ ๋…ธ์ถœํ•˜๋Š” ๊ฒƒ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค:

https://search.naver.com/search.naver?where=news&query=ํ•˜์ด๋ธŒ&sm=tab_opt&sort=0&photo=0&field=0&pd=0&ds=&de=&docid=&related=0&mynews=0
&office_type=0&office_section_code=0&news_office_checked=&nso=so% 3Ar% 2Cp%3 Aall
&is_sug_officeid=0

 

์ง์ ‘ ํ•„ํ„ฐ ์กฐ๊ฑด์„ ๊ฑธ์–ด๊ฐ€๋ฉด์„œ URL์ด ๋ณ€ํ™”ํ•˜๋Š” ๊ฒƒ์„ ๋ณด๋ฉด์„œ ๊ฐ๊ฐ์˜ ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ํ™•์ธ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค:

  • &query=      >  ๊ฒ€์ƒ‰์–ด๊ฐ€ ๋“ค์–ด๊ฐ€๋Š” ์ž๋ฆฌ
  • &sort=0       >  ์–ด๋–ป๊ฒŒ ์ •๋ ฌ์„ ํ• ์ง€ ์ •ํ•˜๋Š” ๋ถ€๋ถ„ (0์€ ๊ด€๋ จ๋„ ์ˆœ)
  • &photo=0   >  ๋‰ด์Šค ์œ ํ˜•์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„ (0์€ ์ „์ฒด)
  • &pd=0          >  ๋‰ด์Šค ๊ธฐ๊ฐ„์„ ์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๋ถ€๋ถ„ (0์€ ์ „์ฒด)
  • &ds=&de=   >  ๋‰ด์Šค ๊ธฐ๊ฐ„์ด ์ง์ ‘์ž…๋ ฅ์ผ ๋•Œ (&pd=3) ์‹œ์ž‘์ผ์ž(&ds=)์™€ ์ข…๋ฃŒ์ผ์ž(&de=)๋ฅผ ์ •ํ•˜๋Š” ๋ถ€๋ถ„ (yyyy.mm.dd ํ˜•์‹)
  • &start=        >  ๋‰ด์Šค ๊ฒ€์ƒ‰๊ฒฐ๊ณผ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋ฅผ ์ง€์ •ํ•˜๋Š” ๋ถ€๋ถ„์ด๋ฉฐ ์ตœ๋Œ€ 400๊นŒ์ง€ ์กด์žฌ (๋„ค์ด๋ฒ„ ๋‰ด์Šค ๊ฒ€์ƒ‰๊ฒฐ๊ณผ๋Š” ์ตœ๋Œ€ 4,000๊ฑด)

์ด๋ ‡๊ฒŒ ์ฐพ์€ ๋‚ด์šฉ์„ ๋”•์…”๋„ˆ๋ฆฌ๋กœ ์ €์žฅ์„ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์œ„์˜ ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ 2022.12.25 ~ 2022.12.31 ๊ธฐ๊ฐ„ ๋™์•ˆ ํ•˜์ด๋ธŒ ๊ด€๋ จ ๋‰ด์Šค ์ง€๋ฉด๊ธฐ์‚ฌ์˜ ๋งํฌ๋ฅผ ์ˆ˜์ง‘ํ•ด ๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์†Œ์Šค์ฝ”๋“œ

from requests_html import HTMLSession

# HTML ์„ธ์…˜
session = HTMLSession()

# ๋„ค์ด๋ฒ„ ๋‰ด์Šค ํ•„ํ„ฐ ์‚ฌ์ „
sort_dict = {'๊ด€๋ จ๋„์ˆœ':'0', '์ตœ์‹ ์ˆœ':'1', '์˜ค๋ž˜๋œ์ˆœ':'2'}

type_dict = {'์ „์ฒด':'0', 'ํฌํ† ':'1', '๋™์˜์ƒ':'2'
             , '์ง€๋ฉด๊ธฐ์‚ฌ':'3', '๋ณด๋„์ž๋ฃŒ':'4', '์ž๋™์ƒ์„ฑ๊ธฐ์‚ฌ':'5'}

period = {'์ „์ฒด' : '0'
          , '1์‹œ๊ฐ„' : '7', '2์‹œ๊ฐ„' : '8', '3์‹œ๊ฐ„' : '9'
          , '4์‹œ๊ฐ„' : '10', '5์‹œ๊ฐ„' : '11', '6์‹œ๊ฐ„' : '12'
          , '1์ฃผ' : '1', '1๊ฐœ์›”': '2', '3๊ฐœ์›”': '13'
          , '6๊ฐœ์›”': '6', '1๋…„' : '5', '์ง์ ‘์ž…๋ ฅ': '3'}

# ์กฐ๊ฑด์— ๋งž๋Š” ๊ฒ€์ƒ‰ ํŒŒ๋ผ๋ฏธํ„ฐ ์„ค์ •

stock_nm = 'ํ•˜์ด๋ธŒ'
sort = '๊ด€๋ จ๋„์ˆœ'
article_type = '์ „์ฒด'
prd = '์ง์ ‘์ž…๋ ฅ'
start_dt =  '2022.12.25' if prd=='์ง์ ‘์ž…๋ ฅ' else ''
end_dt =  '2022.12.31' if prd=='์ง์ ‘์ž…๋ ฅ' else ''

# URL ์ƒ์„ฑ
base_url = 'https://search.naver.com/search.naver?where=news&query='
url_elements = [base_url, stock_nm, '&sm=tab_opt&sort=', sort_dict[sort], '&photo=', type_dict[article_type]
               , '&pd=', period[prd], '&ds=', start_dt, '&de=', end_dt]
               
url = ''.join(url_elements)

# Requests-url๋กœ HTML ์›นํฌ๋กค๋ง ์ง„ํ–‰

news_links = []

for i in range(0,400):  # ๋„ค์ด๋ฒ„๋Š” ์ตœ๋Œ€ 4000๊ฑด ๊นŒ์ง€ ์ œ๊ณต์„ ํ•˜๋ฏ€๋กœ, 400ํŽ˜์ด์ง€๊ฐ€ max
    # URL์— ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ ์ถ”๊ฐ€
    url +=  f'&start={i}1'
      
	## ์„ธ์…˜ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
    r = session.get(url)
    
    ## ๊ฒ€์ƒ‰๊ฒฐ๊ณผ ๋ถ€๋ถ„์— ์žˆ๋Š” ๋‰ด์Šค๋งํฌ ๊ฐ€์ ธ์˜ค๊ธฐ
    links = r.html.find('#main_pack > section > div > div.group_news')[0].absolute_links
    
    ## ๋‰ด์Šค๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ๋งํฌ๋“ค์€ ํŒจํ„ด์„ ํ™œ์šฉํ•˜์—ฌ ์ œ๊ฑฐ
    valid_links = [l for l in links if not l.endswith(('.co.kr','/','.com')) and not l.startswith('https://search.naver.com/?')]
    
    ## ๋ฐ์ดํ„ฐ ์ €์žฅ
    news_links.extend(valid_links)

# ์ค‘๋ณต ๋งํฌ ๊ฐ€๋Šฅ์„ฑ ์ œ๊ฑฐ
news_links = list(set(news_links))
len(news_links)
 
446

446๊ฑด์˜ ๋‰ด์Šค ๊ธฐ์‚ฌ๊ฐ€ ์ˆ˜์ง‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

 

์•„๋ž˜ ๊ฒ€์ƒ‰๊ฒฐ๊ณผ ์ƒ์œผ๋กœ ํŽ˜์ด์ง€ ๋ฒˆํ˜ธ๋Š” 33๊นŒ์ง€ ๋ฐ–์— ์—†์ง€๋งŒ, ๋‰ด์Šค๊ธฐ์‚ฌ๊ฐ€ 446๊ฑด์ด๋‚˜ ๋‚˜์˜จ ์ด์œ ๋Š” ๊ด€๋ จ ๋‰ด์Šค ๊ธฐ์‚ฌ๊นŒ์ง€ ๊ฐ™์ด ์ˆ˜์ง‘์ด ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์•„๋ž˜ ์šฐ์ธก ์Šคํฌ๋ฆฐ์ƒท์— ํ‘œ์‹œ๋œ ๊ด€๋ จ๋‰ด์Šค 11๊ฑด๊ณผ 26๊ฑด ๋ชจ๋‘ 446๊ฑด์— ํฌํ•จ์ด ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ด๋ธŒ ๊ฒ€์ƒ‰๊ฒฐ๊ณผ ํŽ˜์ด์ง€ ์ˆ˜ (์ขŒ)  / ๊ด€๋ จ๋‰ด์Šค (์šฐ)

 

์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ๋„ค์ด๋ฒ„ ๊ฒ€์ƒ‰ ํ•„ํ„ฐ์™€ requests-html์„ ํ™œ์šฉํ•˜์—ฌ ์›ํ•˜๋Š” ์กฐ๊ฑด์˜ ๋‰ด์Šค์˜ ๋งํฌ๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ๋ฒ•์— ๋Œ€ํ•ด ๋‹ค๋ค˜์Šต๋‹ˆ๋‹ค. ์ดํ›„ ํฌ์ŠคํŒ…์—์„œ๋Š” ์ˆ˜์ง‘ํ•œ URL๋กœ ๋‰ด์Šค ์ œ๋ชฉ, ๊ธฐ์‚ฌ ๋“ฑ์˜ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์™€์„œ ์ €์žฅํ•˜๋Š” ๊ฒƒ ๊นŒ์ง€ ๋‹ค๋ฃจ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€