웹사이트의 body 콘텐츠를 추출하는 함수를 OpenFaaS를 이용해 구현하려면 사용자 정의 함수를 작성해야 합니다. OpenFaaS를 활용해 함수를 구성하고 배포하는 과정입니다.
1. OpenFaaS 환경 준비
(1) OpenFaaS 설치
OpenFaaS를 설치하려면 faasd 또는 Kubernetes 환경을 사용할 수 있습니다. OpenFaaS CLI(faas-cli)도 함께 설치해야 합니다.
curl -sSL https://cli.openfaas.com | sudo sh
(2) OpenFaaS 로그인
OpenFaaS에 로그인하여 배포를 준비합니다.
faas-cli login --username=admin --password=<your-password>
2. 기본 제공 함수 확인
OpenFaaS는 다양한 기본 제공 함수 템플릿을 제공합니다. 아래는 대표적인 템플릿들입니다.
(1) Node.js 템플릿
Node.js 기반의 함수를 빠르게 작성할 수 있는 템플릿으로, 비동기 작업과 REST API 구현에 적합합니다.
faas-cli template store pull node
(2) Python 템플릿
Python으로 작성된 함수를 생성할 수 있는 템플릿으로, 데이터 분석, 웹 스크래핑, 간단한 데이터 처리 작업에 유용합니다.
faas-cli template store pull python3
(3) Golang 템플릿
Golang 기반 템플릿은 높은 성능과 효율성을 요구하는 작업에 적합합니다.
faas-cli template store pull go
(4) Custom Dockerfile 템플릿
특정 요구사항에 따라 사용자 정의 Docker 이미지를 사용하는 함수 작성에 유용합니다.
faas-cli template store pull dockerfile
위 템플릿들은 OpenFaaS 템플릿 스토어에서 다운로드할 수 있으며, 프로젝트에 맞는 템플릿을 선택하여 활용할 수 있습니다.
3. 사용자 정의 함수 생성
(1) Python 템플릿 준비
Python 템플릿을 다운로드하여 사용자 정의 함수 작성 환경을 설정합니다.
faas-cli template store pull python3
(2) 함수 생성
새로운 함수를 생성합니다.
faas-cli new extract-body --lang python3
이 명령을 실행하면 extract-body
디렉토리가 생성되며, 여기에 함수 코드 파일과 설정 파일이 포함됩니다.
(3) 함수 코드 작성
extract-body/handler.py
파일을 수정하여 HTML 콘텐츠에서 body 텍스트를 추출하는 코드를 작성합니다.
import requests
from bs4 import BeautifulSoup
def handle(event, context):
try:
url = event.body.strip()
if not url.startswith("http"):
return "Invalid URL. Please include http or https."
response = requests.get(url, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
body_content = soup.body.get_text(separator="\n", strip=True)
return body_content
except requests.exceptions.RequestException as e:
return f"Error fetching URL: {str(e)}"
except Exception as e:
return f"Unexpected error: {str(e)}"
(4) 의존성 추가
BeautifulSoup
라이브러리를 사용하므로 requirements.txt
파일에 아래 내용을 추가합니다.
beautifulsoup4
requests
4. 함수 빌드 및 배포
(1) 함수 빌드
faas-cli build -f extract-body.yml
(2) 함수 배포
faas-cli deploy -f extract-body.yml
(3) 함수 상태 확인
faas-cli list
5. 함수 사용
(1) cURL로 요청 보내기
배포된 함수는 HTTP POST 요청으로 사용할 수 있습니다.
curl -X POST http://<gateway-url>:8080/function/extract-body \
-d "https://example.com"
(2) 결과 확인
HTML <body>
태그의 텍스트 내용이 응답으로 반환됩니다.
6. 추가 기능 구현
(1) HTML 요소 필터링
특정 요소(예: 스크립트, 광고 등)를 제외하려면 BeautifulSoup의 decompose() 메서드를 활용해 불필요한 태그를 제거합니다.
# 광고 제거 예시
for ad in soup.find_all("div", class_="advertisement"):
ad.decompose()
(2) 화면에 표시되는 텍스트만 추출하기
HTML에서 화면에 보이는 텍스트만 추출하려면 불필요한 태그와 숨겨진 요소를 제거해야 합니다. 이를 위해 BeautifulSoup
를 활용한 추가 처리가 필요합니다.
import requests
from bs4 import BeautifulSoup
def handle(event, context):
try:
# URL 가져오기
url = event.body.strip()
if not url.startswith("http"):
return "Invalid URL. Please include http or https."
# HTML 가져오기
response = requests.get(url, timeout=10)
response.raise_for_status()
# BeautifulSoup으로 HTML 파싱
soup = BeautifulSoup(response.text, 'html.parser')
# 불필요한 태그 제거 (스크립트, 스타일 등)
for script_or_style in soup(["script", "style", "meta", "link"]):
script_or_style.decompose()
# 숨겨진 요소 제거
for hidden in soup.find_all(style=lambda value: value and "display:none" in value):
hidden.decompose()
# 화면에 표시되는 텍스트만 가져오기
visible_text = soup.get_text(separator="\n", strip=True)
# 텍스트 정리: 빈 줄 제거
clean_text = "\n".join(line for line in visible_text.splitlines() if line.strip())
return clean_text
except requests.exceptions.RequestException as e:
return f"Error fetching URL: {str(e)}"
except Exception as e:
return f"Unexpected error: {str(e)}"
주요 변경 사항
- 불필요한 태그 제거:
script
,style
,meta
,link
태그를decompose()
메서드로 제거하여 HTML 구조에서 필요 없는 내용을 제외합니다. - 숨겨진 요소 제거:
style
속성에display:none
이 포함된 태그를 제거합니다. 추가로aria-hidden="true"
와 같은 다른 숨김 기준도 적용 가능합니다. - 텍스트 정리:
get_text()
메서드로 HTML의 텍스트를 가져오되, 줄 구분자로\n
을 지정하고 빈 줄은 제거합니다.
위 코드로 다시 배포하고 테스트를 진행합니다.
빌드 및 배포
faas-cli build -f extract-body.yml
faas-cli deploy -f extract-body.yml
테스트
반환 결과는 HTML 태그 없이 웹 페이지에 표시되는 텍스트만 포함합니다.
curl -X POST http://<gateway-url>:8080/function/extract-body \
-d "https://example.com"
(3) 인코딩 문제 해결하기
일부 웹사이트는 euc-kr
과 같은 비표준 인코딩을 사용하여 HTML을 제공합니다. 이를 처리하기 위해 요청 응답의 인코딩을 명시적으로 설정하거나 BeautifulSoup의 from_encoding
옵션을 활용할 수 있습니다.
import requests
from bs4 import BeautifulSoup
def handle(event, context):
try:
url = event.body.strip()
if not url.startswith("http"):
return "Invalid URL. Please include http or https."
response = requests.get(url, timeout=10)
response.raise_for_status()
# 응답 인코딩 설정 (예: euc-kr)
response.encoding = response.apparent_encoding
soup = BeautifulSoup(response.text, 'html.parser', from_encoding=response.encoding)
# 텍스트 추출 처리
body_content = soup.body.get_text(separator="\n", strip=True)
return body_content
except requests.exceptions.RequestException as e:
return f"Error fetching URL: {str(e)}"
except Exception as e:
return f"Unexpected error: {str(e)}"
주요 대응 방안
- apparent_encoding 사용:
response.apparent_encoding
으로 응답의 실제 인코딩을 감지하여 설정합니다. - from_encoding 옵션: BeautifulSoup 초기화 시 인코딩을 명시적으로 지정하여 파싱 문제를 방지합니다.
- 테스트 환경 확장: 다양한 인코딩의 웹사이트에 대한 테스트를 진행하여 예상치 못한 오류를 방지합니다.
(4) URL 검증 및 필터링
정확한 URL 형식을 검증하거나 특정 도메인만 허용하도록 설정할 수 있습니다. 이를 통해 안전성을 높이고 불필요한 요청을 방지할 수 있습니다.
def validate_url(url):
from urllib.parse import urlparse
parsed = urlparse(url)
if not parsed.scheme or not parsed.netloc:
return False
# 허용 도메인 검증 (예: example.com만 허용)
allowed_domains = ["example.com"]
if parsed.netloc not in allowed_domains:
return False
return True
# 사용 예시
url = event.body.strip()
if not validate_url(url):
return "Invalid or unauthorized URL."
(5) OpenAPI 연동
OpenFaaS와 OpenAPI를 연동하여 API 명세를 작성하고, API Gateway로 연결할 수 있습니다.
참고 리소스
- OpenFaaS 공식 문서: https://docs.openfaas.com/
- BeautifulSoup 공식 문서: https://www.crummy.com/software/BeautifulSoup/bs4/doc/
위의 단계를 따라 OpenFaaS에서 URL의 body 콘텐츠를 추출하는 함수를 손쉽게 구현하고 배포할 수 있습니다.
댓글