[파이썬] re 라이브러리 활용한 정규표현식②

5. 또 다른 반복 표현 {n}, {n,m}

: 문자열을 특정할 수 있는 또 다른 반복 구문 표현으로 {n}, {n,m}이 있다. 해당 구문은 앞에 등장한 문자가 반복되는 회수를 n번 혹은 m~n번 사이로 지정할 수 있는 특징이 있다.  

  • {n} : 앞 문자가 n번 반복되는 패턴
  • {m,n} : 앞 문자가 m ~ n 사이의 수만큼 반복되는 패턴

예제 6) {n} 사용된 패턴을 통해 문자열 적용 유무 확인

- {n} 사용 위한 컴파일 함수 사용

- {n} 앞에 놓인 문자 A가 n 숫자에 맞게 등장한 경우

- {n} 앞에 놓인 문자 A가 n 숫자보다 적게 등장한 경우  → n 수를 충족하지 않아 문자열 특정하지 못함

 

예제 7) {m, n} 사용된 패턴을 통해 문자열 적용 유무 확인

- {m,n} 사용 위한 컴파일 함수 사용

- {n} 앞에 놓인 문자 A가 n 숫자에 최소값으로 등장한 경우

- {n} 앞에 놓인 문자 A가 n 숫자에 최대값으로 등장한 경우

 

6. [ ]괄호 : 괄호 안에 들어가는 문자가 들어 있는 패턴

: [ ] 괄호는 특정 위치에 대한 지정 없이 찾고자 하는 문자가 들어가 있는지 여부를 확인하기 위해 사용된다. 별도의 기호 없이 사용할 경우 해당 문자열을 알파벳 혹은 숫자 개별 단위로 찾는 특성이 있다. [ ] 괄호는 기호의 활용을 통해 보다 다양하게 활용 가능한데, 하이픈 (-) 표시를 통해 범위를 표시할 수 있으며, (^) 기호를 통해 반대로 괄호 안에 있는 것들을 제외한 문자열을 탐색할 수도 있다.  

  • [abc]괄호는 a, b, c 중 하나가 들어가 있는 패턴을 의미
  • [c-e]는 c,d,e 중 하나가 들어가 있는 패턴을 의미(0-9, A-Z, 가-힣 등으로 응용 가능)
  • [^a-z]는 소문자가 아닌 문자가 들어가 있는 패턴을 의미

예제 8) [ ] 사용된 패턴을 통해 문자열 적용 유무 확인

- [ ] 기능 사용을 위한 패턴 컴파일 함수 사용

- [ ] 괄호 안에 놓인 문자가 등장한 경우 → 첫 번째 등장값 반환

- [ ] 괄호 안에 놓인 문자가 등장하지 않은 경우  → 문자열 특정하지 못함

예제 9) 하이픈(-) 사용된 패턴을 통해 문자열 적용 유무 확인

- [-] 기능 사용을 위한 컴파일 함수 사용

- [-] 범위 내에 놓인 문자가 등장한 경우 → 첫 번째 등장한 번위값 반환

- [-] 범위 내에 놓인 문자가 등장하지 않은 경우  → 문자열 반환하지 못함

예제 10) (^) 사용된 패턴을 통해 문자열 적용 유무 확인

- (^) 기능 사용을 위한 컴파일 함수 사용

- [-] 범위 내에 놓인 문자가 등장한 경우 → (^) 기능으로 문자열 반환하지 못함

- [-] 범위 내에 놓인 문자 외 다른문자가 등장하지 않은 경우  → (^) 기능으로 문자열 반환

 

7. 정규 표현식 라이브러리 함수 사용법

1) match와 search 함수

  • match : 문자열 처음부터 정규식과 매칭되는 패턴을 찾아서 리턴
  • search : 문자열 전체를 검색해서 정규식과 매칭되는 패턴을 찾아서 리턴

예제 11) 같은 구문에 대한 match와 seach 함수 차이

- match와 search 함수의 차이를 알아보기 위한 컴파일 함수 사용

- 동일 구문에 대한 match와 search 함수 차이 확인  search는 구문의 처음부터 적용되어 대문자 안 됨을 확인

2) findall 함수: 정규표현식과 매칭되는 모든 문자열을 리스트 객체로 리턴

예제 12) findall 함수의 기능 확인

