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.