Post

[Python] ํฌ๋กค๋ง(Crawling)

๐Ÿ“Œ ๋“ค์–ด๊ฐ€๋ฉฐ

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ํฌ๋กค๋ง(Crawling)์œผ๋กœ ์›น ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•œ๋‹ค. ๋‹ค์Œ ๋‰ด์Šค ํ—ค๋“œ๋ผ์ธ๊ณผ ๋กœ๋˜ ๋ฒˆํ˜ธ๋ฅผ ๊ฐ€์ ธ์™€ ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์œผ๋กœ ๋งŒ๋“ค๊ณ  ์‹œ๊ฐํ™”๊นŒ์ง€ ํ•ด๋ณธ๋‹ค.

ํฌ๋กค๋Ÿฌ(crawler): ์ž๋™ํ™”๋œ ๋ฐฉ๋ฒ•์œผ๋กœ ์›น์„ ํƒ์ƒ‰ํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ. ์›น์„ ํ›‘๋Š” ๊ฒƒ์ด ์›น ํฌ๋กค๋ง, ๊ทธ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ๊ฒƒ์ด ๋ฐ์ดํ„ฐ ํฌ๋กค๋ง์ด๋‹ค.

ํฌ๋กค๋ง์˜ ๊ธฐ๋ณธ ํ๋ฆ„:

1
โ‘  URL ์ •์˜ โ†’ โ‘ก requests.get()์œผ๋กœ ์š”์ฒญ โ†’ โ‘ข BeautifulSoup์œผ๋กœ HTML ๋ณ€ํ™˜ โ†’ โ‘ฃ select()๋กœ ์›ํ•˜๋Š” ํƒœ๊ทธ ์„ ๋ณ„

1. ๋‰ด์Šค ํ—ค๋“œ๋ผ์ธ ํฌ๋กค๋ง

1
2
3
4
5
6
7
8
# ๋‹ค์Œ ๋‰ด์Šค ํŽ˜์ด์ง€ ํฌ๋กค๋ง
url = 'https://news.daum.net/'

resp = requests.get(url)                              # โ‘ก ์š”์ฒญ
html = BeautifulSoup(resp.text, 'html.parser')        # โ‘ข HTML ๋ณ€ํ™˜

for news in html.select('a.link_txt')[:-13]:          # โ‘ฃ ํƒœ๊ทธ ์„ ๋ณ„
    print(news.text.strip().replace('[', '').replace(']', ''))

Desktop View

๐Ÿ’ก ๊ฐœ๋ฐœ์ž ๋ชจ๋“œ๋กœ ์›ํ•˜๋Š” ์š”์†Œ์˜ ํƒœ๊ทธ(a.link_txt)๋ฅผ ํ™•์ธํ•ด select()์— ๋„ฃ๋Š”๋‹ค. .text.strip()์œผ๋กœ ํ…์ŠคํŠธ๋งŒ ์ถ”์ถœํ•˜๊ณ  .replace()๋กœ ๋ถˆํ•„์š”ํ•œ ๋ฌธ์ž๋ฅผ ์ •๋ฆฌํ•œ๋‹ค.


2. ๋กœ๋˜ ๋ฒˆํ˜ธ ํฌ๋กค๋ง (1~30ํšŒ์ฐจ)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
lotto_list = []
for i in range(1, 31):
    print(f'{i}ํšŒ์ฐจ ํฌ๋กค๋ง ์ค‘์ž…๋‹ˆ๋‹ค.')

    # ์ฐจ๋‹จ ๋ฐฉ์ง€ (๋žœ๋ค ๋”œ๋ ˆ์ด)
    seed = np.random.randint(100)
    np.random.seed(seed)
    time.sleep(np.random.randint(5))

    url = f'https://search.daum.net/search?w=tot&DA=LOT&q={i}ํšŒ์ฐจ%๋กœ๋˜'
    resp = requests.get(url)
    html = BeautifulSoup(resp.text, 'html.parser')

    for ball_nm in html.select('span.ball')[:6]:
        lotto_list.append(int(ball_nm.text))

print('ํฌ๋กค๋ง ์™„๋ฃŒ!!!')