- findall 함수의 기능을 알아보기 위한 컴파일 함수 사용

- 구문에 대한 findall 함수의 기능 확인 → [a-z]+ 의 기준에 맞는 문자열 단위들을 리스트 형태로 반환

3) split 함수 : 찾은 정규 표현식 문자열을 기준으로 기존의 문자열을 분리

- split 함수의 기능을 알아보기 위한 컴파일 함수 사용

- 구문에 대한 split 함수의 기능 확인 → [-]을 기준점으로 나눠진 문자열들을 리스트 형태로 반환

re 라이브러리 활용한 정규표현식①

1. 정규표현식을 사용하는 이유

: '정규 표현식'이란 특정 텍스트 안에서 지정한 문자를 찾아내는 도구를 말한다. 이 기능이 실제 프로그래밍에 많이 사용되는 이유는 새로 수집한 데이터나 기존에 다른 용도로 쓰이던 데이터를 필요한 정보 형태로 가공해내는 데 있어 활용성이 매우 높기 때문이다. 간단한 예로 우리에게 '주민등록번호 : 981029-1234567' 라는 데이터가 있을 때, 우리는 '-' 다음 놓인 숫자를 활용해 그 사람의 성별을 알아낼 수 있다. 여기서 '- 다음에 놓이는 수'의 개념을 식으로 표현하는 것이 정규표현식의 활용을 통해 가능해지는 것이다. 

 

2. 정규표현식의 문자열 지칭 방법

: 정규 표현식은 아래와 같이 일정한 규칙을 가지고 작성됨으로 가지고 있는 데이터 양식에 따라 필요한 패턴을 직접 만들어서 사용할 수 있다. 해당 양식에 따라 작성된 패턴을 re 라이브러리의 complie 함수를 통해 패턴으로 저장하면 문자열 안에 해당 패턴의 존재 유무를 확인하고 추가적인 함수 활용을 통해 원하는 형태로 변형이 가능하다.

정규 표현식 축약 표현 예 시
[0-9] \d 숫자를 찾음
[^0-9] \D 숫자가 아닌 것을 찾음(텍스트, 특수 문자, white space(스페이스, 탭, 엔터 등등)
[\t\n\r\f\v] \s white space(스페이스, 탭, 엔터 등등) 문자인 것을 찾음
[^\t\n\r\f\v] \S white space(스페이스, 탭, 엔터 등등) 문자가 아닌 것을 것을 찾음
[A-Za-z0-9] \w 문자, 숫자를 찾음
[^A-Za-z0-9] \W 문자, 숫자가 아닌 것을 찾음

예제 1) 정규 표현식을 활용해 문자열 내에서 숫자 위치 찾기 

 

3. 점 (dot) 의 활용

: . (dot)은 정규 표현식 상에서 줄바꿈 문자 (\n)을 제외한 모든 문자 (한 개)를 의미한다. 만약 정말 . 을 문자열 내에서 찾고 싶다면 \n 으로 표기하거나 [.]으로 표기하면 된다.

 

예제 2) . (dot)이 사용된 패턴을 통해 문자열 적용 유무 확인 

- . (dot) 기능을 활용해 패턴 저장하기

- 패턴이 발견되는 사례 정리① .(dot)의 수만큼 문자/ 숫자가 차지한 경우

- 패턴이 발견되는 사례 정리② 문자열 사이에 패턴이 위치한 경우

- 패턴이 발견되지 못한 사례① .(dot)의 수보다 많은 변수가 있을 경우

- 패턴이 발견되지 못한 사례② .(dot)의 수보다 적은 변수가 있을 경우

- 패턴이 발견되지 못한 사례③ 대문자 대신 소문자가 적혀 있을 경우

 

4. ?,  *,  +를 사용한 반복되는 패턴 표현

: 문자열 내에서 해당 패턴을 찾기 위해 .(dot)의 경우에는 .(dot)의 개수와 문자열(\n 제외) 개수가 정확히 일치해야 한다는 제한 사항이 있다. 이러한 제한 사항 없이 보다 활용성 높게 문자열을 지정하고자 특정 형태의 문자열을 통째로 찾아내는 ?, *, + 구문이 사용된다. 

  • ?는 앞 문자가 0번 또는 1번 표시되는 패턴 (없어도 되고 한번 있어도 되는 패턴)
  • *은 앞 문자가 0번 또는 그 이상 반복되는 패턴
  • +는 앞 문자가 1번 또는 그 이상 반복되는 패턴 

