이번에는 제가 원하는 정적으로 동작하는 웹 사이트에서 제품명, 제품유형, 제조사, 인증일, 인증만료일 등 데이터를 추출하는 프로그램을 파이썬으로 구현해보았습니다.
항상 크롤링에서 중요한 것은, 파싱하고자 하는 웹 사이트의 HTML에서 원하는 경로를 바로 파악하는 능력이 필요하다고 생각합니다.
(내가 원하는 데이터가 어떤 div 태그영역에 있는지 확인하고, div 태그 내에서 class 값 또는 id 값 등을 이용해 해당 데이터를 추출할 수 있는지가 필요)
아래는 제가 원하는 사이트에서 html 내 태그값을 이용하여 제품명, 분류, 제조사, 인증일, 인증만료일, 상태값을 추출하는 코드입니다.
import requests, openpyxl
from bs4 import BeautifulSoup
wb = openpyxl.Workbook()
sheet = wb.active
sheet.append(["제품명", "분류", "제조사", "인증일", "인증만료일", "상태값"])
#크롤링할 사이트 직접입력하였으며, URL 변수로 별도 선언 후 input() 을 통해 크롤링할 URL을 입력받도록 만들어도 됨.
for i in range(1, 10+1, 1):
raw = requests.get(
"https://www.bsi.bund.de/SiteGlobals/Forms/IT-Sicherheitskennzeichen/EN/IT-Sicherheitskennzeichen_Formular.html?gtp=980004_list%253D{}".format(
(i)))
html = BeautifulSoup(raw.text, 'html.parser')
#크롤링 할 영역을 container로 저장
container = html.select(".c-search-results > ul > li")
for c in container:
#제품명 추출
product_name = c.select_one(".c-search-result-teaser__headline").text.strip()
#본문(카테고리, 제조사, 인증일, 인증만료일)의 데이터를 추출하여 line별로 list에 저장
product_data = c.select_one(".c-search-result-teaser__content").text.strip()
product_data_list = product_data.splitlines()
#리스트로부터 제품의 카테고리, 제조사, 인증일, 인증만료일 데이터를 추출
category = product_data_list[0].replace("Category: ", "")
manufacturer = product_data_list[1].replace("Manufacturer: ", "")
Date_of_issue = product_data_list[2].replace("Date of issue: ", "")
end_of_term = product_data_list[3].replace("End of term: ", "")
#제품의 상태값은 해당 제품들의 링크로 들어가서 추출해야하므로, 링크값(a태그) 추출 후, 한번 더 BeautifulSoup를 이용해 Status 값을 추출
product_status_link = c.find('a')['href']
raw_status = requests.get('https://www.bsi.bund.de/' + product_status_link)
html_status = BeautifulSoup(raw_status.text, 'html.parser')
product_status = html_status.select_one('.c-product-stage__security-status').text.strip()
#엑셀 시트에 저장
sheet.append([product_name, category, manufacturer, Date_of_issue, end_of_term, product_status])
wb.save("C:/Users/user/Documents/bsi_product_search.xlsx")
결과
위 코드에서 포인트는 A웹사이트에서, A->A' 사이트(A'는 각 제품의 상세페이지)로 한번 더 들어가서 제품의 현재 상태값(status)을 추출해주는 부분입니다.
각 제품들의 링크로 들어가서 한번 더 beautifulsoup를 이용해 파싱하고, 상태값을 불러오는 부분에서 상당한 딜레이가 발생하는 것을 확인하였습니다.
최근 해외 사이트들의 동향을 조사하고 본문 내용을 정리하는데 번역을 한번 돌리고 파일화 하는 작업들이 많다보니 이를 파이썬으로 만들면 어떨까해서 아래처럼 만들어 보았습니다.
작업 순서는 아래와 같습니다.
- 1) 원하는 사이트 정적 웹 크롤링(BeautifulSoup)
- 2) Googletranslate 를 활용한 번역
- 3) 번역한 내용을 메모장 파일로 저장
(코드)
import requests, googletrans, time
from bs4 import BeautifulSoup
maxsize = 4500
sleep_time = 2
translator = googletrans.Translator()
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
url = input("번역할 웹 페이지의 URL을 입력하세요: ")
data = requests.get(url, headers=headers)
soup = BeautifulSoup(data.text, 'html.parser')
# 글 제목 추출
title = soup.select('.metadata-content-area')
for index, element in enumerate(title, 1):
f = open('C:/Users/USER/PycharmProjects/global_iot_security/test.txt', 'w', encoding='UTF-8')
trans_title = translator.translate(element.text.strip(), src = 'en', dest='ko')
f.write("{} 번째 게시글의 제목: {}".format(index, trans_title.text))
f.close()
# 세부내용 추출
full_contents = soup.select('.doc-content-area')
for i in full_contents:
txt_contents = i.get_text()
f = open("C:/Users/USER/PycharmProjects/global_iot_security/test.txt", "a", encoding='UTF-8')
#txt_contents가 maxsize 보다 클 때(5000자 이상이면 오류 발생, 4500자씩 분해하여 번역)
if len(txt_contents) > maxsize:
results_list = []
concatenated_result = ""
original_contents = [txt_contents[i:i + maxsize] for i in range(0, len(txt_contents), maxsize)]
for i in original_contents:
r = translator.translate(i.strip(), dest='ko', src='en')
time.sleep(sleep_time)
results_list.append(r.text)
f.write(r.text.strip())
for i in results_list:
concatenated_result += i
# 전체 내용이 4500자 이하라면, 그대로 본문 전체를 번역하여 파일로 씀
else:
res = translator.translate(txt_contents.strip(), dest='ko', src='en')
time.sleep(sleep_time)
f.write(res.text.strip())
f.close()
* 단 주의할 점은, 코드에서 번역시에 5천자가 넘게되면 번역 오류가 발생하게 됩니다.
따라서 저는 우선 전체 크롤링 할 내용이 4500자를 기준으로 넘는지 안넘는지를 비교하여 경우에 따른 케이스로 만들어보았습니다.
최근에 파이썬으로 프로그램을 만들어보고 있는데, pycharm으로 개발하면서 실행파일로 누구나 사용할 수 있도록 하기 위해 배포하려고 해서 관련 포스팅을 남깁니다.
가장 일반적인 실행파일 생성 방법은 PyInstaller 또는 **cx_Freeze**와 같은 패키지를 사용하는 것입니다. 여기서는 가장 많이 사용되는 **PyInstaller**를 활용하여 파이썬 스크립트를 실행 파일로 만드는 방법을 다루겠습니다.
1. PyInstaller 설치
PyInstaller는 파이썬 스크립트를 단일 실행 파일로 변환해주는 도구입니다. 터미널이나 명령 프롬프트에서 다음 명령어로 설치할 수 있습니다.
(windows : cmd 창)
> pip install pyinstaller
* 혹시라도 pip가 설치되어있지 않다고 할 경우에는, python을 제어판에서 삭제했다가 다시 설치하고, 설치할 때 환경변수 등 관련 체크박스가 해제되어있는 부분을 확인하고 체크해주신 후에 설치하면 pip가 자동으로 설치되게 됩니다. 이후에는 pip를 이용한 install 등 가능하게 됩니다.
2. PyInstaller 사용 방법
설치 후, 파이썬 스크립트를 실행 파일로 변환하려면 터미널 또는 명령 프롬프트에서 다음 명령을 입력합니다:
> pyinstaller --onefile 'test.py'
여기서 'test.py'는 실행 파일로 만들고자 하는 본인의 파이썬 파일 이름입니다.
주요 옵션:
--onefile: 하나의 실행 파일로 만듭니다. 기본적으로 PyInstaller는 여러 파일을 생성하는데, 이 옵션을 사용하면 단일 파일로 묶어줍니다.
--noconsole: 프로그램을 콘솔 창 없이 GUI 형태로 실행하고 싶을 때 사용합니다. (GUI 프로그램인 경우에만 유용)
3. 실행 파일 생성 과정
PyInstaller가 실행되면, 다음과 같은 작업을 수행합니다:
dist/ 폴더에 실행 파일이 생성됩니다.
build/ 폴더에 빌드와 관련된 파일이 생성됩니다.
.spec 파일이 생성되며, 이는 빌드 구성을 저장하는 파일입니다.
4. 실행 파일 배포
dist/ 폴더에 생성된 .exe 파일을 다른 사용자에게 배포할 수 있습니다. 배포할 때는 해당 파일만 전달하면 됩니다.
5. 참고 사항
윈도우에서 만든 실행 파일은 윈도우에서만 실행 가능하고, macOS 또는 리눅스에서 만들면 그 운영체제에서만 실행 가능합니다. 각 운영체제에서 해당 OS에 맞게 빌드해야 합니다.
실행 파일 크기가 커질 수 있으므로 불필요한 패키지는 제외하는 것이 좋습니다. 이를 위해 .spec 파일을 편집할 수 있습니다.
6. 실행 파일로 만들 때 발생할 수 있는 문제 해결
외부 모듈이 포함되지 않는 문제: 일부 외부 모듈이 자동으로 포함되지 않을 수 있습니다. 이 경우, hidden-import 옵션을 사용하여 추가합니다.
드론의 구조는 드론과 지상의 원격조정자가 각종 데이터를 주고받는 ‘통신부’, 드론의 비행을 조정하는 ‘제어부’, 드론을 날아가게 구동시키는 ‘구동부’, 그리고 카메라 등 각종 탑재 장비들로 구성된 ‘페이로드’의 네 부분으로 나뉜다고 볼 수 있습니다.
※ LTE, WIFI 등 드론 통신방식에 따라 통신부(송신기)에서 제어부(비행제어기)로 위치데이터 등이 이동되고, 제어부의 센서융합기를 통해 자이로센서, 지자기 센서 등 센서값에 대한 측정치를 갖고 있습니다. 이를 비행제어기를 통해 실제 구동부(모터, 프로펠러 등)으로 핀을 통해 데이터를 전달합니다.
드론은 지상에서 드론으로 원격조정(RC) 비행명령어 및 카메라 조작 등 페이로드 제어 신호를 전송하기 위한 상향링크(지상 → 드론)가 필요하고,
비디오, 사진 및 드론의 위치, 비행속도, 배터리 잔량 등의 비행정보를 지상으로 전송하기 위한 하향링크(드론 → 지상)가 필요합니다.
※ GPS 신호는 1.2GHz(혹은 1.5GHz) 주파수 대역으로 수신
[요약]
- 상향링크 : 지상에서 드론으로 페이로드 제어신호를 전송
- 하향링크 : 페이로드, 제어부 등에서 발생한 비행정보를 지상으로 전송
1) 900MHz 및 1.3GHz 주파수 대역
: 900MHz 주파수 대역은 비디오 및 텔레메트리 전송을 위한 하향링크로 사용
- 900MHz 대역은 최근 규격이 확정된 IoT(internet of things)용 WiFi 11ah 무선랜과도 주파수대역이 겹친다. 1.3GHz 주파수 대역 역시 비디오 전송을 위한 하향링크로 사용되는데, 2005년 이후에 쏘아 올린 GPS 위성의 1.2GHz L2 주파수 대역과 가까워서 드론에 탑재된 GPS 수신기에 간섭을 줄 수 있습니다.
2) 2.4GHz 및 5.8GHz 주파수 대역
: 2.4GHz 주파수 대역은 거의 모든 드론이 원격조정 및 페이로드 제어로 사용하는 상향링크입니다.
그러나 2.4GHz는 WiFi, 블루투스, 지그비 등과 주파수대역이 겹치므로 사람이 많이 모이는 공원 등의 지역에서는 드론 비행에 주의해야 합니다. 일부 드론들은 2.4GHz 대역을 비디오 전송 하향링크로 사용합니다. 이 경우, 원격조정 상향링크는 5.8GHz 주파수 대역을 이용합니다. 5.8GHz 주파수 대역은 최근 출시된 드론들이 비디오 및 텔레메트리 전송 하향링크로 사용하는 주파수 대역입니다.
3) WiFi 및 4G/3G
: 드론에 WiFi 수신기를 설치해 스마트폰 WiFi로 직접 드론을 원격조정할 수 있습니다. 드론에 LTE 혹은 WCDMA 송수신기를 설치해 이동통신 네트워크를 통해 스마트폰으로 드론을 원격조정하거나 드론의 비디오 데이터를 지상으로 전송하기도 합니다.
3. GNSS
1. GPS 및 GNSS(Global Navigation Satellite System : 위성항법시스템)
: GPS는 인공위성으로부터 수신기까지 신호가 도달하는 데 걸린 시간(소요시간)을 기준으로 거리를 측정합니다.
GNSS는 크게 1) 위성, 2) 지상의 제어국, 3) 사용자로 구성되어 있습니다. 지상 제어국의 수신장치에서 고도 약 20,000km 중궤도에 위치해 있는 인공위성에서 신호를 받아 수 m 이내의 위치정보를 알아낼 수 있는 것이 GNSS의 기본 원리입니다.
제5조(초경량비행장치의 기준) 법 제2조제3호에서 “자체중량, 좌석 수 등 국토교통부령으로 정하는 기준에 해당하는 동력비행장치, 행글라이더, 패러글라이더, 기구류 및 무인비행장치 등”이란 다음 각 호의 기준을 충족하는 동력비행장치, 행글라이더, 패러글라이더, 기구류, 무인비행장치, 회전익비행장치, 동력패러글라이더 및 낙하산류 등을 말한다.
5. 무인비행장치: 사람이 탑승하지 아니하는 것으로서 다음 각 목의 비행장치
가. 무인동력비행장치: 연료의 중량을 제외한 자체중량이 150킬로그램 이하인 무인비행기, 무인헬리콥터 또는 무인멀티콥터*
나. 무인비행선: 연료의 중량을 제외한 자체중량이 180킬로그램 이하이고 길이가 20미터 이하인 무인비행선
-> 여기서드론은 일반항공기처럼 날개가 고정되어있는 고정익과, 로터를 갖고있는 회전익 으로 분류되며,멀티콥터(Multi Copter)란 여러 개의 로터(Rotor)를 가진 비행체로, 로터의 수에 따라 아래처럼 불리게 됩니다.