โš ๏ธ ๋ฐ˜๋ณต ์š”์ฒญ ์‹œ ์ฐจ๋‹จ(block)์„ ํ”ผํ•˜๊ธฐ ์œ„ํ•ด ๋žœ๋ค ๋”œ๋ ˆ์ด(time.sleep)๋ฅผ ์ค€๋‹ค. ๋ชจ๋“  ๋ฒˆํ˜ธ๋ฅผ ํ•˜๋‚˜์˜ ๋ฆฌ์ŠคํŠธ์— ๋‹ด๋Š” ์ด์œ ๋Š”, ์ดํ›„ reshape์œผ๋กœ ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•จ์ด๋‹ค.


3. ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„ ๋ณ€ํ™˜

1
2
3
4
lotto = np.array(lotto_list).reshape(-1, 6)   # 6๊ฐœ์”ฉ ๋ฌถ์–ด ํšŒ์ฐจ๋ณ„ ํ–‰์œผ๋กœ
index_list = [f'{i}ํšŒ์ฐจ' for i in range(1, 31)]
df = pd.DataFrame(lotto, index=index_list)
df

Desktop View

๐Ÿ’ก reshape(-1, 6)์€ โ€œ์—ด์€ 6๊ฐœ๋กœ ๊ณ ์ •, ํ–‰์€ ์ž๋™ ๊ณ„์‚ฐโ€์ด๋ผ๋Š” ๋œป. ๋ฆฌ์ŠคํŠธ๋ฅผ ํšŒ์ฐจ๋ณ„ 6๊ฐœ ๋ฒˆํ˜ธ์˜ ํ‘œ๋กœ ์žฌ๊ตฌ์„ฑํ•œ๋‹ค.


4. ์‹œ๊ฐํ™”

1
2
3
4
5
6
import seaborn as sns
import matplotlib.pyplot as plt

plt.figure(figsize=(12, 6))
sns.countplot(lotto_list)   # ๋ฒˆํ˜ธ๋ณ„ ์ถœํ˜„ ๋นˆ๋„
plt.show()

Desktop View

countplot์œผ๋กœ ๊ฐ ๋ฒˆํ˜ธ์˜ ๋นˆ์ถœ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ’ก ๋ฒˆํ˜ธ๋ณ„ ํŽธ์ฐจ๊ฐ€ ํฐ ๊ฒƒ์€ ํ‘œ๋ณธ์ด 30ํšŒ์ฐจ๋ฟ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ํšŒ์ฐจ๊ฐ€ ๊ธธ์–ด์งˆ์ˆ˜๋ก ํ†ต๊ณ„์  ํ™•๋ฅ (๊ท ๋“ฑ)์— ๊ฐ€๊นŒ์›Œ์งˆ ๊ฒƒ์ด๋‹ค.


๐Ÿ“ ์ •๋ฆฌ

1
2
3
4
5
6
ํฌ๋กค๋ง ํ๋ฆ„
โ”œโ”€ ์š”์ฒญ       requests.get(url)
โ”œโ”€ ํŒŒ์‹ฑ       BeautifulSoup(resp.text, 'html.parser')
โ”œโ”€ ์„ ๋ณ„       html.select('ํƒœ๊ทธ')
โ”œโ”€ ์ฐจ๋‹จ ๋ฐฉ์ง€  time.sleep()์œผ๋กœ ๋žœ๋ค ๋”œ๋ ˆ์ด
โ””โ”€ ๊ฐ€๊ณต/์‹œ๊ฐํ™”  reshape โ†’ DataFrame โ†’ countplot
๋„๊ตฌ์—ญํ• 
requestsURL์— ๋ฐ์ดํ„ฐ ์š”์ฒญ
BeautifulSoupHTML ํŒŒ์‹ฑ
select()CSS ์„ ํƒ์ž๋กœ ํƒœ๊ทธ ์ถ”์ถœ
reshape/DataFrame์ˆ˜์ง‘ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ๋กœ

ํฌ๋กค๋ง์€ โ€œ์š”์ฒญ โ†’ ํŒŒ์‹ฑ โ†’ ์„ ๋ณ„โ€์˜ ๋‹จ์ˆœํ•œ 3๋‹จ๊ณ„ ํ๋ฆ„์ด๋‹ค. ์—ฌ๊ธฐ์— ์ฐจ๋‹จ ๋ฐฉ์ง€(๋”œ๋ ˆ์ด)์™€ ๋ฐ์ดํ„ฐ ๊ฐ€๊ณต(DataFrame)์„ ๋”ํ•˜๋ฉด ์‹ค์šฉ์ ์ธ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ ํŒŒ์ดํ”„๋ผ์ธ์ด ์™„์„ฑ๋œ๋‹ค.

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.