예제 3) ?이 사용된 패턴을 통해 문자열 적용 유무 확인 

- ? 사용 위한 컴파일 함수 사용

- ? 앞에 놓인 문자 A가 없는 경우 → 문제 없이 B 구문만 특정

- ? 앞에 놓인 문자 A가 여러개 있는 경우 → 앞에 A부분들은 포함되어 있지 않고, 마지막 AB 구문만 특정

예제 4) *이 사용된 패턴을 통해 문자열 적용 유무 확인

- * 사용 위한 컴파일 함수 사용

- * 앞에 놓인 문자 A가 없는 경우 → 문제 없이 B 구문만 특정

- * 앞에 놓인 문자 A가 여러개인 경우 → 여러개의 A가 포함된 구문 전체 특정

예제 5) +이 사용된 패턴을 통해 문자열 적용 유무 확인

- + 사용 위한 컴파일 함수 사용

- + 앞에 놓인 문자 A가 없는 경우 +앞 문자가 한 개 이상 등장하지 않아 문자열 특정하지 못함

- + 앞에 놓인 문자 A가 여러개인 경우 → 여러개의 A가 포함된 구문 전체 특정

openpyxl 라이브러리 사용해 엑셀 파일 추출하기

0. 코드정리 

- 엑셀 파일로 파이썬 데이터 내보내는 코드

# 출력하고자 하는 데이터 리스트로 정리한 후 
# def 함수 인자만 필요에 맞게 변경 시 파일 출력 가능
import openpyxl

def write_excel_template(filename, sheetname, listdata):
    excel_file = openpyxl.Workbook()
    excel_sheet = excel_file.active
    
    if sheetname != '':
        excel_sheet.title = sheetname
    
    for item in listdata:
        excel_sheet.append(item)
    excel_file.save(filename)
    excel_file.close()

- 파이썬으로 엑셀 파일 데이터 입력하는 코드

# 출력하고자 하는 파일명/ 시트명 확인 후
# 출력하고자 하는 데이터의 열 변경 후 사용할 것

import openpyxl

excel_file = openpyxl.load_workbook('파일명.xlsx')

# 별도의 시트 지정이 필요한 상황인지 확인 후 아래 두개 중 선택할 것
excel_sheet = excel_file.active
excel_sheet = excel_file.get_sheet_by_name('시트명')

for row in excel_sheet.rows:
    print(row[0].value, row[1].value, row[2].value)

excel_file.close()

1. 엑셀 파일로 파이썬 데이터 내보내기

: 파이썬을 통해 수집한 데이터를 엑셀 자료로 추출하는 여러 방법 중 가장 대표적인 것이 openpyxl 라이브러리를 활용하는 것이다. openpyxl 라이브러리를 통해 엑셀 파일로 출력하는 단계는 아래와 같이 진행된다. 데이터 입력 단계에서 리스트 형태로 입력해야 한다는 점에만 주의한다면 문제 없이 엑셀 파일로 출력이 가능할 것이다.

  • openpyxl 라이브러리 입력 (오류 시 pip install openpyxl 통해 라이브러리 등록)

  • Workbook() 함수 통해 신규 엑셀 파일 열기

  • 엑셀 파일 내 시트 지정 및 시트 이름 바꾸기

  • 엑셀 시트 내 파이썬의 리스트 데이터 입력하기

  • 엑셀 파일 저장 및 닫기

  • 위의 예시에 따라 출력된 엑셀 파일

 

2. 파이썬으로 엑셀 데이터 가져오기

: 파이썬 to 엑셀 파일로 출력하는 경우와 반대로 엑셀 파일 내 데이터를 파이썬으로 가져오려는 상황에서도 openpyxl 라이브러리를 사용하여 해결 가능하다. 엑셀 자료를 파이썬으로 출력하는 방법은 아래와 같이 이뤄진다.

  • openpyxl 라이브러리 입력 (오류 시 pip install openpyxl 통해 라이브러리 등록)

  • load 함수를 사용해 저장되어 있는 엑셀 파일 열기

  • 데이터 추출이 필요한 시트 지정

  • 시트 내 출력하고자 하는 데이터 설정 (아래의 예시는 열을 기준으로 출력 요청)

  • 엑셀 닫기

