scratchback
๋ค์ด๋ฒ ๋ด์ค์ ์ธ์คํ๊ทธ๋จ์ ํฌ๋กค๋งํ ์ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ๋๋ค.
ํ์ ์ฌํญ
์ต์ ๋ฒ์ ์ Anaconda๋ฅผ ์ฌ์ฉํ๊ณ ๊ณ์๋ ๊ฒ์ ์ถ์ฒ๋๋ฆฝ๋๋ค.
ํ์ง๋ง requests, beautifulsoup4, selenium ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ค์น๋์ด ์์ง ์๋ค๋ฉด ํ๋กฌํํธ(prompt)์์ pip install requests
, pip install beautifulsoup4
, pip install selenium
๋ฅผ ์คํํ์ฌ requests
, beautifulsoup4
, selenium
๋ฅผ ์ค์นํ์
์ผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. http://bit.ly/install-for-crawling ์ ์ฐธ๊ณ ํ์ฌ ํ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ ์ค์นํด์ฃผ์ธ์.
๋ง์ฝ jupyter notebook์์ ์ค์นํ๊ธฐ๋ฅผ ์ํ๋ค๋ฉด !pip install <๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ด๋ฆ>
์ ์
๋ ฅํ๊ณ ์คํ์ํค๋ฉด ์ค์น๊ฐ ์๋ฃ๋ฉ๋๋ค.
๋, Chrome ๋ธ๋ผ์ฐ์ ๋ก ์ธ์คํ๊ทธ๋จ์ ์ ๊ทผํ๊ธฐ ๋๋ฌธ์, ๋ค์์ ๋งํฌ ์์ ํฌ๋กฌ ๋ฒ์ ์ ๋ง๋ ๋๋ผ์ด๋ฒ๋ฅผ ๋ค์ด๋ก๋ ๋ฐ์์ผ ํฉ๋๋ค.
์์
ํ๊ณ ์๋ PC์ ํฌ๋กฌ ๋ฒ์ ์ ์ฃผ์์ฐฝ์ chrome://version/๋ฅผ ์
๋ ฅํ ๊ฒฝ์ฐ ์ ์ ์์ต๋๋ค.
๋งจ ์ฒซ ์ค์ Chrome : 75.0.3770.90์ด๋ผ๊ณ ๋์์์ ๊ฒฝ์ฐ 75 ๋ฒ์ ์ ํฌ๋กฌ์ ์ฌ์ฉํ๊ณ ์๋ ๊ฒ์
๋๋ค.
์ค์น
ํ๋กฌํํธ(prompt) ์ฐฝ์ pip install scratchback
์ ์
๋ ฅํ์ฌ ์ค์นํ ์ ์์ต๋๋ค.
NaverNews Crawler
๋ค์ด๋ฒ ๋ด์ค์์๋ '์๋ณด' ์นดํ
๊ณ ๋ฆฌ์ ๋ด์ค ์ ๋ณด๋ค์ ๊ฐ์ ธ์ค๋ ํฌ๋กค๋ฌ์
๋๋ค. ๊ฐ์ ธ์ค๋ ์ ๋ณด๋ค๋ก๋ ๊ธฐ์ฌ ์ ๋ชฉ, ๊ธฐ์ฌ ๋ณธ๋ฌธ, ๊ธฐ์ฌ ๋ ์ง, ์ ๋ฌธ์ฌ, ๊ธฐ์ฌ id, ๊ธฐ์ฌ url
๊ฐ ์์ต๋๋ค.
์ฌ์ฉ ๋ฐฉ๋ฒ
๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ถ๋ฌ์ค๋ ์ฝ๋๋ ์๋์ ๊ฐ์ต๋๋ค.
from scratchback import NaverNews
crawler = NaverNews()
์์ ๊ฐ์ด NaverNews()
์์ฑ ์์ ์๋ฌด ๊ฒ๋ ์ง์ ํ์ง ์์ ๊ฒฝ์ฐ ์ฝ๋ ์คํํ ๋น์ผ ๋ค์ด๋ฒ ๋ด์ค ์๋ณด ์นดํ
๊ณ ๋ฆฌ์ ์ฒซ ํ์ด์ง ๋ด์ค ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ต๋๋ค.
crawler = NaverNews(page_num=3, page_start=4)
page_num
๊ณผ page_start
๋ฅผ ์ง์ ํจ์ผ๋ก์จ ๋ ์ง๋ณ๋ก ์ด๋ ํ์ด์ง๋ถํฐ ์ผ๋ง๋ ๊ฐ์ ธ์ฌ์ง๋ฅผ ์ ํ ์ ์์ต๋๋ค. ๋ง์ฝ page_num
๊ฐ์ ์ง์ ํ์ง ์๋๋ค๋ฉด ๋ ์ง๋ณ๋ก ํ๋์ ํ์ด์ง๋ง ๊ฐ์ ธ์ค๋ฉฐ, page_start
๋ฅผ ์ ํ์ง ์์ผ๋ฉด 1ํ์ด์ง๋ถํฐ ๊ฐ์ ธ์ค๋๋ก ์ค์ ํ์์ต๋๋ค. ๋ํ ํ์ฌ ์กด์ฌํ๋ ํ์ด์ง ์ ์ด์์ ํ์ด์ง ์๋ฅผ ์
๋ ฅํ๋ฉด ์กด์ฌํ๋ ํ์ด์ง ์ ๋งํผ์ ์ ๋ณด๋ง ๊ฐ์ ธ์ต๋๋ค.
crawler = NaverNews(page_start=4, page_end=10)
page_num
๋์ page_end
๋ฅผ ์ฌ์ฉํ์ฌ ์ด๋์์๋ถํฐ ์ด๋๊น์ง ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ์ง ์ค์ ํ ์ ์์ต๋๋ค. ๋ง์ฝ page_num
, page_start
, page_end
๋ฅผ ์
๋ค ์ค์ ํ์๋๋ฐ page_num
์ด page_end - page_start + 1
๊ฐ๊ณผ ์ผ์นํ์ง ์์ ๊ฒฝ์ฐ ์๋ฌ๊ฐ ๋ฐ์ํ๋ ์ ์ํ์๊ธฐ ๋ฐ๋๋๋ค. page_start
, page_end
๋ฅผ ์ง์ ํ ๊ฒฝ์ฐ page_num
์ ์ง์ ํ์ง ์์๋ ๋ฉ๋๋ค.
crawler = NaverNews(date_start="2019.06.14")
๋ณ์๋ก ๋ ์ง๋ฅผ ์ง์ ํ์ฌ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ผ๋ฉฐ ์
๋ ฅํ๋ ๋ ์ง์ ์์์ YYYY.MM.DD๋ก, ๋ค๋ฅธ ์์์ ์๋ํ์ง ์์ต๋๋ค. ๋ฐ๋ก ๋ ์ง๋ฅผ ์ง์ ํ์ง ์์ผ๋ฉด ์ค๋ ๋ ์ง๋ก ์ง์ ๋๊ณ ๋ฏธ๋์ ๋ ์ง๋ฅผ ์
๋ ฅํด๋ ์๋์ผ๋ก ์ค๋์ ๋ ์ง๋ก ์ง์ ๋ฉ๋๋ค. ๋ ์ง๋ฅผ ์
๋ ฅํ๋ ๋ณ์๋ date_start
์ date_end
๊ฐ ์์ต๋๋ค. ์์ ์ฝ๋์ ๊ฒฝ์ฐ 2019๋
6์ 14์ผ๋ถํฐ ์ฝ๋๋ฅผ ์คํํ๋ ๋ ๊น์ง์ ๋ด์ค ์๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ฉฐ, ์ผ๋ณ๋ก ํ ํ์ด์ง๋ง์ ๊ฐ์ ธ์ค๋ ๊ธฐ๋ฅ์ ํฉ๋๋ค.
crawler = NaverNews(date_start="2019.06.14", date_end="2019.06.16")
date_end
๋ณ์๋ฅผ ํตํด ๊ฐ์ ธ์ค๊ณ ์ ํ๋ ๋ ์ ๋ง์ง๋ง๋ ์ง์ ํ ์ ์์ต๋๋ค. date_end
๋ฅผ ๋ฐ๋ก ์ง์ ํ์ง ์๋ ๋ค๋ฉด ์ค๋ ๋ ์ง๋ก ์ง์ ๋ฉ๋๋ค.
๋ง์ฝ 2019๋ 6์ 14์ผ๋ถํฐ 6์ 16์ผ๊น์ง์ ๋ด์ค ์๋ณด๋ฅผ ๋ ์ง๋ณ๋ก 1ํ์ด์ง๋ถํฐ 10ํ์ด์ง๊น์ง ๊ฐ์ ธ์ค๊ณ ์ถ๋ค๋ฉด, ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ฅผ ํตํด ํฌ๋กค๋งํ ์ ์์ต๋๋ค.
crawler = NaverNews(page_start=1, page_end=10, date_start="2019.06.14", date_end="2019.06.16")
crawl()
๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ๋ค์ด๋ฒ ๋ด์ค ์๋ณด ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
news_list = crawler.crawl()
๊ฒฐ๊ณผ๊ฐ์ธ news_list์ ํํ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
{'headline': '[๋ ์จ] ์ค๋ ์ด์ฌ๋ฆ ๋์ ์ ๊ณณ๊ณณ ์๋๊ธฐ...์ ์ฃผ๋ ยท๋จํด์ ๋น',
'content': '์ค๋๋ ์ด์ฌ๋ฆ ๋์๊ฐ ์ด์ด์ง๋ ๊ฐ์ด๋ฐ ๋ด๋ฅ ๊ณณ๊ณณ์ ์๋๊ธฐ๊ฐ, ์ ์ฃผ๋์ ๋จํด์์๋ ๋น๊ฐ ๋ด๋ฆด ๊ฒ์ผ๋ก ๋ณด์
๋๋ค.๊ธฐ์์ฒญ์ ์ค๋ ์ ์ฃผ๋์ ๋จํด์์ ๋จ์ชฝ์ ์ง๋๊ฐ๋ ๊ธฐ์๊ณจ ์ํฅ์ผ๋ก 5~30mm์ ๋น๊ฐ ์ค๊ฒ ๋ค๊ณ ๋ฐํ์ต๋๋ค.๋ด๋ฅ์ ๋์ฒด๋ก ๋ง๊ฒ ์ง๋ง, ์์์ ๊ฒฝ๋ถ๊ณผ ์ ๋ถ ๋ด๋ฅ์๋ ๋๊ธฐ ๋ถ์์ ์ผ๋ก ์คํ ํ๋ ์๋๊ธฐ๊ฐ ๋ด๋ฆฌ๋ ๊ณณ์ด ์๊ฒ ์ต๋๋ค.์ค๋ ๋ฎ ๊ธฐ์จ์ ์์ธ๊ณผ ๋์ ยท๋๊ตฌ 27๋ ๋ฑ ์ด์ ๋ณด๋ค 1โผ2๋ ๋ฎ์ง๋ง, ์ฌ์ ํ ๋ฅ๊ฒ ์ต๋๋ค.[์ ์๊ถ์(c) YTN & YTN PLUS ๋ฌด๋จ์ ์ฌ ๋ฐ ์ฌ๋ฐฐํฌ ๊ธ์ง]',
'written at': datetime.date(2019, 6, 14),
'company': 'YTN',
'url': 'https://news.naver.com/main/read.nhn?mode=LSD&mid=sec&sid1=001&oid=052&aid=0001306642',
'title': '2๋ฒ์งธ ๋ด์ค',
'id': '052-0001306642'}
๋ฆฌ์คํธ ๋ด์ ๊ฐ๊ฐ์ ๋ด์ค์ ๋ํ ์ ๋ณด๊ฐ ๋์ ๋๋ฆฌ ํํ๋ก ๋ค์ด์๋ ๋ชจ์ต์ ๋๋ค.
์๋์ ์ฝ๋๋ฅผ ํตํด ๊ฒฐ๊ณผ๊ฐ์ ๋ฐ์ดํฐํ๋ ์ ํ์์ผ๋ก ๋ณํํ ๋ค csvํ์ผ๋ก ์ ์ฅํ ์ ์์ต๋๋ค.
import pandas as pd
data = pd.DataFrame(news_list)
data.to_csv("news.csv")
Instagram Crawler
์ธ์คํ๊ทธ๋จ ๊ณ์ ์์ด๋๋ฅผ ์
๋ ฅํ๋ฉด ๊ณ์ ์ ์
๋ก๋๋ ๊ฒ์๋ฌผ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ํฌ๋กค๋ฌ์
๋๋ค.
ํ์ด์ง ๋ก๋ฉ์ 1๋ถ ์ด์ ์์๋ ๊ฒฝ์ฐ ํ๋ก๊ทธ๋จ์ด ๋ฉ์ถ๋๋ก ์ค๊ณ๋์ด ์์ต๋๋ค. ์ธํฐ๋ท ํ๊ฒฝ์ด ์ํํ ๊ณณ์์ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅ๋๋ฆฝ๋๋ค.
์ฌ์ฉ ๋ฐฉ๋ฒ
์๋์ ๊ฐ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ถ๋ฌ์ฌ ์ ์์ต๋๋ค. Instagram ๊ฐ์ฒด ์์ฑ ์, ๋ค์ด๋ก๋ ๋ฐ์ chromedriver์ ๊ฒฝ๋ก๋ฅผ ์ ๋ ฅํด์ฃผ์ด์ผ ํฉ๋๋ค.
from scratchback import Instagram
crawler = Instagram("chromedriver")
crawler ๋ณ์ ์์ฑ ์ headless
์ต์
์ False
๋ก ์ง์ ํ๋ฉด Chrome ๋ธ๋ผ์ฐ์ ๋ฅผ ํตํด ํฌ๋กค๋ง ์งํ ์ํฉ์ ํ์ธํ ์ ์์ต๋๋ค.
crawler = Instagram("chromedriver", headless=False)
crawl()
๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ํฌ๋กค๋ง์ ํ ์ ์์ต๋๋ค. ์ด ๋, ํฌ๋กค๋งํ๊ณ ์ ํ๋ ๊ณ์ ์ ์์ด๋๋ฅผ ์
๋ ฅํด์ฃผ์ด์ผ ํฉ๋๋ค.
post_list = crawler.crawl("dsschoolkr")
posts
์ต์
์ ์ง์ ํ๋ฉด ๊ฐ์ ธ์ค๋ ค๊ณ ํ๋ ๊ฒ์๋ฌผ์ ๊ฐ์๋ฅผ ์กฐ์ ํ ์ ์์ต๋๋ค. ์๋์ ๊ฐ์ด posts
๋ฅผ 2๋ก ์ง์ ํ ๊ฒฝ์ฐ, ํด๋น ๊ณ์ ์ ์ ์ผ ์ต๊ทผ ๊ฒ์๋ฌผ ๋๊ฐ์ ์ ๋ณด๋ฅผ ๋ฐํํฉ๋๋ค.
post_list = crawler.crawl("dsschoolkr", posts=2)
๊ฒฐ๊ณผ๊ฐ์ธ post_list
์ ํํ๋ ์๋์ ๊ฐ์ต๋๋ค.
[{'comments': '0',
'content': '์ค๋๋ฐค(6/9) 8์ ์ ํ๋ธ ์คํธ๋ฆฌ๋ฐ์ผ๋ก ์คํ๋ฒ
์ค 1ํธ ๋ฐ์ดํฐ์ฌ์ด์ธํฐ์คํธ๊ฐ ์ง์
/์ ๋ง/๋ฐ์ดํฐ์ ๊ด๋ จ๋ ์ง๋ฌธ์ ์ง์ ๋ต๋ณ๋๋ฆฝ๋๋ค :)์ฐธ์ฌ๋ฐฉ๋ฒ์ ํ๋กํ ์ค๋ช
์ ํ์ธํด์ฃผ์ธ์!',
'img_src': ['https://scontent-icn1-1.cdninstagram.com/vp/0665d8f0404e266aa84d3d77eb919b56/5DC64220/t51.2885-15/e35/61234597_166094021086395_2911502642251464796_n.jpg?_nc_ht=scontent-icn1-1.cdninstagram.com'],
'like': '8',
'post_id': 'ByezZRLBSjV'}]
๋ฆฌ์คํธ ๋ด์ ๊ฐ๊ฐ์ ๊ฒ์๋ฌผ์ ๋ํ ์ ๋ณด๊ฐ ๋์ ๋๋ฆฌ ํํ๋ก ๋ค์ด์๋ ๋ชจ์ต์ ๋๋ค.
post_id
๋ ๊ฒ์๋ฌผ์ ๊ณ ์ id๋ฅผ ์๋ฏธํฉ๋๋ค. img_src
์๋ ์ด๋ฏธ์ง ํน์ ๋์์์ url ์ ๋ณด๊ฐ ๋ฆฌ์คํธ ํํ๋ก ๋ด๊ฒจ์์ผ๋ฉฐ, content
์๋ ๊ฒ์๋ฌผ์ ์์ฑ๋ ๋ฌธ๊ตฌ๊ฐ ๋ด๊ฒจ์์ต๋๋ค. like
๋ ๊ฒ์๋ฌผ ์ข์์ ๊ฐ์, comments
๋ ๊ฒ์๋ฌผ์ ๋ฌ๋ฆฐ ๋๊ธ์ ๊ฐ์๋ฅผ ์๋ฏธํฉ๋๋ค.
์๋์ ์ฝ๋๋ฅผ ํตํด ๊ฒฐ๊ณผ๊ฐ์ ๋ฐ์ดํฐํ๋ ์ ํ์์ผ๋ก ๋ณํํ๊ณ csvํ์ผ๋ก ์ ์ฅํ ์ ์์ต๋๋ค.
import pandas as pd
data = pd.DataFrame(post_list)
data.to_csv("post.csv")