์ผ | ์ | ํ | ์ | ๋ชฉ | ๊ธ | ํ |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- ๊ทธ๋ฆฌ๋
- Crawling
- OS
- JPA
- ์ ๋ ๋์
- ์นด์นด์ค
- ์ผ์ฑ๊ธฐ์ถ
- ๋ฐฑ์ค
- ์นํฌ๋กค๋ง
- selenium
- ๋จ์ํ ์คํธ
- ํด์
- API
- Java
- ์๊ณ ๋ฆฌ์ฆ
- ์ด์์ฒด์
- ํ๋ก๊ทธ๋๋จธ์ค
- ๋งคํธ๋ฉ
- ์นด์นด์ค๊ธฐ์ถ
- BFS
- ToyProject
- spring
- python
- ์ด์งํ์
- webcrawling
- ํด์๋ฒ
- ์์์ฒ๋ฆฌ
- ํฌ๋กค๋ง
- ํ์ด์ฌ
- matlab
DevKim
[ Webtooniverse ] 2์ฐจ DB ๊ตฌ์ถ- ์นด์นด์ค ์นํฐ ํฌ๋กค๋ง ๋ณธ๋ฌธ
[ Webtooniverse ] 2์ฐจ DB ๊ตฌ์ถ- ์นด์นด์ค ์นํฐ ํฌ๋กค๋ง
on_doing 2021. 8. 5. 11:56๐ Webtooniverse ์ ํต์ฌ์ธ ์นํฐ ๋ฐ์ดํฐ๋ฅผ ์์งํด๋ณด์ ๐
๋๋์ด ๊ธฐ๋ค๋ฆฌ๊ณ ๊ธฐ๋ค๋ฆฌ๋ ์นด์นด์ค ์นํฐ์ด ์ถ์๋๋ค!
๊ธฐ์กด์ ๋ค์์นํฐ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ค๊ณ ํ์ผ๋, ์นด์นด์ค ์นํฐ๊ณผ ํฉ์ณ์ง๋ค๋ ๊ธฐ์ฌ๋ฅผ ๋ณด๊ณ ์ถ์๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๊ธฐ๋ก ํ๋ค.
์ฌ์ดํธ๋ฅผ ๋ณด์๋ง์ ๋ ์๊ฐ์, ์..ํฌ๋กค๋ง ํ๊ธฐ ์ฝ์ง ์๊ฒ ๊ตฌ๋์๋ค.
[ ์์งํ ๋ฐ์ดํฐ ]
ํฌ๋กค๋งํด์ผ ํ ์นํฐ ์นดํ ๊ณ ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ๋ค.
1. ์นํฐ ์์ - ์์ผ๋ณ ์ํ๋ค์ ์ ๋ณด๋ค
2. ์์ค ์์ - ์์ผ๋ณ ์ํ๋ค์ ์ ๋ณด๋ค
3. ์๊ฒฐ ์นํฐ - ์นํฐ ์์ 50๊ฐ + ์์ค ์์ 50๊ฐ
[ ์ฌ์ดํธ ๋ถ์ ์ด์ ]
"๋ค์ด๋ฒ ์นํฐ ์ฌ์ดํธ์ ๋ฌ๋ฆฌ ์นด์นด์ค ์นํฐ์ ์ฌ์ดํธ ์ ์ฒด๋ฅผ selenium์ผ๋ก ์๋ํํ๊ธฐ์ ์ด๋ ค์์ด ์์๋ค."
1. ์ฌ์ดํธ๋ง ๋ด๋ ์๊ฒ ์ง๋ง, ์ค๊ฐ์ค๊ฐ ์์ ์ธ๋ค์ผ์ด ์๊ณ ์์ ์ธ๋ค์ผ๊ณผ ๊ทธ๋ ์ง ์์ ์ธ๋ค์ผ์ ํ๊ทธ๊ฐ ๋ค๋ฅด๋ค.
2. ์ฑ์ธ ์นํฐ์ ๋น๋ก๊ทธ์ธ ์ํ์์ click์ด ๋์ง ์๋๋ค.
3. ๋๋ค์์ ์ฌ์ดํธ์ ๊ฒฝ์ฐ nth-child ๊ฐ์ด 1,2,3,4.. ์ด๋ ๊ฒ ์์ฐจ์ ์ผ๋ก ์ฆ๊ฐํ์ง๋ง,
์นด์นด์ค ์นํฐ์ ๊ฒฝ์ฐ ๋ค์ฃฝ๋ฐ์ฃฝ์ธ ๊ฒฝ์ฐ๊ฐ ๋ง์๋ค.
4. ์นํฐ ์์ ํญ์ ๊ฒฝ์ฐ, ์์ ์ธ๋ค์ผ์ ์์น๊ฐ ์ผ์ ํ์ง๋ง ์์ค์์ ํญ์ ๊ฒฝ์ฐ, ์ธ๋ค์ผ์ ์์น๊ฐ ๋ถ๊ท์น์ ์ด๋ค.
5. ์ํ์ ์ ๋ณด๋ค์ ๊ฐ์ ธ์์ผํ๋๋ฐ ์ํ ํด๋ฆญ์, ์์์ด ์ฌ์๋๋ ์นํฐ๋ค์ด ์๋ค.
[ ์ ๊ทผ ๋ฐฉ๋ฒ ]
์นํฐ ์ ๋ณด์ ์ ๊ทผํ๋ ๊ฒ๋ ์ฒ์์ ์ด๋ ค์์ด ์์์ง๋ง,
์ ๋ชฉ๊ณผ ์๊ฐ, ์ฅ๋ฅด ์ ๋ณด๋ head ํ๊ทธ์์ ๊ฐ์ ธ์ฌ ์ ์์๋ค. ๋คํ์ด๋ ๋ด๋ถ ํ๊ทธ๋ ๋์ผํ๋ค.
1. ์ฑ์ธ ์นํฐ์ ๊ฑด๋๋ด๋ค.
1-1. ์ด์ฐจํผ ๋ง๋ค๊ณ ์ํ๋ ์ฌ์ดํธ์์๋ ์นด์นด์ค ์นํฐ์ด ๋ง์๋ ์ํ ๋ด์ฉ์ ๋ณด์ฌ์ค ์ ์๋ค.
1-2. ์ฑ์ธ ์นํฐ์ '์นด์นด์ค ํ์ด์ง์์ ๋ก๊ทธ์ธ ํ ์ฌ์ฉํด์ฃผ์ธ์'๋ผ๋ ๋ฌธ๊ตฌ๋ก ๋์ฒดํ๋ค.
2. ์์ง์ด๋ ์ธ๋ค์ผ๊ณผ ์์ง์ด์ง ์๋ ์ด๋ฏธ์ง ์ธ๋ค์ผ์ ๊ฐ๊ฐ์ ๋ฉ์๋๋ก ๋ง๋ค์
3. nth-child ์์๋ ์ด์ฉ ์ ์์ด ์์ผ๋ณ๋ก ํ์ธํด์ฃผ์ด์ผํ๋ค.
4. ์์ธ ํ์ด์ง๋ก ํด๋ฆญ์, ์์์ด ๋ฐ๋ก ์ฌ์๋๋ ๊ฒฝ์ฐ๋ฅผ ๊ณ ๋ คํ์ฌ time.sleep์ 30์ด๋ก ๊ธธ๊ฒ ์ก์์ค๋ค.
[ ์ฝ๋ ]
1. ์์ ์ธ๋ค์ผ์ ์นํฐ
- m : ์์ผ์ ๋ํ๋ด๋ ์ซ์ (์=1,ํ=2..)
- day : ์์ผ์ ๋ํ๋ด๋ ๋ฌธ์ (์,ํ,์.....)
์นํฐ๊ณผ ์ฅ๋ฅด์ FK๋ ๊ฐ์ด ๋ฃ์ด์ค์ผํ๊ธฐ ๋๋ฌธ์,
์นํฐ PK๊ฐ์ DB์ ์ง์์ ์ผ๋ก ๋์กฐํ๋ฉด์ ํ์ธํด์ฃผ๋ ์์ ์ด ์ถ๊ฐ์ ์ผ๋ก ํ์ํ๋ค.
def week_toon_move(m, day):
global index
# =============================================์์ง์ด๋ ์นํฐ ํด๋ฆญ=============================================#
# ์ธ๋ค์ผ
toon_img = driver.find_element_by_css_selector(
f'#root > main > div > div.page.color_bg_black__2MXm7.activePage > div.swiper-container.swiper-container-initialized.swiper-container-horizontal.swiper-container-pointer-events > div > div.swiper-slide.swiper-slide-active > div > div > div > div > div > div:nth-child({m}) > div.Masonry_masonry__38RyV > div:nth-child(1) > div > div > div > div > div > a > video'
).get_attribute('poster')
driver.find_element_by_css_selector(
f'#root > main > div > div.page.color_bg_black__2MXm7.activePage > div.swiper-container.swiper-container-initialized.swiper-container-horizontal.swiper-container-pointer-events > div > div.swiper-slide.swiper-slide-active > div > div > div > div > div > div:nth-child({m}) > div.Masonry_masonry__38RyV > div:nth-child(1) > div > div > div > div > div > a > video'
).click()
time.sleep(23)
# ์ ๋ชฉ
toon_title=driver.find_element_by_css_selector('head > meta:nth-child(33)').get_attribute('content').strip()
# ์๊ฐ
toon_author=driver.find_element_by_css_selector('head > meta:nth-child(27)').get_attribute('content')
temp_List=toon_author.split(',')
temp_List=temp_List[1:-1]
toon_author=' / '.join(temp_List).strip()
# ์ค๋ช
toon_content=driver.find_element_by_css_selector('head > meta:nth-child(26)').get_attribute('content')
# ์์ผ
toon_weekday = day
# ์ค์ ์ฌ์ดํธ
real_url = driver.current_url
# ์ค์ ํ๋ซํผ
toon_platform = '์นด์นด์ค'
# ์๊ฒฐ ์ฌ๋ถ
finished = False
#์ฅ๋ฅด
genre = driver.find_element_by_css_selector(
'#root > main > div > div.page.color_bg_black__2MXm7.activePage > div > div.Content_homeWrapper__2CMgX.common_positionRelative__2kMrZ > div.Content_metaWrapper__3srNJ > div.Content_contentMainWrapper__3AlhK.Content_current__2yPD8 > div.spacing_pb_28__VqvVT.spacing_pt_96__184F4 > div.common_positionRelative__2kMrZ.spacing_mx_a__2yxXH.spacing_my_0__1f7t6.MaxWidth_maxWidth__2Qvbl > div.Meta_meta__1HmBY.spacing_mx_20__17RDr.spacing_mt_16__29c-N > div > div > p.Text_default__HZL19.textVariant_s13_regular_white__1-AxN.spacing_ml_3__2NL9t.opacity_opacity85__gH87s').text
data.append(
[toon_title, toon_author, toon_content, toon_img, toon_weekday, real_url, None, toon_platform, finished,genre])
print([toon_title, toon_author, toon_content, toon_img, toon_weekday, real_url, None, toon_platform, finished,genre])
sql = "INSERT INTO webtoon (toon_title, toon_author, toon_content, toon_img, toon_weekday, real_url, toon_age, toon_platform, finished,toon_avg_point,review_count,total_point_count) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s,%s,%s,%s)"
val = (toon_title, toon_author, toon_content, toon_img, toon_weekday, real_url, None, toon_platform, finished,0,0,0)
cur.execute(sql, val)
conn.commit()
genre_List=dic[genre]
for genre_id in genre_List:
sql = "INSERT INTO webtoon_genre(toon_id,genre_id) VALUES (%s, %s)"
val = (index,genre_id)
cur.execute(sql, val)
conn.commit()
index+=1
driver.back()
time.sleep(2)
2. ์ด๋ฏธ์ง ์ธ๋ค์ผ ์นํฐ
- m: ์์ผ ๋ณ ์ซ์
- day: ์์ผ ์ด๋ฆ
- start : nth-child(start)
- end :nth-child(end)
์นํฐ ์์์ ๊ฒฝ์ฐ nth-child ์ซ์๊ฐ 2,3,5,7,8.. ์ด๋ฐ์์ผ๋ก ์ฆ๊ฐํ๋ ๊ฒ ๊ฐ๋ค.
๋์ค์๋ ๊ท์น์ ์ฐพ์์ 2,3,5 ๋ฐ๋ก 7~ ๋๊น์ง ์ด๋ ๊ฒ ๋ถ๋ฆฌํด์ ๋๊ฐ์ ๋ฉ์๋๋ก ๋นผ๋๊ณ ์ฝ๋๋ฅผ ๋๋ ธ๋ค.
์ค๊ฐ์ ์ฑ์ธ ๋งํ๊ฐ ๋ค์ด๊ฐ ๊ฒฝ์ฐ, ๊ฑด๋๋ฐ์ด์ผํ๊ธฐ ๋๋ฌธ์ ์ด ๊ฒฝ์ฐ ๋ํ ๊ณ ๋ คํด์ฃผ์ด์ผํ๋ค.
def week_toon_range(m, day, start,end):
global index
for i in range(start, end + 1):
# ์ธ๋ค์ผ
toon_img = driver.find_element_by_css_selector(
f'#root > main > div > div.page.color_bg_black__2MXm7.activePage > div.swiper-container.swiper-container-initialized.swiper-container-horizontal.swiper-container-pointer-events > div > div.swiper-slide.swiper-slide-active > div > div > div > div > div > div:nth-child({m}) > div.Masonry_masonry__38RyV > div:nth-child({i}) > div > div > div > div > a > picture > img'
).get_attribute('src')
# ์นํฐ ํด๋ฆญ
driver.find_element_by_css_selector(
f'#root > main > div > div.page.color_bg_black__2MXm7.activePage > div.swiper-container.swiper-container-initialized.swiper-container-horizontal.swiper-container-pointer-events > div > div.swiper-slide.swiper-slide-active > div > div > div > div > div > div:nth-child({m}) > div.Masonry_masonry__38RyV > div:nth-child({i}) > div > div > div > div > a'
).click()
time.sleep(30)
# ์ฑ์ธ์นํฐ ํจ์ค
# try:
# driver.find_element_by_css_selector(
# 'body > div:nth-child(21) > div > div > div >div.common_positionAbsolute__3eY3C.common_widthFull__1hw6a.spacing_px_20__1gg7C.Alert_buttonsWrap__2fPaV >button').click()
# time.sleep(3)
# ์นํฐ ์ ๋ณด
# ์ ๋ชฉ
toon_title=driver.find_element_by_css_selector('head > meta:nth-child(32)').get_attribute('content').strip()
# ์๊ฐ
toon_author = driver.find_element_by_css_selector('head > meta:nth-child(27)').get_attribute('content')
temp_List = toon_author.split(',')
temp_List = temp_List[1:-1]
toon_author = ' / '.join(temp_List).strip()
# ์ค๋ช
toon_content = driver.find_element_by_css_selector('head > meta:nth-child(26)').get_attribute('content')
# ์์ผ
toon_weekday = day
# ์ฐ๋ น
# toon_age
# ์ค์ ์ฌ์ดํธ
real_url = driver.current_url
# ์ค์ ํ๋ซํผ
toon_platform = '์นด์นด์ค'
# ์๊ฒฐ ์ฌ๋ถ
finished = False
# ์ฅ๋ฅด
genre = driver.find_element_by_css_selector(
'#root > main > div > div.page.color_bg_black__2MXm7.activePage > div > div.Content_homeWrapper__2CMgX.common_positionRelative__2kMrZ > div.Content_metaWrapper__3srNJ > div.Content_contentMainWrapper__3AlhK.Content_current__2yPD8 > div.spacing_pb_28__VqvVT.spacing_pt_96__184F4 > div.common_positionRelative__2kMrZ.spacing_mx_a__2yxXH.spacing_my_0__1f7t6.MaxWidth_maxWidth__2Qvbl > div.Meta_meta__1HmBY.spacing_mx_20__17RDr.spacing_mt_16__29c-N > div > div > p.Text_default__HZL19.textVariant_s13_regular_white__1-AxN.spacing_ml_3__2NL9t.opacity_opacity85__gH87s').text
data.append([toon_title, toon_author, toon_content, toon_img, toon_weekday, real_url, None, toon_platform,
finished,genre])
print([toon_title, toon_author, toon_content, toon_img, toon_weekday, real_url, None, toon_platform,
finished,genre])
sql = "INSERT INTO webtoon (toon_title, toon_author, toon_content, toon_img, toon_weekday, real_url, toon_age, toon_platform, finished,toon_avg_point,review_count,total_point_count) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s,%s,%s,%s)"
val = (toon_title, toon_author, toon_content, toon_img, toon_weekday, real_url, None, toon_platform, finished,0,0,0)
cur.execute(sql, val)
conn.commit()
genre_List = dic[genre]
for genre_id in genre_List:
sql = "INSERT INTO webtoon_genre(toon_id,genre_id) VALUES (%s, %s)"
val = (index,genre_id)
cur.execute(sql, val)
conn.commit()
index+=1
driver.back()
time.sleep(3)
[ ๊ฒฐ๊ณผ ๊ฐ ]
์ค๊ฐ ๊ณผ์ ์ด ํ๋ํ์ง๋ง..
db์ ๊ฒฐ๊ณผ ๊ฐ์ด ์ ์์ ์ผ๋ก ์ ์ฅ๋๋ ๊ฒ์ ํ์ธํ ์ ์๋ค.
์ฅ๋ฅด์ ์นํฐ์ ์ฐ๊ฒฐ ํ ์ด๋ธ์๋ ์ ๋ค์ด๊ฐ์ง๋ค.