리스트를 문자열로 변환하는 방법

1. join 함수을 통한 리스트 to 문자열 변환 

: join 함수를 사용하면 정말 간단한 방식으로 기존의 타입이 리스트 형태였던 데이터를 문자열(str) 형태로 변환할 수 있다. 아래의 예시를 살펴보면 원하는 리스트 내 변인 사이에 삽입할 인자를 먼저 정의한 뒤, 해당 리스트를 쓰면 바로 문자열로 변환되는 것을 확인할 수 있다.

 

 다만 join 함수를 단독으로 사용할 경우 리스트 변인으로 문자열만을 포함하는 경우에만 한정적으로 작업이 진행되는 특성이 있다. 그렇기에 리스트 내 int 등의 다른 타입이 포함되어 있을 경우에 사용이 제한되는 경우가 있음에 유의해야 한다.

join 함수의 기본 사용 형태

2. join  + map 함수을 통한 리스트 to 문자열 변환

 : 위에 정리한 join 함수의 문제점, 문자열 외에 데이터 값이 있을 경우 적용되지 않는 사례를 보완하기 위해 map 함수를 함께 사용할 수 있다. map 함수의 특성과 이를 적용해 str과 int 인자가 혼재되어 있는 리스트를 문자열로 치환한 사례에 대해 정리해보면

 

※ map(함수 , 리스트 혹은 튜플 등) 함수는 이와 같이 2개의 인자를 사용한다.

  1. 함수 - str() 함수, 리스트 내 인자들을 대상으로 문자열 타입으로 변환하는 함수
  2. 리스트 - 위의 함수에 적용되어 리스트 내 모든 인자 타입을 문자열로 변환

str 변환 후 join 사용 형태

 

3. for 반복문을 통한 리스트 to 문자열 변환 

: 두 번째 방법은 for 반복문을 이용해 리스트 정보를 연속적으로 삽입시키는 방식이다. 우선 반복문의 결과로 도출되는 list 내 인자들을 받아줄 str 타입의 변수를 생성한 뒤 (아래 예시의 alist_str) 해당 변수 안으로 리스트 변인들을 차례대로 대입하는 방식이다.

 

 이 경우에도 join 함수와 마찬가지로 리스트 내 인자들을 str 값으로 변환하는 작업이 함께 이루어져야 한다. 다만 반복문 특성 상 인자별로 단일로 수행되기에 인자에 str() 함수를 더하는 것만으로 문제 없이 작업이 수행된다.   

for 반복문 통해 문자열 변환 형태

여러 페이지 동시 크롤링 위한 url 구조 활용

1. url 주소를 통한 웹페이지 구조 파악

: 유의미한 수준의 설득력 있는 인사이트를 도출하기 위해서는 충분한 양의 로우 데이터를 확보하는 것이 중요하다. 하지만 일반적으로 방대한 양의 데이터는 여러 페이지에 걸쳐 나열되어 있는 경우가 많기에 페이지마다 따로 크롤링 작업을 진행할 경우 모을 수 있는 데이터는 극히 제한적이다. 결국 여러 페이지에 걸친 크롤링 작업을 자동화하는 기술이 중요한데 이를 위해 우선적으로 확인해야 하는 것이 url 주소이다. 

 

초기 페이지 유입 시 url (상품리스트 1페이지)

 온라인 쇼핑몰 내 상품리스트를 들어가면 일반적으로 url 주소는 위와 같이 나타난다. 복잡하기만 하고 특별한 구조가 보이지 않아 일반적으로 쓰이는 반복문을 적용하는게 쉽지 않아 보이는데 이때 쇼핑몰 페이지를 앞뒤로 한두번 이동하다보면 숨겨져 있던 웹페이지 url 구조를 확인할 수 있다.

 

페이지 이동 시 나타난 url (상품리스트 2페이지)

 실제로 상품리스트 상의 2번 페이지로 이동하니 위와 같이 url의 숨은 부분이었던 '&page=2' 부분이 나타남을 확인할 수 있었다. 다른 페이지도 추가적으로 확인해보기도 하고 url 주소 내 숫자를 임의적으로 바꿔가면서 'page=N' 부분만 수정한다면 페이지별 반복작업을 자동화 할 수 있는 url 구조라는 사실을 확인할 수 있었다.

 

