DS Study/Web Scraping

[Web Scraping] [3.2] Regular Expressions

23학번이수현 2025. 3. 26. 13:59

1. 왜 정규표현식이 필요할까?

- 기본적으로 BeautifulSoup의 find(), find_all(), select() 등을 쓰면 정해진 태그와 속성에 따라 데이터를 가져올 수 있다.

- 하지만,

i) 정확한 문자열이 아니라 패턴으로 데이터를 찾거나,

ii) 부분 일치 / 유동적인 텍스트 / 숫자 포함 여부 등을 찾고 싶다면,

- 정규표현식을 사용한다면 쉽게 찾을 수 있다.

- 파이썬에선 re module로 쉽게 활용가능하다.

 

2. 정규표현식을 BeautifulSoup에서 쓰는 방법

- re 모듈을 활용하면 다음 항목에서 정규표현식 사용이 가능하다.

"""

i) name : 태그 이름이 특정 패턴과 일치하는 경우

ii) text : 텍스트 내용이 패턴과 일치하는 경우

iii) attrs : 속성 값이 특정 패턴을 따를 때
"""

import re
from bs4 import BeautifulSoup

 

3. Example

- 다음과 같은 HTML 코드가 있다고 가정해보자.

html = '''
<html>
  <body>
    <h1>Python Tutorial</h1>
    <p class="content">Welcome to Python</p>
    <p class="content">Learn more about Data Science</p>
    <a href="/article/123">Article 123</a>
    <a href="/article/456">Article 456</a>
    <a href="/about">About Us</a>
  </body>
</html>
'''

soup = BeautifulSoup(html, 'html.parser')

 

- 여기서 특정 텍스트("Python")이 포함된 태그를 찾는다면 다음과 같이 찾을 수 있다.

import re

results = soup.find_all(text=re.compile('Python'))
for r in results:
    print(r)

------------------------------------------------
Output

Python Tutorial
Welcome to Python

- text = re.compile()은 텍스트 내용을 대상으로 정규표현식을 적용할 수 있게 해준다.

 

- href에서 /article로 시작하는 attribute를 찾고싶다면 다음과 같이 할 수 있다.

links = soup.find_all('a', href=re.compile('^/article/'))

for link in links:
    print(link['href'])


----------------------------------------------------------------
Output

/article/123
/article/456

 

- '^STRING' 여기서 ^는 STRING으로 시작하는 text를 다 찾아준다.

 

- 이러한 정규표현식을 키에 적용도 가능하다.

# 태그 이름이 'h'로 시작하는 모든 태그 찾기
headers = soup.find_all(re.compile('^h'))

for h in headers:
    print(h.name, h.text)
h1 Python Tutorial

 

- 뿐만 아니라, content가 class인 아이들도 추출가능하다.

# class가 content로 끝나는 태그 찾기
content_tags = soup.find_all('p', class_=re.compile('content$'))

for tag in content_tags:
    print(tag.text)

Welcome to Python  
Learn more about Data Science

 

4. 정규표현식을 이용하여 email을 추출

- 정규표현식은 문자열에서 특정한 패턴을 찾아내기 위한 강력한도구이다.

- Web Scraping할 때, 특정 데이터(이메일, 날짜, 숫자 등)을 추출할 때 매우 유용하게 쓰인다.

re.findall(r'\d+', '총 1,234명이 참여했습니다')  # ['1', '234']

 

- 이를 이용하여 이메일 주소를 추출해보자.

- 일반적인 이메일 주소의 포맷은 다음과 같은 형태다.

[\w\.-]+@[\w\.-]+\.\w+	

re.findall(r'[\w\.-]+@[\w\.-]+\.\w+', '문의: hello@example.com')  
# ['hello@example.com']

 

- 전화번호는 다음과 같다.

re.findall(r'01[0-9]-\d{3,4}-\d{4}', '문의는 010-1234-5678로 주세요')

 

- 날짜는 다음과 같다.