2. for 반복문을 통한 여러 페이지 동시 크롤링

: url 구조를 통해 확인한 구조를 바탕으로 for 반복문을 사용한다면 여러페이지에 걸친 크롤링 작업을 자동화할 수 있다. url 구조 상에서 변화가 필요한 부분을 정의한 뒤에 해당 부분을 range 함수 등 범위를 지정하는 방법을 통해 원하는 범위 만큼 작업 가능하다.

import requests
from bs4 import BeautifulSoup

url : 'https://www.ssg.com/disp/category.ssg?dispCtgId=6000184784&sort=sale&page='

for i in range(1,10):
    res = requests.get(url+str(i))  #페이지 표시 부분 for 반복문으로 대체
    soup = BeautifulSoup(res.content,'html.parser')
    items = soup.select('a > em.tx_ko')
    
    for item in items:
        print(item.get_text())

 

3. 페이지 오류 방지하기 위한 대처 방안

: 여러 페이지를 동시에 작업하다보면 일부 페이지의 수신 오류에 따라 진행중인 크롤링 작업이 전체 취소되는 경우가 자주 발생한다. 이러한 상황을 사전에 방지하기 위한 한가지 방법으로 응답 코드(response code)를 통해 서버 정상 수신 여부를 확인하는 status_code를 사용할 수 있다.

 

 웹페이지 상의 데이터를 요청할 경우 서버로부터 응답코드(response code)를 받게 되는데 해당 코드는 HTTP 규격에 따라 200인 경우 정상을 나타내며 그렇지 않은 경우 수신에 문제가 있다는 의미이다. 따라서 status_code 함수를 통해 특정 페이지 요청 후의 응답 코드가 200인지 그렇지 않은지에 대한 조건문을 더함으로써 중도 오류 없이 데이터 추출이 가능하다.  

url = 'https://www.ssg.com/disp/category.ssg?dispCtgId=6000184784&sort=sale&page='

for i in range(1,10):    
    res = requests.get(url+str(i))
    
    if res.status_code != 200:
        print('페이지 없음')      # 페이지 수신을 못한 경우 오류 발생 방지
    else:
        soup = BeautifulSoup(res.content,'html.parser')
        items = soup.select('a > em.tx_ko')
    
        for item in items:
            print(item.get_text())

select 함수를 사용한 추출 데이터 지정

0. 코드 정리

# 정보 추출할 사이트 주소와 데이터 특정할 인자 수정해 사용할 것 

import requests
from bs4 import BeautifulSoup
res = requests.get('정보 추출할 사이트 주소')
soup = BeautifulSoup(res.content,'html.parser')

# 데이터 특정 위한 인자 예시, 하단 설명 참고 
section = soup.select('p.item_title > a > span.prName_PrName')

for item in section:
    print(item.get_text())    #select() 함수는 리스트값을 결과로 입력하여 for 반복문을 통해 추출

1. 데이터 지정 간 select 함수를 사용하는 이유

: 정제되지 않은 웹사이트를 대상으로 상황에 맞는 크롤링 구문을 작성하다보니 크롤링 문법이 다른 문법에 비해 직관적이지 않게 보이는 특성이 있다. 그에 따라 보다 다양한 방법을 사전에 알고 있어야 다른 사람의 코드를 참조할 수 있는데 find()를 이용한 함수만큼 혹은 그 이상 사용되는 것이 select() 함수이다. find() 함수가 상대적으로 이해하기 쉬운 특징이 있는 반면 select() 함수는 보다 더 구체적인 구문을 특정하는데 용이하다는 특징이 있어 실제적으로 더 많이 이용되고 있다.

 

2. select 함수의 기본 사용 형태와 인자 작성법

1) 기본적인 사용 형태

: find() 함수와 기본적으로 사용 형태가 비슷해 보이지만 select() 함수의 경우 결과값을 받는 형태와 안에 들어가는 인자가 달라진다는 점에 유의해 사용해야 한다. find() 함수의 경우 결과값을 객체(object)로 받아 여러개의 값을 가져올 경우 find_all() 함수로 대체 사용해야 했다. 하지만 select() 함수의 경우 결과값을 기본적으로 리스트 형태로 받기 때문에 오히려 하나의 값에 대한 객체(object)로 받고자 할 때 select_one()이라는 함수로 대체 사용해야 하는 특징이 있다. 

# find()와 select() 함수는 호환이 가능한데, 정보 타입에 따라 select() 함수는 find_all() 함수와 select_one()함수는 find()함수와 교차사용이 가능하다. 

import requests
from bs4 import BeautifulSoup
res = requests.get('https://www.okmall.com/products/list?cate=20008603&gi_num=2')
soup = BeautifulSoup(res.content,'html.parser')

section = soup.select('p.item_title > a > span.prName_PrName') # find() 대신 select() 사용

for item in section:
    print(item.get_text())    #select() 함수는 리스트값을 결과로 입력하여 for 반복문을 통해 추출

 

2) select() 함수 인자 작성법

: select() 함수 내 인자를 작성할 때에는 CSS 언어의 style 태그가 HTML 태그를 취할 때의 문법 구조와 동일하게 작성된다. tag 값은 별도의 표시 없이 값만 가져오며 class 값은 앞에 "."과 함께 그리고 id 값은 앞에 "#"과 함께 쓰인다. 동일한 태그 내의 정보를 중복으로 사용 가능하며 이런 구문을 작성할 때에는 띄어쓰기 없이 붙여 사용해야 한다.

#tag 값 : tag 값 입력
#class 값 : .class 값 입력
#id 값 : #id 값 입력

import requests
from bs4 import BeautifulSoup
res = requests.get('https://www.okmall.com/products/list?cate=20008603&gi_num=2')
soup = BeautifulSoup(res.content,'html.parser')

section = soup.select('태그값.class값#id값') #단일 태그 안에 있는 정보를 기입할 떄에는 붙여서 사용 

for item in section:
    print(item.get_text())

또한 selcet()함수는 보다 구체적으로 특정 데이터를 특정하기 위해 상위 태그 정보를 함께 기입하는 방법도 존재한다. 기본적으로 띄어쓰기를 통해 상위태그와 하위태그 정보를 연속적으로 나열 가능하며 바로 앞에 있는 상위 태그임을 나태내고 싶다면 띄어쓰기 대신 ">" 기호를 추가할 수 있다. 다만 ">" 기호를 사용할 경우 바로 앞에 위치한 상위태그가 정보가 아닐 시에는 정보 추출이 제한된다는 점에 유의해야 한다.

#상위 태그 포함 예시
section = soup.select('태그명.class명 태그명#id명 > 태그명.class명' )

 

3) select() 함수 인자 추출 방법

: 웹페이지 내 '검사' 기능을 사용한다면 크롤링을 통해 추출하고자 하는 정보의 CSS selector 정보를 즉시적으로 복사할 수 있다. 웹페이지 검사 기능 내 원하는 정보가 담긴 구문을 우클릭한 후 'Copy' 안에 'Copy Selector'를 클릭한 뒤 해당 정보를 select() 함수 인자로 사용 가능한 정보를 추출 가능하다.

 

# 검사 기능 내 CSS selector 정보 카피하는 방법 이미지 

크롤링 기본 방법 및 필요 지식 정리

1. 크롤링 위한 기본 코드 정리

: 웹페이지 내 필요 정보를 크롤링하기 위해  BeautifulSoup, requests 두 개의 라이브러리를 사용하는 방법이 대표적이다. 해당 방법에 이용되는 코드의 의미를 알아야 이에 기반해 응용할 수 있는 폭이 넓어지니 우선적으로 코드에 대해 의미를 이해한 뒤 전체 코드를 사용해 작업에 사용하는 것이 이상적일 것이다.

#라이브러리 내 함수를 사용하기 위해선 사용자 컴퓨터 내에 라이브러리가 이미 설치가 되어 있어야 한다. (No module 에러 주의)

#Mac 환경 터미널, 윈도우 환경 cmd 내 'pip install 라이브러리명' 명령을 내림으로써 라이브러리 설치 가능하다.

 

1) 크롤링 위한 기본 코드

import requests
from bs4 import BeautifulSoup

변수1 = requests.get('사이트 주소')
변수2 = BeautifulSoup(변수1.content,'html.parser')

data = 변수2.find('h3')
print(data.get_text())

 

2) 크롤링 기본 코드 해석

: 위의 기본 코드에 대해 줄마다의 의미를 정리하면 아래와 같다. 결국 크롤링을 잘하기 위해선 4단계의 방법을 아는 것이 중요한데 페이지 검사 기능을 사용하는 것도 좋지만, 기본적인 HTML과 CSS에 대한 지식이 더해졌을 때 보다 응용할 수 있는 범위가 넓어질 것이다.

# 1단계 : 크롤링 관련 라이브러리 임포트
import requests  # 웹페이지 가져오기 라이브러리
from bs4 import BeautifulSoup # 웹페이지 분석(크롤링) 라이브러리

# 2단계 : 원하는 웹페이지 가져오기
href = requests.get('https://www.nocutnews.co.kr/news/5862355')

# 3단계 : 파싱 - 문자열의 의미를 분서해주는 것 (html 구조로 정리)
soup = BeautifulSoup(href.content,'html.parser')

# 4단계 : 필요한 데이터 찾아 변수에 담기
data = soup.find('h3')

# 5단계 : 결과값만 추출하기
print(data.get_text())

 

2. 크롤링 작업 간 필요한 HTML/ CSS 지식 정리

: 크롤링 기본 5단계 중 4단계 '필요한 데이터 찾아 변수에 담기'를 잘 수행하기 위해선 기본적인 HTML과 CSS 언어에 대한 지식이 필요하다. 태그만으로는 정보를 특정하는데 어려운 부분이 있어 class 값 혹은 속성 값 혹은 id 값을 상황에 맞게 적절히 사용해야 하며 이를 위해 HTML/ CSS의 기본 구성에 대해 알 필요가 있다.

 

1) HTML 코드의 기본 구성과 이에 기반한 필요 데이터 특정

: HTML 코드는 'tag' 를 기본 구성으로 'class 값', 'id 값', '속성 값'으로 구별된다. 필요한 정보 이상의 방대한 자료를 크롤링하거나 원하는 정보를 다 담지 못하는 경우를 방지하기 위해서는 크롤링하고자 하는 대상의 코드 구성을 확인하고 원하는 정보만을 정확히 특정할 수 있어야 한다. 

# HTML 코드 예  
<img class = "클래스명" id = "아이디명" src = "저장된 이미지 주소" width = "50px">

# class 값은 일반적으로 동일한 구조 안에서 내용만 달라지는 경우에 이를 군집하기 위해 사용되는 특징을 지님 

→ 웹 페이지 내 나열되어 있는 정보를 한꺼번에 크롤링하는 목적으로 사용하기에 적합하다.

# id 값은 주로 태그 간의 구분을 위해 사용됨으로 다른 태그와 중복 없이 단일로 사용되는 특징을 지님

→ 특정 태그 안에 정보를 단일로 가져오는 목적으로 사용하기에 적합하다.

 

2) HTML 구조 내 원하는 데이터를 변수에 담는 방법 

: tag/ class 값/ id 값/ 속성 값 네 가지 정보에 대해 원하는 정보를 특정하였을 때 각 경우에 따라 데이터 추출하는 방법 정리

# 1번째 방법 : HTML 태그를 통한 정보 특정
data = soup.find('태그')

# 2번째 방법 : HTML 태그와 class 값을 통한 정보 특정
data = soup.find('p', class_ = 'class 값')
data = soup.find('p', 'cssstyle')

# 3번째 방법 : HTML 태그와 속성 값을 통한 정보 특정 
data = soup.find('p', attrs = {'속성 이름'} = '속성 값')

# 4번째 방법 : id 값을 통한 정보 특정
data = soup.find(id = 'id값')

라이브러리의 개념과 사용 방법

1. 라이브러리의 개념

: 라이브러리는 미리 만들어놓은 함수들의 집합으로 개발 간 필요한 라이브러리를 찾아 사용한다면 개발에 필요한 시간과 노력을 획기적으로 절약할 수 있다. 라이브러리를 사용하기 위해선 원하는 기능이 갖고 있는 라이브러리를 찾고, 해당 라이브러리를 개발 환경 내에 설치한 뒤에 사용법에 맞춰 함수 기능을 이용할 수 있다.

#라이브러리 내 함수를 사용하기 위해선 사용자 컴퓨터 내에 라이브러리가 이미 설치가 되어 있어야 한다. (No module 에러 주의)

#Mac 환경 터미널, 윈도우 환경 cmd 내 'pip install 라이브러리명' 명령을 내림으로써 라이브러리 설치 가능

 

# 라이브러리 예시

  • NumPy: 파이썬을 이용해 다양한 수학 계산을 할 수 있도록 해준다.
  • Pandas: 데이터 분석 라이브러리.
  • matplotlib: 데이터 시각화 라이브러리.
  • scipy: 과학 계산에 많이 쓰이는 계산기법 및 알고리즘 탑재.
  • PyTorch: 딥러닝 라이브러리.

 

2. 라이브러리 사용 방법

: 라이브러리를 등록하고 사용함에 있어 등록하는 방법에 따라 호출하는 방법이 달라짐을 인지해야 한다.

 

1) 라이브러리 함수 전체 등록 및 사용 방법 1 

# 라이브러리 내 전체 함수 등록 방법 1
import 라이브러리명

# 라이브러리 내 함수 적용 및 출력
변수 = 라이브러리명.함수명()
print(변수)

2) 라이브러리 함수 전체 등록 및 사용 방법 2

# 라이브러리 내 전체 함수 등록 방법 2
from 라이브러리명 import *

# 라이브러리 내 함수 적용 및 출력
변수 = 함수명()
print(변수)

3) 라이브러리 함수 부분 등록 및 사용 방법

 

# 라이브러리 내 부분 함수 등록
from 라이브러리명 import 함수명1, 함수명2

# 부분적으로 입력한 함수 출력
num = 함수명1()
print(num)

 

 

3. 라이브러리 관련 세부 기능에 대해

1) as : 라이브러리명 혹은 함수명을 원하는 형태로 단축해줄 수 있는 기능

# as를 사용하여 라이브러리명 단축
import 라이브러리명 as d

변수 = d.함수명()
print(변수)

# as를 사용하여 함수명 단축
from 라이브러리명 import 함수명 as f

변수 = f()
print(변수)

객체와 클래스

1. 객체 지향 프로그래밍 (Object Oriented Progarmming)

:  객체(object) 단위로 데이터와 기능(함수)을 하나로 묶어서 쓰는 언어 

#붕어빵 찍어내는 틀을 클래스, 그 안에서 생성되는 붕어빵 (단팥빵 붕어빵, 슈크림 붕어빵 등)을 객체라 생각하고 아래 설명 및 코드 확인

 

 1) 해당 사물을 나타낼 수 있는 설계도를 만들어 둔 뒤 (Class)

 2) 해당 사물의 설계도를 기반으로 사물 1 객체를 만든다. (Object)

 3) 사물1 객체의 기능을 호출한다.

  - attribute : 사물1 객체의 변수

  - method : 사물1 객체의 함수

 

cf) 절차 지향 프로그래밍 : step by step으로 컴퓨터에 한줄씩 명령하는 방식 (ex. 파스칼, 포트란, C언어)

2. 객체 (Object) 와 클래스(Class) 정의하는 방법

1) 클래스 선언 및 함수 정의 방법

# class 선언 시 첫글자는 보통 대문자로 입력
# class에 있는 attribute에는 def 밑에 self가 들어가야함

class square():
    width = 0
    height = 0
    color = ''
    name = ''
    
    def square_area(self):
        return self.width * self.height

2) 클래스를 기반으로 객체 생성

#객체(object) 생성
square1 = square()
square2 = square()

#객체별 attribute 값 입력
square1.width = 10
square1.height = 10
square1.color = 'yellow'
square1.name = 'yellow square'

square2.width = 20
square2.height = 20
square2.color = 'blue'
square2.name = 'blue square'

3) 함수 값 출력

print(square1.square_area()) #square1에 해당하는 함수값 출력
print(square2.square_area()) #square2에 해당하는 함수값 출력

 

이중 반복문을 활용한 구구단 풀이

1. 구구단 계산식 도출

for i in range (2,10):      #i의 값이 2~9 값으로 고정되어 있는 동안
    for j in range(2,10):    # j의 값을 2~9까지 우선적으로 반복하는 구문
        print(i,"*",j,"=",i*j)
    print('\n')           #구구단별 행 구분

2. 결과 값이 짝수만 도출 (조건문 추가된 구구단 계산식)

for i in range (2,10):
    for j in range(2,10):
        if (i*j)%2 == 0:   #2로 나눴을 때 몫이 0인 경우일때만 
            print(i,"*",j,"=",i*j)     # 해당식 출력 요청
    print('\n')

+ Recent posts